2015-07-09 7 views
14

Ho un pacchetto di PackageA con una funzione generica:In R, come posso estendere i metodi generici da un pacchetto all'altro?

#' 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, che dipende PackageA, vorrei aggiungere ulteriori metodi di doWork:

#' @import PackageA 
setMethod(
    "doWork", 
    signature = c("character"), 
    definition = function(x) { 

     length(x) == 1 && x == "10" # Some more logic... 
    } 

Questo funziona. Tuttavia, significa che l'utente di PackageB deve anche library(PackageA).

Questo fallisce:

library(PackageB) 

doWork("10") # Fails! 

Questo funziona:

library(PackageA) 
library(PackageB) 

doWork("10") 

Vorrei utilizzare il generico PackageA in PackageB, ma non richiedono PackageA deve essere caricato per utilizzare solo i metodi in PackageB .

Come posso ottenere questo risultato?

risposta

9

Questo è in realtà documentato, ma non è molto chiaro; vedere la sezione 1.5.6 di Writing R Extensions.

Il trucco è di importare il generic da PackageA e quindi riesportarlo da PackageB. Utilizzando roxygen annotazioni, questo appare come:

#' @importMethodsFrom PackageA doWork 
#' @export 
setMethod(
    "doWork", 
    signature = c("character"), 
    definition = function(x) { 

     length(x) == 1 && x == "10" # Some more logic... 
    }) 

Quando si chiama devtools::document(), questa fallirà se non si ha prima caricato PackageA (chiamata library(PackageA)).

Tuttavia, una volta costruito, PackageA non è richiesta:

> library(PackageB) 
> showMethods("doWork") 
Function: doWork (package PackageA) 
x="character" 
x="numeric" 

Per riferimento, il file generato automaticamente NAMESPACE assomiglia:

exportMethods(doWork) 
importMethodsFrom(PackageA, doWork) 

Questo metodo produce nessun avviso sui conflitti di denominazione e così su, quindi sembra essere "kosher".

4

Questo sembra funzionare per me, ma non lo vedo documentato, quindi non necessariamente suppongo che sia kosher. pckgA:

#' @export 

setGeneric("doWork", function(x) standardGeneric("doWork")) 
setMethod("doWork", signature = "numeric", function(x) x == 11) 

e pckgB:

#' @export 
#' @import pckgA 

setGeneric("doWork", getGeneric("doWork", package="pckgA")) 
setMethod("doWork", "character", function(x) identical(x, "10")) 

Il trucco principale è stato quello di importare e riesportare doWork da pckgA in pckgB. Poi a partire da una sessione di R pulita:

library(pckgB) 
doWork("10") 
# [1] TRUE 
doWork("11") 
# [1] FALSE 
doWork(11) 
# [1] TRUE 
library(pckgA) 
doWork(11) 
# [1] TRUE 
doWork("10") 
# [1] TRUE 

Potrebbe essere necessario cancellare completamente l'area di lavoro (inclusi gli oggetti nascosti) per sbarazzarsi di eventuali definizioni dei metodi precedenti per questo a prendere realmente effetto correttamente.

+0

Il mio roxygen non sembra gradire questo: "Errore nel blocco del roxygen ... .Data non è uno slot nell'ambiente di classe" – sdgfsdh

+0

Noterò che questa è la soluzione perché funziona *, ma non lo fa Mi sembra il modo giusto di farlo. – sdgfsdh