R 引用类、制表符完成和强制方法定义

R 引用类、制表符完成和强制方法定义,r,s4,reference-class,R,S4,Reference Class,我目前正在使用引用类编写一个包。我遇到过 这是一个通过阅读各种来源得出的结论: 我收集是因为引用方法并不是全部复制到每个对象 在类中,它们在第一次访问时被复制 例如,定义: test <- setRefClass("TEST", fields = list( a = "numeric"), methods = list( addone = function(){

我目前正在使用引用类编写一个包。我遇到过 这是一个通过阅读各种来源得出的结论:

我收集是因为引用方法并不是全部复制到每个对象 在类中,它们在第一次访问时被复制

例如,定义:

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

example <- test$new()
因此,方法
addone
不作为选项提供。可供 但是,请致电:

example$addone()
现在,选项卡再次显示

# > 
# > 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
现在,
addone
field
show
作为选项显示

MartinMorgan建议强制在上述链接之一中定义方法。这 效果很好

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()
我的一些类有30多个方法,所以我希望尽可能简洁地完成这项工作。 我定义了:

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

example <- test$new()
虽然这样做有效,但感觉有点笨拙。还有
测试$def@refMethods使用
而不是
getRefClass(“测试”)$def@refMethods
以便 感觉有点不对劲。以前有人处理过这个问题吗


有没有更好的解决方案?如果问题太长,谢谢你的建议和道歉。

我想知道你的目标是什么?函数名是否随选项卡完成一起显示?那么就值得在R-devel邮件列表中发布一个功能请求。如
?setRefClass
中所述,使用方法
可以更优雅地处理原始场景。持续的黑客攻击可能是

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

也许可以在类层次结构的基础上为此编写一个S3方法?

@Martin Morgan指出,这被称为制表符完成。包
rcompletion
和后来的
rcompgen
的任务就是实现这一点。它们现在已移动到
utils

我查看了
completion.R
的代码,根据我所能确定的
utils::.DollarNames.environment
正在处理引用类的制表符完成

重新定义该函数似乎可以实现制表符的完成:

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

y我知道这是一个老问题,但在google上搜索refClass tab completion时,它仍然是最重要的条目,因此我只需添加一个更新:

不要像Martin建议的那样在.DollarNames函数中使用grep,而是使用utils包中的findMatches,因为它可以更好地处理不同的Rgui(grep会在点击tab时删除部分键入的名称)


.DollarNames.TEST谢谢你,这比我的解决方案非常有用,而且更优雅。我也不知道它被称为tab completion。了解这个术语使我能够在UTIL中找到相关的包。使用参考类完成tab是我的目标,我将编辑问题标题以更好地反映这一点。这似乎很有希望。Wou添加
.DollarNames.envRefClass是的,这将是一个坏主意--您将更改所有引用类的行为,而不仅仅是您自己的引用类。也许一些人喜欢它的当前行为,也许
方法将在将来某个日期实现超级复制程序
。DollarNames.envRefClass
,而您早已忘记的方法将然后覆盖它。正确的做法是在R-devel上把它作为一个功能请求,特别是现在你至少有一个工作原型来说明你认为合适的行为。Martin Morgan感谢你的时间和专业知识。我将向R-devel发布一个功能请求。实际上,
。DollarNames
是一个S3通用因此,您可以在上面编写S3方法;我在回答中对此进行了说明。
# > 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     
initialize = function(...) {
    methods <- getRefClass(class(.self))$methods()
    eval(parse(text=paste0(".self$", methods)))
    callSuper(...)
}
.DollarNames.TEST <- function(x, pattern)
    grep(pattern, getRefClass(class(x))$methods(), value=TRUE)
assignInNamespace( x = ".DollarNames.environment",
                     function(x, pattern = "") {
    y <- NULL
    if(isS4(x) && !is.null(x[['.refClassDef']])){
      if(.hasSlot(x$.refClassDef,'refMethods')){
        y<-x$.refClassDef@refMethods
        y<-ls(y, all.names = TRUE, pattern = pattern)
      }
    }
    x<-ls(x, all.names = TRUE, pattern = pattern)
    unique(c(x,y))
                                               }
,ns = "utils")
.DollarNames.TEST <- function(x, pattern){
    utils:::findMatches(pattern, getRefClass(class(x))$methods())
}