代码之家  ›  专栏  ›  技术社区  ›  Rappster

有效地将源代码从多个文件整合到一个文件中,包括(Roxygen)注释

  •  2
  • Rappster  · 技术社区  · 13 年前

    问题

    将源代码从多个源文件合并到一个源文件的有效方法是什么?包括Roxygen文档注释,也可能包括其他注释?

    我记得有一个包中的解析方法可以解释注释(把它放在某个属性“字段”中),但我再也找不到了。


    背景信息

    主要有两个原因,我喜欢将源代码从给定数量的源文件合并到单个源文件的灵活性:

    1. 为了保持头脑清醒,我坚持“每个文件一个定义”的模式,每个源文件只包含一个定义(函数、S4方法、S4引用类等)。此外,这些源文件可能存储在我的“源目录”的不同子目录中,因此甚至可能具有相同的文件名。然而,为了组合一个真正的R包,有时最好将多个def分组到一个源文件中。在文件名重复的情况下,我甚至需要这样做。
    2. 在并行化时,可以将所有必要的源代码分组到一个文件中,并将其推送给工作进程,这样他们就可以获得代码

    作业

    这是我目前的解决方案;感觉“还好”,但是

    1. 我觉得可能有更好、更高效的方法
    2. 它在检测Roxygen代码方面似乎有点脆弱

    创建示例源文件

    foo1 <- function(x) {message("I'm foo #1"); return(TRUE)}
    roxy.1 <- c(
        "#' Title foo1()",
        "#'", 
        "#' Description foo1().",
        "##' This line is commented out",
        "#'", 
        "#' @param x Some R object that doesn't matter.",
        "#' @return \\code{TRUE}.",
        "#' @references \\url{http://www.something.com/}",
        "#' @author Janko Thyson \\email{john.doe@@something.com}",
        "#' @seealso \\code{\\link{foo2}}",
        "#' @example inst/examples/foo1.R"
    )
    
    foo2 <- function(y) {message("I'm foo #2"); return(FALSE)}
    roxy.2 <- c(
        "#' Title foo2()",
        "#'", 
        "#' Description foo2().",
        "##' This line is commented out",
        "#'", 
        "#' @param y Some R object that doesn't matter.",
        "#' @return \\code{FALSE}.",
        "#' @references \\url{http://www.something.com/}",
        "#' @author Janko Thyson \\email{john.doe@@something.com}",
        "#' @seealso \\code{\\link{foo1}}",
        "#' @example inst/examples/foo2.R"
    )
    
    dir.create("src/functions", recursive=TRUE, showWarnings=FALSE)
    dir.create("src/conso", recursive=TRUE, showWarnings=FALSE)
    
    write(roxy.1, file="src/functions/foo1.R")
    write(deparse(foo1), file="src/functions/foo1.R", append=TRUE)
    write(roxy.2, file="src/functions/foo2.R")
    write(deparse(foo2), file="src/functions/foo2.R", append=TRUE)
    

    合并功能

    consolidateThis <- function(
        path="src/functions",
        path.conso="src/conso/src_functions.R",
        rgx.roxy="^(#' ?|##' ?)(\\w*|@|$)",
        do.overwrite=TRUE,
        do.roxygen=TRUE,
        ...
    ) {
        if (!file.exists(path)) {
            stop("Check your 'path' argument")
        }
        files <- list.files(path, full.names=TRUE)
        if (do.overwrite) {
            file.create(path.conso)
        }
        sapply(files, function(ii) {
            this <- readLines(con=ii, warn=FALSE)
            code <- base::parse(text=this)
            if (do.roxygen) {     
                idx.roxy <- grep(rgx.roxy, this)
                if (length(idx.roxy)) {
                    if (length(idx.roxy) == 1) {
                        stop("Weird roxygen code (just a one-liner)") 
                    }
                    bench <- seq(from=idx.roxy[1], max(idx.roxy))
                    if (!all(bench %in% idx.roxy)) {
                        stop("Breaks in your roxygen code. Possibly detected comments that aren't roxygen code")
                    }
                    code.roxy <- this[idx.roxy]
                    write(code.roxy, file=path.conso, append=TRUE)
                }
            }
            write(c(deparse(code[[1]]), ""), file=path.conso, append=TRUE)
        })
        return(path.conso)
    }
    

    应用函数

    path <- consolidateThis()
    > path
    [1] "src/conso/src_functions.R"
    

    因此,现在有一个源文件“src/conso/src_functions.R”,其中包含合并的代码

    1 回复  |  直到 10 年前
        1
  •  2
  •   Josh O'Brien    13 年前

    您是否特别需要解析(然后展开)函数的源代码?如果没有,您可以大大简化代码。

    下面的输出与 ConsolidateThis()

    ConsolidateThis2 <-
    function(path="src/functions",
             path.conso="src/conso/src_functions.R",
             overwrite = TRUE) {
        if(overwrite) cat("", file = path.conso) # Blank out the file's contents
    
        ## A function to append infile's contents to outfile and add 2 <RET>          
        prettyappend <- function(infile, outfile) {
            file.append(outfile, infile)
            cat("\n\n", file = outfile, append = TRUE)
        }
    
        ## Append all files in 'path.conso' to file 'path'
        sapply(dir(path, full.names=TRUE), prettyappend, path.conso)
    }
    
    ConsolidateThis2()