Using roxygen2 and doxygen on the same package? [closed]
Asked Answered
C

1

91

I have an R package that uses roxygen2. It has some C code in /src, and I have just started working with Doxygen. Are there any ways to combine the documentation or integrate compiling with roxygen2? Any "best practices" for where to put the C code documentation?

Googling for roxygen2 and doxygen primarily leads to roxygen is similar to doxygen results. I have found a few packages with Doxyfiles, but no consistent organization. For example, lme4 has inst/doc/Doxyfile output to a folder called doxygen outside the lme4 source directory. There is also a Doxyfile in the root directory of the Matrix (but in previous releases was in inst. This documentation is also exported outside the package directory.

Is there any reason not to include the C documentation inside a package, or why is Doxygen so infrequently used within R packages, despite widespread use of C?

update: see related roxygen2 feature request

Carrolcarroll answered 20/12, 2013 at 23:24 Comment(4)
This doesn't answer your question, but if you use Rcpp you can use roxygen2 to document your exported C++ functionsDillondillow
I guess Doxygen is not used in R packages, because people do not document their C code. C code is almost never part of the API and R package provides, so people just do not document it. If you want to put your C docs in the package, just generate the HTML from a Makefile and put it in inst/.Gault
I don't know roxygen, but maybe it has some xml output, as doxygen has, and you can combine it with some xslt and create a complete doc from that.Vidrine
Are you trying to include roxygen2 input in doxyten output or the other way around?Acquiescent
G
4

I personally use the following code in a "dataManagement" package I call in all my scripts. It has roxygen documentation and examples. You actually simply call document() and have doxygen ran on the C code, in src/ . The doc is put in inst/doxygen So that your package is CRAN ready.

The R documentation being designed for R end users not supposed to look at the C code I didn't integrate the C code documentation in the classic R documentation but it would probably be a good practice to copy the resulting C documentation as a "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()
    }
Grange answered 23/2, 2015 at 16:43 Comment(2)
Thanks! I guess I didn't realize that the simple solution was to re-define devtools::document to add a system call to doxygen path/to/Doxyfile. I've added this to my package. I've also added a feature request in the roxygen2 github repository @DillondillowCarrolcarroll
So - as far as I understand it, the pull request for this feature was not accepted. Because I nevertheless wanted to have a convenient way to create doxygen documentation, I created a small R package based on the code above.Analogy

© 2022 - 2024 — McMap. All rights reserved.