有效地将来自多个文件的源代码整合到单个文件中,包括(Roxygen)注释

时间:2012-09-12 15:28:09

标签: r roxygen2 roxygen consolidation

问题

将源代码从多个源文件合并到单个源文件的有效方法是什么 - 包括Roxygen文档注释以及可能还包括其他注释?

我记得有些软件包中有一个解析方法可以解释注释(将它放在某个属性“field”中),但我再也找不到它了。


背景信息

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

  1. 为了保持领先,我坚持“每个文件一个定义”范例,其中每个源文件只包含一个定义(函数,S4方法,S4参考类等)。此外,这些源文件可能存储在我的“源目录”的各个子目录中,因此甚至可能具有相同的文件名。然而,为了将真正的R包组合在一起,有时最好将多个defs组合到一个源文件中。如果文件名重复,我甚至需要。
  2. 并行化时,能够将一个文件中所需的所有源代码分组并将其推送到工作进程以便他们可以获取代码是很方便的
  3. 作业

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

    1. 我觉得可能会有更好的,更高效的方法,
    2. 检测Roxygen代码似乎有点脆弱
    3. 创建示例源文件

      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 个答案:

答案 0 :(得分:2)

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

以下产生与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()