问题
I have a package PackageA with a generic function:
#' doWork
#'
#' Do some work!
#'
#' @export
setGeneric(
"doWork",
function(x) {
standardGeneric("doWork")
})
setMethod(
"doWork",
signature = c("numeric"),
definition = function(x) {
x == 10 # Some logic...
}
In PackageB, which depends on PackageA, I would like to add more methods to doWork:
#' @import PackageA
setMethod(
"doWork",
signature = c("character"),
definition = function(x) {
length(x) == 1 && x == "10" # Some more logic...
}
This works. However, it means that the user of PackageB must also library(PackageA).
This fails:
library(PackageB)
doWork("10") # Fails!
This works:
library(PackageA)
library(PackageB)
doWork("10")
I would like to use the generic from PackageA in PackageB, but not require PackageA to be loaded to use just the methods in PackageB.
How can I achieve this?
回答1:
This is actually documented, but it's not very clear; see section 1.5.6 of Writing R Extensions.
The trick is to import the generic from PackageA and then re-export it from PackageB. Using roxygen annotations, this looks like:
#' @importMethodsFrom PackageA doWork
#' @export
setMethod(
"doWork",
signature = c("character"),
definition = function(x) {
length(x) == 1 && x == "10" # Some more logic...
})
When you call devtools::document(), this will fail unless you have first loaded PackageA (call library(PackageA)).
However, once built, PackageA is not required:
> library(PackageB)
> showMethods("doWork")
Function: doWork (package PackageA)
x="character"
x="numeric"
For reference, the auto-generated NAMESPACE file looks like:
exportMethods(doWork)
importMethodsFrom(PackageA, doWork)
This method produces no warnings about naming conflicts and so on, so it seems to be "kosher".
回答2:
This seems to work for me, but I don't see it documented so I wouldn't necessarily assume it is kosher. pckgA:
#' @export
setGeneric("doWork", function(x) standardGeneric("doWork"))
setMethod("doWork", signature = "numeric", function(x) x == 11)
and pckgB:
#' @export
#' @import pckgA
setGeneric("doWork", getGeneric("doWork", package="pckgA"))
setMethod("doWork", "character", function(x) identical(x, "10"))
The main trick was to import and re-export doWork from pckgA in pckgB. Then starting with a clean R session:
library(pckgB)
doWork("10")
# [1] TRUE
doWork("11")
# [1] FALSE
doWork(11)
# [1] TRUE
library(pckgA)
doWork(11)
# [1] TRUE
doWork("10")
# [1] TRUE
You may need to completely clear your workspace (including hidden objects) to get rid of any prior method definitions for this to actually take effect properly.
来源:https://stackoverflow.com/questions/31317366/in-r-how-can-i-extend-generic-methods-from-one-package-in-another