В R, как я могу распространять общие методы из одного пакета в другой?
У меня есть пакет PackageA
с общей функцией:
#' doWork
#'
#' Do some work!
#'
#' @export
setGeneric(
"doWork",
function(x) {
standardGeneric("doWork")
})
setMethod(
"doWork",
signature = c("numeric"),
definition = function(x) {
x == 10 # Some logic...
}
В PackageB
, который зависит от PackageA
, я хотел бы добавить еще несколько методов в doWork
:
#' @import PackageA
setMethod(
"doWork",
signature = c("character"),
definition = function(x) {
length(x) == 1 && x == "10" # Some more logic...
}
Это работает. Однако это означает, что пользователь PackageB
должен также library(PackageA)
.
Это не удается:
library(PackageB)
doWork("10") # Fails!
Это работает:
library(PackageA)
library(PackageB)
doWork("10")
Я хотел бы использовать generic из PackageA
в PackageB
, но не требует загрузки PackageA
для использования только методов в PackageB
.
Как я могу это достичь?
Ответы
Ответ 1
Это фактически документировано, но это не очень понятно; см. раздел 1.5.6
Написание расширений R.
Фокус в том, чтобы импортировать родовое из PackageA
, а затем повторно экспортировать его из PackageB
. Используя аннотации roxygen
, это выглядит так:
#' @importMethodsFrom PackageA doWork
#' @export
setMethod(
"doWork",
signature = c("character"),
definition = function(x) {
length(x) == 1 && x == "10" # Some more logic...
})
Когда вы вызываете devtools::document()
, это произойдет, если вы не загрузили первый раз PackageA
(вызов library(PackageA)
).
Однако, после построения, PackageA
не требуется:
> library(PackageB)
> showMethods("doWork")
Function: doWork (package PackageA)
x="character"
x="numeric"
Для справки, автоматически сгенерированный файл NAMESPACE
выглядит следующим образом:
exportMethods(doWork)
importMethodsFrom(PackageA, doWork)
Этот метод не дает никаких предупреждений о конфликтах именования и т.д., поэтому он кажется "кошерным".
Ответ 2
Кажется, это работает для меня, но я не вижу, чтобы это было документировано, поэтому я не обязательно предполагал, что это кошерный. pckgA
:
#' @export
setGeneric("doWork", function(x) standardGeneric("doWork"))
setMethod("doWork", signature = "numeric", function(x) x == 11)
и pckgB
:
#' @export
#' @import pckgA
setGeneric("doWork", getGeneric("doWork", package="pckgA"))
setMethod("doWork", "character", function(x) identical(x, "10"))
Основной трюк состоял в том, чтобы импортировать и реэкспортировать doWork
из pckgA
в pckgB
. Затем, начиная с чистой сессии R:
library(pckgB)
doWork("10")
# [1] TRUE
doWork("11")
# [1] FALSE
doWork(11)
# [1] TRUE
library(pckgA)
doWork(11)
# [1] TRUE
doWork("10")
# [1] TRUE
Вам может потребоваться полностью очистить рабочую область (включая скрытые объекты), чтобы избавиться от каких-либо определений предшествующего метода, чтобы это действительно эффективно срабатывало.