Программно переключить пакет в `::` вызов в R - PullRequest
0 голосов
/ 30 декабря 2018

При вызове функции bar::foo() я хотел бы иметь возможность программно переключать пакет bar, чтобы тот же синтаксис вызывал hello::foo().

Пример :

  • Допустим, у меня есть три пакета, parentPkg, childPkg1 и childPkg2.
  • InparentPkg У меня есть вызов функции childPkg1::foo()
  • foo() также является функцией в childPkg2
  • Я хотел бы иметь возможность, в parentPkg дляиспользуйте оператор :: для вызова foo(), но для программного переключения имени пакета.Что-то вроде:

    dummy_pkg_name = ifelse(scenario=="child1", "childPkg1", "childPkg2")
    dummy_pkg_name::foo()
    

Возможно ли это?Как мне этого добиться?

Некоторый контекст

parentPkg - это функция, которая взаимодействует с веб-приложением, принимает некоторые запросы и данные и возвращает результаты из различных статистических данных.модели в зависимости от сценариев.
Каждый сценарий довольно сложен, и не все можно обобщить в parentPkg.По этой причине childPkg1 и childPkg2 (на самом деле их также 3 и 4) являются своего рода подпакетами, которые занимаются очисткой данных и различными альтернативами для каждого сценария, но возвращают один и тот же класс значения.
Идея состоит в том, что parentPkg переключит пакет на соответствующий дочерний элемент в зависимости от сценария и вызовет все необходимые функции без необходимости писать одинаковую последовательность для каждого дочернего элемента, но только с немного другим вызовом ::.

Ответы [ 3 ]

0 голосов
/ 30 декабря 2018

Вы также можете создать call(), который затем можно будет оценить.

call("::", quote(bar), quote(foo()))
# bar::foo()

Использовать:

c <- call("::", quote(stats), quote(t.test))
eval(c)
# function (x, ...) 
# UseMethod("t.test")
# <bytecode: 0x4340988>
# <environment: namespace:stats>

Заключить в функцию, используя setdiff в качестве нашегофункция по умолчанию:

f <- function(pkg, fn = setdiff) {
    pkg <- substitute(pkg)
    fn <- substitute(fn)
    eval(call("::", pkg, fn))
}

f(base)
# function (x, y) 
# {
#     x <- as.vector(x)
#     y <- as.vector(y)
#     unique(if (length(x) || length(y)) 
#         x[match(x, y, 0L) == 0L]
#     else x)
# }
# <bytecode: 0x30f1ea8>
# <environment: namespace:base>

f(dplyr)
# function (x, y, ...) 
# UseMethod("setdiff")
# <environment: namespace:dplyr>
0 голосов
/ 30 декабря 2018

Чтобы придерживаться KISS , просто переназначьте новые именованные функции в глобальной среде.Обязательно не указывайте (), так как вы не запрашиваете запуск функции.

parent_foo <- parentPkg::foo
child1_foo <- childPkg1::foo
child2_foo <- childPkg2::foo
child3_foo <- childPkg3::foo

Затем условно примените их по мере необходимости:

if (scenario=="child1") {
  obj <- child1_foo(...)
} 
else if (scenario=="child2") {
  obj <- child2_foo(...)
} 
...
0 голосов
/ 30 декабря 2018

Поскольку :: можно рассматривать как функцию, похоже, что

`::`(dummy_pkg_name, foo)()

- это то, что вам нужно.В качестве альтернативы

getFromNamespace("foo", ns = dummy_pkg_name)()

Например,

`::`(stats, t.test)
# function (x, ...) 
# UseMethod("t.test")
# <bytecode: 0x102fd4b00>
# <environment: namespace:stats>

getFromNamespace("t.test", ns = "stats")
# function (x, ...) 
# UseMethod("t.test")
# <bytecode: 0x102fd4b00>
# <environment: namespace:stats>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...