2012-09-22 1 views
7

J'écris actuellement un paquet en utilisant des classes de référence. Je suis venu à travers une question qui à la lecture de diverses sources:Classes de référence, complétion de tabulation et définition de méthode forcée

Method initialisation in R reference classes

Can't reliably use RefClass methods in Snowfall

Je déduis est dû au fait que les méthodes de référence ne sont pas tous copiés sur chaque objet dans la classe plutôt qu'ils sont copié lors de la première consultation.

https://stat.ethz.ch/pipermail/r-devel/2011-June/061261.html

À titre d'exemple définir:

test <- setRefClass("TEST", 
       fields = list(a = "numeric"), 
       methods = list(
        addone = function(){ 
             a <<- a+1 
             }, 
        initialize = function(){ 
              a <<- 1 
              } 
          ) 
       ) 

example <- test$new() 

Ainsi par exemple est un nouvel objet de la classe TEST. Taper example$ et la console tabuler dans donne

> example$ 
# example$.->a   example$.refClassDef example$.self   
# example$a   example$initialize 

donc la méthode addone n'est pas présenté comme une option. Il est disponible à appel cependant:

example$addone() 

maintenant à nouveau révèle tabulant

# > 
# > example 
# Reference class object of class "TEST" 
# Field "a": 
# [1] 2 
# > example$ 
# example$.->a   example$.refClassDef example$.self   
# example$a   example$addone  example$field   
# example$initialize example$show 

maintenant addone et field et show sont présentés comme des options.

Martin Morgan conseille de forcer la définition des méthodes dans l'un des liens ci-dessus. Ce fonctionne bien

test <- setRefClass("TEST", 
       fields = list(a = "numeric"), 
       methods = list(
        addone = function(){ 
             a <<- a+1 
             }, 
        initialize = function(){ 
              a <<- 1 
              .self$addone #force definition 
              } 
          ) 
       ) 

example <- test$new() 

maintenant donne tabbing:

# > example$ 
# example$.->a   example$.refClassDef example$.self   
# example$a   example$addone  example$initialize 

Certains de mes cours ont plus de 30 méthodes, donc je voudrais faire aussi succintement que possible. J'ai défini:

test <- setRefClass("TEST", 
       fields = list(a = "numeric"), 
       methods = list(
        addone = function(){ 
             a <<- a+1 
             }, 
        initialize = function(){ 
         a <<- 1 
         eval(parse(text=paste0('.self$',ls([email protected])))) 
              } 
          ) 
       ) 

example <- test$new() 

donne maintenant tabulant:

# > example$ 
# example$.->a   example$.refClassDef example$.self   
# example$a   example$addone  example$callSuper  
# example$copy   example$export  example$field   
# example$getClass  example$getRefClass example$import  
# example$initFields example$initialize example$show   
# example$trace  example$untrace  

Bien que cela fonctionne, il se sent un peu maladroit. Aussi [email protected] est utilisé plutôt que getRefClass("TEST")[email protected] de sorte que se sent un peu faux. Quelqu'un at-il déjà traité de cette question?

Existe-t-il une meilleure façon d'aborder une solution? Merci pour tous conseils et excuses si la question est trop étirée.

Répondre

6

Je me demande quel est votre objectif? Noms de fonctions apparaissant avec l'achèvement de l'onglet? Ensuite, il vaut la peine d'afficher un message sur la liste de diffusion R-devel avec une demande de fonctionnalité. Le scénario d'origine est plus élégamment traité avec usingMethods comme documenté sur ?setRefClass.Un hack continue pourrait être

initialize = function(...) { 
    methods <- getRefClass(class(.self))$methods() 
    eval(parse(text=paste0(".self$", methods))) 
    callSuper(...) 
} 

complétions Tab peuvent être personnalisés via .DollarNames dans le paquet utils, si

.DollarNames.TEST <- function(x, pattern) 
    grep(pattern, getRefClass(class(x))$methods(), value=TRUE) 

Peut-être une méthode S3 pourrait être écrit à la base de votre hiérarchie de classes pour cela?

+0

Merci, c'est très utile et plus élégant que ma solution. Aussi, je ne savais pas qu'il était appelé l'achèvement de l'onglet. Connaissant ce terme m'a permis de trouver le paquet pertinent dans les utils. L'achèvement de l'onglet avec les classes de référence était mon objectif et je vais modifier le titre de la question pour mieux refléter cela. – jdharrison

+0

Cela semble très prometteur. Serait-ce une mauvaise idée d'ajouter '.DollarNames.envRefClass <- function (x, motif) grep (motif, getRefClass (classe (x)) $ methods(), value = TRUE)' à mon paquetage? – jdharrison

+0

Oui, ce serait une mauvaise idée - vous changeriez de comportement pour toutes les classes de référence, pas seulement pour les vôtres. Peut-être que certains aiment son comportement actuel, peut-être 'methodes' implémentera un super-duper' .DollarNames.envRefClass' et votre méthode oubliée depuis longtemps l'utilisera. La bonne chose à faire est d'en faire une demande de fonctionnalité sur R-devel, surtout maintenant que vous avez au moins un prototype fonctionnel pour illustrer le comportement que vous jugez approprié. –

1

@Martin Morgan a noté que cela a été appelé achèvement de l'onglet. Le paquet rcompletion et plus tard rcompgen ont été chargés d'atteindre cet objectif. Ils ont maintenant été déplacés au utils.

rcompletion update

j'ai regardé à travers le code de completion.R et de ce que je pouvais déterminer utils:::.DollarNames.environment manipulait la touche de tabulation pour les classes de référence.

completion.R

Redéfinir la fonction semblait réaliser la complétion:

assignInNamespace(x = ".DollarNames.environment", 
        function(x, pattern = "") { 
    y <- NULL 
    if(isS4(x) && !is.null(x[['.refClassDef']])){ 
     if(.hasSlot(x$.refClassDef,'refMethods')){ 
     y<[email protected] 
     y<-ls(y, all.names = TRUE, pattern = pattern) 
     } 
    } 
    x<-ls(x, all.names = TRUE, pattern = pattern) 
    unique(c(x,y)) 
               } 
,ns = "utils") 

Quelques choses à noter:

  • J'utiliser seulement pour mon propre usage. Actuellement, je débogue et documente un paquet. J'ai eu quelques noms de méthode longish et ne me souviens pas exactement de ce qu'ils étaient si complétement de l'onglet aidera grandement.

  • L'utilisation de assignInNamespace dans un package est désapprouvée (si elle n'est pas interdite) voir ?assignInNamespace.

  • La définition forcée des méthodes est plus conseillée.

+0

En fait, '.DollarNames' est un générique S3 donc vous pouvez y écrire des méthodes S3; Je l'ai illustré dans ma réponse. –

3

Je sais c'est une vieille question, mais il est toujours la première entrée lors de la recherche onglet refClass terminé sur Google, donc je vais juste ajouter une mise à jour:

Au lieu d'utiliser grep dans le. fonction DollarNames comme suggéré par Martin, l'utilisation findMatches du paquet utils comme il joue mieux avec les différents parages Rgui (grep supprimera votre nom partiellement tapé sur l'onglet frapper)

.DollarNames.TEST <- function(x, pattern){ 
    utils:::findMatches(pattern, getRefClass(class(x))$methods()) 
} 

Ceci est également la façon dont la touche de tabulation est traité à l'interne pour les listes et les données.frames

Questions connexes