Как расширить метод 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, но это решение все же.