2015-09-18 20 views
3

我想從我的R源代碼腳本中提取註釋(與模式匹配),以保留它們發生的功能。從R源文件中提取註釋,保留它們發生的功能

的目標是編寫使用經典的降價複選框- [ ]- [x]內部函數體代碼文檔註釋,並提取作進一步處理這些意見作爲特徵向量的名單 - 我可以輕鬆編寫新.md文件。

下面是可重複使用的示例和預期輸出。

# preview the 'data' 
script_body = c('# some init comment - not matching pattern','g = function(){','# - [x] comment_g1','# - [ ] comment_g2','1','}','f = function(){','# - [ ] comment_f1','# another non match to pattern','g()+1','}') 
cat(script_body, sep = "\n") 
# # some init comment - not matching pattern 
# g = function(){ 
#  # - [x] comment_g1 
#  # - [ ] comment_g2 
#  1 
# } 
# f = function(){ 
#  # - [ ] comment_f1 
#  # another non match to pattern 
#  g()+1 
# } 

# populate R souce file 
writeLines(script_body, "test.R") 

# test it 
source("test.R") 
f() 
# [1] 2 

# expected output 
r = magic_function_get_comments("test.R", starts.with = c(" - [x] "," - [ ] ")) 
# r = list("g" = c(" - [x] comment_g1"," - [ ] comment_g2"), "f" = " - [ ] comment_f1") 
str(r) 
# List of 2 
# $ g: chr [1:2] " - [x] comment_g1" " - [ ] comment_g2" 
# $ f: chr " - [ ] comment_f1" 

回答

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)修復,它帶有自己的警告 - 例如,執行來自未知來源的文件存在安全風險。

+0

jangorecki - 你真的接受這個答案,所以我可以刪除我(康拉德的是一個更好的解決方案) – hrbrmstr

+0

@hrbrmstr恭敬地不同意。 –

+0

@hrbrmstr我會接受這個但不刪除你的,它回答問題,它是好的,它教人,我也看到它的價值! – jangorecki

2

這是不太可能有人會寫的grep/stringr::str_match一部分,你(這不是一個咕嚕代碼編寫服務)。但是,對已解析的函數源進行迭代的習慣用法可能對更廣泛的受衆足夠有用,以保證包含。

CAVEATsource() S中.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" 
+0

「我這樣做是因爲source()保留了評論,而解析不是。」實際上,'source'在內部使用'parse'。 –

+0

我的簡短嘗試可能是沒有根據的(我知道它保留了它,但通過解析來獲得註釋是一種痛苦)。我會重新詞組。 – hrbrmstr

+0

評估不是問題,所以你的解決方案是完美的,我會自己處理正則表達式 - 同意你對此的評論。謝謝! – jangorecki