R:查找带有作者评论的代码(如果有)

R: Finding code with authors' comments, if any

是否有沿 getAnywhere() 的任何相当简单、直接的函数,其中 returns 带有任何注释的函数的源代码,这样如果我没有看到任何注释,我可以确信有none,代码是用 R、c、c++、Fortran 还是其他语言编写的?例如,stats:::plot.acf 似乎没有任何评论。我可以由此得出结论,它的文本没有评论吗?

我知道有一个类似流程图的搜索过程,如果您知道源代码是用 R 编写的,那么可以通过一些适当的搜索方法从特定的 github 存储库获得包含注释的源代码 tp gethub .此外,如果您确定代码使用的是某种特定的其他语言,则可以通过更精细的搜索过程获得它,该过程涉及找到正确的文件,然后在其中进行文本搜索,这与基础包和贡献包不同。我的印象是,至少直到最近,如果您想了解是否有包含注释的代码版本,通过隐式流程图搜索方法学习和工作并没有捷径。此外,我相信除了注释本身或先验知识外,没有任何地方可以识别出包含或不包含注释的代码版本。

但是,R 是一个发展相当迅速的生态系统,我认为希望有更简单的工具来确定是否存在包含注释的源版本并在存在时找到它并不是完全没有道理的,现在可能存在。是吗?

R 函数的源代码是否在内部保留(通过其 srcref 属性)取决于函数定义时选项 keep.source 的值。 源代码,我指的是用户输入的代码,带有注释、可能不一致的缩进、可能不一致的运算符间距等

options(keep.source = FALSE)
f <- function(x) {
    ## A comment
        x +
  1}

getSrcref(f)
## NULL # (invisibly)

deparse(f, control = "all")
## [1] "function (x) "
## [2] "{"            
## [3] "    x + 1"    
## [4] "}" 
options(keep.source = TRUE)
g <- function(x) {
    ## A comment
        x +
  1}

getSrcref(g)
## function(x) {
##     ## A comment
##         x +
##   1}

deparse(g, control = "all")
## [1] "function(x) {"   
## [2] "    ## A comment"
## [3] "        x +"     
## [4] "  1}"

贡献包中的函数是否保留其源代码取决于在从源构建包(由您或 CRAN)构建包时传递给 R CMD INSTALL 的选项。默认是丢弃源代码,但您可以通过从源安装并设置 --with-keep.source 标志来避免这种情况:

install.packages(pkgs, type = "source", INSTALL_opts = "--with-keep.source")

基础包(basestats 等)中的函数不会有它们的源代码,除非您从环境变量 R_KEEP_PKG_SOURCE 设置为 [ 的源构建 R 本身=25=]——至少,这是我从?options中推断出来的。要了解构建 R,请参阅相应的 manual.

给定一个带有源代码引用的函数,您可以通过编程方式从源代码中提取注释。一种快速而肮脏的方法是模式匹配:

zzz <- deparse(g, control = "all")
grep("#", zzz, value = TRUE)
## [1] "    ## A comment"

不过,可能存在误报,因为模式 # 也匹配字符串和包含散列字符的 non-syntactic 名称,它们根本不是注释。

grep("#", "\"## Not a comment\"", value = TRUE)
## [1] "\"## Not a comment\""

一种更可靠的提取评论的方法是检查解析数据中类型为 COMMENT:

的标记
getParseData(parse(text = zzz), includeText = NA)
##    line1 col1 line2 col2 id parent          token terminal         text
## 23     1    1     4    4 23      0           expr    FALSE             
## 1      1    1     1    8  1     23       FUNCTION     TRUE     function
## 2      1    9     1    9  2     23            '('     TRUE            (
## 3      1   10     1   10  3     23 SYMBOL_FORMALS     TRUE            x
## 4      1   11     1   11  4     23            ')'     TRUE            )
## 20     1   13     4    4 20     23           expr    FALSE             
## 6      1   13     1   13  6     20            '{'     TRUE            {
## 8      2    5     2   16  8     20        COMMENT     TRUE ## A comment
## 17     3    9     4    3 17     20           expr    FALSE             
## 10     3    9     3    9 10     12         SYMBOL     TRUE            x
## 12     3    9     3    9 12     17           expr    FALSE             
## 11     3   11     3   11 11     17            '+'     TRUE            +
## 14     4    3     4    3 14     15      NUM_CONST     TRUE            1
## 15     4    3     4    3 15     17           expr    FALSE             
## 16     4    4     4    4 16     20            '}'     TRUE            }

显然,getParseData returns 的信息比您需要的多得多。这是一个您可以改用的实用程序,它将带有源引用的函数和 returns 列出注释的字符向量作为参数,如果有的话:

getComments <- function(func) {
    func <- match.fun(func)
    if (is.null(getSrcref(func))) {
        stop("'func' has no source references")
    }
    data <- getParseData(func, includeText = NA) 
    if (is.null(data)) {
        op <- options(keep.source = TRUE, keep.parse.data = TRUE)
        on.exit(options(op))
        expr <- parse(text = deparse(func, control = "all"))
        data <- getParseData(expr, includeText = NA)
    }
    data$text[data$token == "COMMENT"]
}
getComments(g)
## [1] "## A comment"

h <- function(x) {
    ## I will comment
            ##     anywhere
    ######## and with as many hashes
    x + 1 # as I want!
}

getComments(h)
## [1] "## I will comment"                
## [2] "##     anywhere"                 
## [3] "######## and with as many hashes"
## [4] "# as I want!"

## You will need Rtools on Windows and Command Line Tools on macOS
## to install from sources packages containing C/C++/Fortran code.
## 'lme4' is one such package ... feel free to choose a different one.
install.packages("lme4", type = "source", INSTALL_opts = "--with-keep.source")
getComments(lme4::lmer)
##  [1] "## , ...)"                                                                              
##  [2] "## see functions in modular.R for the body .."                                          
##  [3] "## back-compatibility kluge"                                                            
##  [4] "## if (!is.null(list(...)[[\"family\"]])) {"                                            
##  [5] "##    warning(\"calling lmer with 'family' is deprecated; please use glmer() instead\")"
##  [6] "##    mc[[1]] <- quote(lme4::glmer)"                                                    
##  [7] "##    if(missCtrl) mc$control <- glmerControl()"                                        
##  [8] "##    return(eval(mc, parent.frame(1L)))"                                               
##  [9] "## }"                                                                                   
## [10] "## update for  back-compatibility kluge"                                                
## [11] "## https://github.com/lme4/lme4/issues/50"                                              
## [12] "## parse data and formula"                                                              
## [13] "## create deviance function for covariance parameters (theta)"                          
## [14] "## optimize deviance function over covariance parameters"                               
## [15] "## prepare output"

AFAIK,没有方便的机制来检查 R 函数调用的 C 代码在编译之前是否包含注释...

一如既往,相关文档有点零散。我发现这些帮助页面很有用:?parse?deparse?.deparseOpts?srcref(以及其中的链接)、?options?getParseData