Как расширить метод S3 из другого пакета без загрузки пакета
Я разрабатываю пакет, который имеет функцию forecast.myclass
. Я хочу, чтобы эта функция прекрасно работала с пакетом forecast
. То есть при загрузке пакета forecast
код forecast(object)
должен вызывать forecast.myclass
из моего пакета.
Так как мне нужно только общее определение forecast
из пакета forecast
, и я не использую никакой другой функции из пакета forecast
, я не хочу включать его в Depends. Поэтому я определяю общий набор в своем пакете следующим образом:
##'
##' @export
forecast <- function(object,...) UseMethod("forecast")
##' @rdname forecast.midas_r
##' @method forecast midas_r
##' @export
forecast.midas_r <- function(object,newdata=NULL,method=c("static","dynamic"),insample=get_estimation_sample(object),...) {
Теперь все работает так, как ожидалось, когда пакет forecast
не загружен. Но когда я загружаю пакет forecast
, тогда forecast.midas_r
не вызывается при выполнении forecast(object)
, где object
имеет класс midas_r
. Как мне решить эту проблему?
Ответы
Ответ 1
Я не уверен, что это простое решение. Как говорили другие, проще всего использовать Depends
, чтобы обойти это, а не переопределять общий метод.
Вот простой пример, который работает для меня. Это в значительной степени совпадает с вашим решением, но объявление @export
означает, что вам не нужно вручную обновлять файл NAMESPACE
.
##' @name mean
##' @export mean.newClass
##'
##' @method mean newClass
##'
##' @title mean for \code{newClass} object
##' @param x A \code{newClass} object
##' @param ... Additional arguments
##'
mean.newClass <- function(x, ...){
stopifnot(class(x)=="newClass")
return(42)
}
Тогда package.skeleton("newPkg")
. Поместите файл mean.R
с указанным выше содержимым в каталог /R
пакета.
Убедитесь, что вы находитесь в нижеуказанной директории 1, затем
roxygenize("newPkg", roxygen.dir="newPkg", copy.package=F, unlink.target=F)
Теперь
library(devtools)
dev_mode(on=TRUE) ### don't want to have to uninstall the package later
install_local("newPkg")
library(newPkg)
x <- c(1,2)
class(x) <- "newClass"
stopifnot(mean(x)==42)
stopifnot(mean(unclass(x))==1.5)
Я понимаю, что mean
является функцией в base
, но я проверил это для изменения общих функций в другом месте, чтобы дать им новый метод, поэтому он должен распространяться и на ваш более общий случай.
Ответ 2
Проблема заключается в том, что ваше определение forecast
generic маскирует определение из пакета прогноза, а ваш метод связан с вашим общим, а не с общим пакетом прогнозов; это всего лишь сложный экземпляр двух пакетов, определяющих функции с тем же именем. Решение состоит в том, чтобы укусить пулю и зависеть: от прогноза или когда в командной строке и в вашем пакете, и в прогнозе подключены полностью разрешенные функции mypackage::forecast()
или Import: прогноз, но не сделать доступным для конечного пользователя общий прогноз за исключением наличия у них require(forecast)
(это может быть целесообразно, если функциональность forecast
была чем-то периферической для вашего пакета, например, построение графика в 3D, когда построение графика в 2D было достаточным).
Для того, что стоит, метод S4 в PkgB, определенный и экспортированный на импортированный S4-общий код из PkgA, неявно предоставляет пользователю S4 общий характер, поэтому общий доступ доступен, даже если Imports: PkgA указан в файле DESCRIPTION PkgB.
Ответ 3
Одним из возможных решений является принудительный экспорт прогноза .midas_r. Это означает, что вручную обновляется NAMESPACE
с помощью export(forecast.midas_r)
каждый раз после check("yourpackagename")
.
Это означает, что для прогноза пакета отображается forecast.midas_r
. Если forecast.midas_r
не экспортируется и существует только в пространстве имен пакета, то при загрузке запроса пакета общий forecast
заменяется идентичной функцией из прогноза пакета. Поэтому, когда forecast
вызывается на неизвестном объекте, R ищет соответствующие методы в прогнозе пакетов и в общем рабочем пространстве. Поскольку forecast.midas_r
является частным методом, R не находит его и создает ошибку.
Это не идеальное решение, так как вам нужно вручную обновить NAMESPACE
, но это решение все же.