从R源文件中提取注释,保持它们发生的功能

时间:2015-09-18 11:53:47

标签: r knitr

我想从我的R源脚本中提取注释(与模式匹配),保留它们发生的功能。

目标是使用经典的降价复选框- [ ]- [x]在函数体代码中编写文档注释,并将这些注释作为字符向量列表进行进一步处理 - 我可以轻松地将其写入新的{ {1}}文件。

下面的可重复示例和预期输出。

.md

2 个答案:

答案 0 :(得分:4)

以下是hrbmstr所做的精简版,未经评估的变体:

get_comments = function (filename) {
    is_assign = function (expr)
        as.character(expr) %in% c('<-', '<<-', '=', 'assign')

    is_function = function (expr)
        is.call(expr) && is_assign(expr[[1]]) && is.call(expr[[3]]) && expr[[3]][[1]] == quote(`function`)

    source = parse(filename, keep.source = TRUE)
    functions = Filter(is_function, source)
    fun_names = as.character(lapply(functions, `[[`, 2))
    setNames(lapply(attr(functions, 'srcref'), grep,
                    pattern = '^\\s*#', value = TRUE), fun_names)
}

这有一个警告:由于我们不评估源,我们可能会错过函数定义(例如,我们找不到f = local(function (x) x))。上面的函数使用一个简单的启发式方法来查找函数定义(它查看function表达式对变量的所有简单赋值。)

这只能使用eval(或source)进行修复,后者有自己的注意事项 - 例如,从未知来源执行文件会带来安全风险。

答案 1 :(得分:2)

任何人都不可能为你编写grep / stringr::str_match部分(这不是一个咕噜咕噜的代码编写服务)。但是,迭代解析的函数源的习惯用法可能对更广泛的受众有用,以保证包含。

CAVEAT source().R文件,意味着评估

#' Extract whole comment lines from an R source file
#'
#' \code{source()} an R source file into a temporary environment then
#' iterate over the source of \code{function}s in that environment and
#' \code{grep} out the whole line comments which can then be further
#' processed.
#' 
#' @param source_file path name to source file that \code{source()} will accept
extract_comments <- function(source_file) {

  tmp_env <- new.env(parent=sys.frame())
  source(source_file, tmp_env, echo=FALSE, print.eval=FALSE, verbose=FALSE, keep.source=TRUE)
  funs <- Filter(is.function, sapply(ls(tmp_env), get, tmp_env))

  lapply(funs, function(f) {
    # get function source
    function_source <- capture.output(f)
    # only get whole line comment lines
    comments <- grep("^[[:blank:]]*#", function_source, value=TRUE)
    # INCANT YOUR GREP/REGEX MAGIC HERE 
    # instead of just returning the comments
    # since this isn't a free code-writing service
    comments
  })

}

str(extract_comments("test.R"))
## List of 2
##  $ f: chr [1:2] "# - [ ] comment_f1" "# another non match to pattern"
##  $ g: chr [1:2] "# - [x] comment_g1" "# - [ ] comment_g2"