R 函数的源代码是否在内部保留(通过其srcref
属性)取决于keep.source
定义函数时 option 的值。源代码是指用户输入的代码,带有注释、可能不一致的缩进、可能不一致的运算符间距等。
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}"
贡献包中的函数是否保留其源代码取决于R CMD INSTALL
从源(由您或由 CRAN)构建包时传递给的选项。--with-keep.source
默认是丢弃源代码,但您可以通过从源安装并设置标志来避免这种情况:
install.packages(pkgs, type = "source", INSTALL_opts = "--with-keep.source")
base
基本包( ,等)中的函数stats
不会有它们的源代码,除非你从源代码构建 R 本身并将环境变量R_KEEP_PKG_SOURCE
设置为yes
- 至少,这是我从?options
. 要了解构建 R,请参阅相应的手册。
给定一个带有源引用的函数,您可以以编程方式从源代码中提取注释。一种快速而肮脏的方法是模式匹配:
zzz <- deparse(g, control = "all")
grep("#", zzz, value = TRUE)
## [1] " ## A comment"
但是,可能存在误报,因为该模式#
还匹配包含哈希字符的字符串和非语法名称,它们根本不是注释。
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
返回的信息比您需要的多得多。这是一个您可以使用的实用程序,它将具有源引用的函数作为参数,并返回列出注释的字符向量(如果有):
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
。