2015-10-25 4 views
1

J'ai un paquet de prétraitement avec une fonction wrapper qui aide l'utilisateur à utiliser l'héritage. Ces classes et méthodes définies par l'utilisateur ne peuvent pas être stockées dans l'espace de noms de package scellé comme je l'ai fait avec les méthodes et classes par défaut du code de niveau supérieur. Quel est l'environnement approprié pour attribuer les définitions? La solution ci-dessous semble fonctionner d'une manière ou d'une autre mais je ne la comprends pas assez bien.Les wrappers setClass et setMethod utilisés dans un package: quel est l'environnement d'affectation correct?

setpreprocessor <- function(classname, operation, mode="numeric"){ 

setClass(classname, contains="PreprocessorClass", 
where=topenv(parent.frame()), prototype=prototype(objectname=classname, 
objectoperation=operation)) 

setMethod("transformdata", where=topenv(parent.frame()), signature(object = 
classname), function(object, dataobject) { 

...code here uses arguments "operation" and "mode"... 
}) 
} 

Répondre

2

Voici un exemple plus complet, avec une mise en forme pour rendre la structure du code un peu plus apparente

setClass("PreprocessorClass") 

setGeneric("transformdata", 
      function(object, dataobject) standardGeneric("transformdata")) 

setpreprocessor <- function(classname, operation, mode="numeric") { 

    setClass(classname, contains="PreprocessorClass", 
      where=topenv(parent.frame()), 
      prototype=prototype(objectname=classname, 
       objectoperation=operation)) 

    setMethod("transformdata", signature(object = classname), 
       where=topenv(parent.frame()), 
       function(object, dataobject) { 
        ## code that uses 'operation', 'mode' 
        list(operation, mode) 
       }) 
} 

parent.frame() est l'environnement dont la fonction est appelé (pas à l'environnement dans lequel la fonction est définie).

Presque tous les environnements ont un environnement englobant, généralement l'environnement dans lequel l'environnement lui-même a été défini défini; voir ?parent.env. topenv() commence à partir de l'argument spécifié et trace les environnements englobants de chaque environnement jusqu'à ce qu'il atteigne .GlobalEnv ou un espace de noms de package.

Donc, si votre code était dans un paquet PkgA, l'utilisateur a chargé le paquet, puis de l'invoquaient setpreprocessor("Foo", "bar") environnement mondial (invite de commande), parent.frame() retournerait .GlobalEnv, tout comme topenv(). Vous verrez

> ls(all=TTRUE) 
[1] ".__C__Foo" ".__T__transformdata:PkgA" 

qui sont les définitions de classe et de méthode créées dans l'environnement global. D'autre part, si l'utilisateur utilisait setpreprocessor() dans une fonction dans un package, topenv(parent.frame()) se retrouverait dans l'espace de noms du package (scellé). Étant donné que l'espace de noms de package est scellé, il ne serait pas possible de créer les définitions de classe ou de méthode.

Une alternative consiste à fournir un environnement dans lequel les définitions de classe et le procédé peuvent être mises en cache

.PreprocessorCache <- new.env() 

setClass("PreprocessorClass") 
## ... 

puis utiliser

where=.PreprocessorCache 

dans les définitions des classes et méthodes. setpreprocessor() peut ensuite être appelée de manière interactive ou dans un code de package.

+0

Merci beaucoup! Le problème original a été résolu et une solution de niveau supérieur a été suggérée. – user2968765