如何在同一个软件包中使用roxygen2和doxygen?

91

我有一个使用了 roxygen2R 包。其中包含一些在 /src 中的 C 代码,并且我刚刚开始使用 Doxygen。是否有任何方法可以将这两种文档结合起来或将编译与 roxygen2 集成?关于放置 C 代码文档的位置,有没有什么“最佳实践”?

通过谷歌搜索 roxygen2 和 doxygen,主要得到的结果是“roxygen 类似于 doxygen”。我发现了一些带有 Doxyfiles 的软件包,但它们没有一致的组织形式。例如,lme4 有一个输出到名为 doxygen 的文件夹中的 inst/doc/Doxyfile。同时,Matrix 的根目录中也有一个 Doxyfile(但在之前的版本中是在 inst 中)。这些文档也导出到软件包目录外。

是否有任何理由不将 C 文档包含在软件包中,或者为什么尽管广泛使用 C,Doxygen 在 R 软件包中如此少用?

更新:请参见相关的 roxygen2 功能请求


8
这并不是回答你的问题,但如果你使用Rcpp,你可以使用roxygen2来记录你所导出的C++函数。 - hadley
2
我猜Doxygen在R包中并不常用,因为人们不会记录他们的C代码。C代码几乎从不是API和R包的一部分,所以人们只是不记录它。如果您想将C文档放入软件包中,只需从Makefile生成HTML并将其放入inst/即可。 - Gabor Csardi
1
我不了解roxygen,但是它可能有一些XML输出,就像doxygen一样,您可以将其与一些XSLT结合使用,并从中创建完整的文档。 - Daniel Albuschat
你是想将roxygen2输入包含在doxyten输出中,还是反过来? - Denise Skidmore
1个回答

4
我个人使用以下代码在我所有的脚本中调用一个名为"dataManagement"的包。它有roxygen文档和示例。您只需调用document(),就可以在src/中运行doxygen C代码,并将文档放在inst/doxygen中,使您的软件包符合CRAN要求。
由于R文档是为R终端用户设计的,不应查看C代码,因此我没有将C代码文档集成到经典的R文档中,但将生成的C文档作为“vignette”复制可能是一个好习惯。
    library("testthat")
    library("devtools")

    #' @title Replace a value for a given tag on file in memory
    #' @description Scan the lines and change the value for the named tag if one line has this tag, 
    #'    add a line at the end if no line has this tag and return a warning if several lines
    #'    matching the tag
    #' @param fileStrings A vector with each string containing a line of the file
    #' @param tag The tag to be searched for 
    #' @param newVal The new value for the tag
    #' @return The vector of strings with the new value
    #' @examples
    #' fakeFileStrings <- c("Hello = world","SURE\t= indeed","Hello = you")
    #' 
    #' expect_warning(ReplaceTag(fakeFileStrings,"Hello","me"))
    #' 
    #' newFake <- ReplaceTag(fakeFileStrings,"SURE","me")
    #' expect_equal(length(newFake), length(fakeFileStrings))
    #' expect_equal(length(grep("SURE",newFake)), 1)
    #' expect_equal(length(grep("me",newFake)), 1)
    #' 
    #' newFake <- ReplaceTag(fakeFileStrings,"Bouh","frightened?")
    #' expect_equal(length(newFake), length(fakeFileStrings)+1)
    #' expect_equal(length(grep("Bouh",newFake)), 1)
    #' expect_equal(length(grep("frightened?",newFake)), 1)
    ReplaceTag <- function(fileStrings,tag,newVal){
        iLine <- grep(paste0("^",tag,"\\>"),fileStrings)
        nLines <- length(iLine)
        if(nLines == 0){
            line <- paste0(tag,"\t= ",newVal)
            iLine <- length(fileStrings)+1
        }else if (nLines > 0){
            line <- gsub("=.*",paste0("= ",newVal),fileStrings[iLine])
            if(nLines >1){
                warning(paste0("File has",nLines,"for key",tag,"check it up manually"))
            }
        }
        fileStrings[iLine] <- line
        return(fileStrings)
    }
    #' Prepares the R package structure for use with doxygen
    #' @description Makes a configuration file in inst/doxygen
    #'     and set a few options: 
    #'     \itemize{
    #'        \item{EXTRACT_ALL = YES}
    #'        \item{INPUT = src/}
    #'        \item{OUTPUT_DIRECTORY = inst/doxygen/}
    #'     }
    #' @param rootFolder The root of the R package
    #' @return NULL
    #' @examples 
    #' \dontrun{
    #' DoxInit()
    #' }
    #' @export
    DoxInit <- function(rootFolder="."){
        doxyFileName <- "Doxyfile"
        initFolder <- getwd()
        if(rootFolder != "."){
            setwd(rootFolder)
        }
        rootFileYes <- length(grep("DESCRIPTION",dir()))>0
        # prepare the doxygen folder
        doxDir <- "inst/doxygen"
        if(!file.exists(doxDir)){
            dir.create(doxDir,recursive=TRUE)
        }
        setwd(doxDir)

        # prepare the doxygen configuration file
        system(paste0("doxygen -g ",doxyFileName))
        doxyfile <- readLines("Doxyfile")
        doxyfile <- ReplaceTag(doxyfile,"EXTRACT_ALL","YES")
        doxyfile <- ReplaceTag(doxyfile,"INPUT","src/")
        doxyfile <- ReplaceTag(doxyfile,"OUTPUT_DIRECTORY","inst/doxygen/")
        cat(doxyfile,file=doxyFileName,sep="\n")
        setwd(initFolder)
        return(NULL)
    }

    #' devtools document function when using doxygen
    #' @description Overwrites devtools::document() to include the treatment of 
    #'    doxygen documentation in src/
    #' @param doxygen A boolean: should doxygen be ran on documents in src?
    #'     the default is TRUE if a src folder exist and FALSE if not
    #' @return The value returned by devtools::document()
    #' @example
    #' \dontrun{
    #' document()
    #' }
    #' @export
    document <- function(doxygen=file.exists("src")){
        if(doxygen){
            doxyFileName<-"inst/doxygen/Doxyfile"
            if(!file.exists(doxyFileName)){
                DoxInit()
            }
            system(paste("doxygen",doxyFileName))
        }
        devtools::document()
    }

谢谢!我想我没有意识到简单的解决方案是重新定义devtools::document并添加一个系统调用来执行doxygen path/to/Doxyfile。我已经将其添加到我的软件包中,并在roxygen2的GitHub存储库中添加了一个功能请求。@hadley - Abe
据我所了解,这个功能的拉取请求并未被接受。但是,由于我仍然希望有一种方便的方法来创建doxygen文档,因此我基于上述代码创建了一个小型R包 - nevrome

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接