Search code examples
rr-packageroxygen2

R CMD check gives warning when using @includeRmd for examples using Roxygene


I'm writing an R package using roxygen2 for documentation. I'm using the @includeRmd tag to reduce duplication, and this works well to generate consistent documentation across the help files, vignette, and pkgdown website.

My only issue is that, when I use the tag to insert examples, R CMD check gives me a nasty warning. Here is my setup:


R/adder.R ... source code for function with roxygen2 block

#' Add three numbers
#'
#' @includeRmd includes/adder_description.Rmd description
#'
#' @param x First number to add
#' @param y Second number to add
#' @param z Third number to add
#' @return The sum of the numbers
#'
#' @includeRmd includes/adder_examples.Rmd examples
#'
#' @md
#' @export
adder <- function(x, y, z) {
  x+y+z
}

includes/adder_description.Rmd ... description text to be included

The `adder()` function adds three numbers.

includes/adder_examples.Rmd ... example code to be included

```{r adder_examples}
adder(3,5,6)
``` 

In my vignette and README, I can insert the same description text and example code like so:

```{r child=rprojroot::find_package_root_file("includes", "adder_description.Rmd")}
```

```{r child=rprojroot::find_package_root_file("includes", "adder_examples.Rmd")}
```

All fine and dandy: the description text and example code are included consistently across the board. However, R CMD check gives the following warning about the \examples{} block generated by roxygen2 in man/adder.Rd:

> checking Rd files ... WARNING
  checkRd: (7) adder.Rd:23: Tag \if is invalid in a \examples block
  checkRd: (7) adder.Rd:23-24: Tag \preformatted is invalid in a \examples block
  checkRd: (7) adder.Rd:24: Tag \if is invalid in a \examples block
  checkRd: (7) adder.Rd:24-25: Tag \preformatted is invalid in a \examples block

Looking at the .Rd file, there certainly are some unusual tags that do not appear when I include the examples in a normal way.

My question is: Are these warnings issued because I am using the @includeRmd tag incorrectly, or is this use case just not what the tag was intended for? It seems that the warnings would preclude submission of the package to CRAN.


Solution

  • Your usage of the @includeRmd tag does not appear to be supported. You can use it to generate a Description or (sub)sections of Details, but not Examples. The documentation states:

    It is currently not possible to document function arguments, return values, etc. in external Rmd documents.

    That isn't too surprising, for a couple of reasons:

    • R CMD check expects the \examples{} block to contain verbatim R code, not Markdown, so injecting Markdown into the block without preprocessing is doomed to fail. Due to the chunk header and footer, the following is not valid R code:

      ```{r adder_examples}
      adder(3, 5, 6)
      ```
      

      That said, roxygen2 seems to do some preprocessing, since the above generates the following \examples{} block:

      \examples{
      \if{html}{\out{<div class="sourceCode r">}}\preformatted{adder(3, 5, 6)
      }\if{html}{\out{</div>}}\preformatted{## [1] 14
      }
      

      The injected text would be valid inside of \description{} or \details{}, but isn't valid inside of \examples{} as it is not verbatim R code.

    • As exceptions to the "verbatim" rule, the \examples{} block permits the \dontrun, \dontshow, and \donttest macros. They are handled exceptionally by R CMD check, but not by the knitr vignette engine. You'd get a build failure if you tried to insert this chunk into a vignette:

      ```{r adder_examples}
      adder(3, 5, 6)
      \dontrun{
      adder(3, 5, "6")
      }
      ```
      

      With chunk option eval = 1L, the parser still throws an error. (eval = FALSE seems OK, but then the first line isn't evaluated.) Hence, even if @includeRmd could be used to generate a valid \examples{} block, you wouldn't necessarily be able to share the code with a vignette.

    If you really want to externalize your Examples, then you can try doing it the old-fashioned way, i.e., with a shell script and sed, using @examples as a marker for text insertion (some examples here). I doubt the complexity is worth it, but you can be the judge...


    Update: I've just tried to hack things a bit with my own minimal package...

    pkgname <- "foo"
    usethis::create_package(pkgname, rstudio = FALSE, open = FALSE)
    setwd(pkgname)
    usethis::use_directory(file.path("inst", "examples"))
    text <- "
    #' @title A title
    #' @description A description.
    #' @param a,b Arguments.
    #' @includeRmd inst/examples/add.Rmd examples
    #' @export
    add <- function(a, b) a + b
    "
    cat(text, file = file.path("R", "add.R"))
    text <- "
    add(1, 1)
    "
    cat(text, file = file.path("inst", "examples", "add.Rmd"))
    roxygen2::roxygenize(".")
    writeLines(readLines(file.path("man", "add.Rd")))
    
    \examples{
    add(1, 1)
    }
    

    So it seemed like deleting the chunk header and footer might allow roxygen2 to generate a sensible \examples{} block. But I was wrong:

    text <- "
    add(1, 1)
    add(2, 2)
    "
    cat(text, file = file.path("inst", "examples", "add.Rmd"))
    roxygen2::roxygenize(".")
    x <- readLines(file.path("man", "add.Rd"))
    writeLines(tail(x, -(grep("^\\\\examples", x) - 1L)))
    
    \examples{
    add(1, 1) add(2, 2)
    }
    

    The generated text is invalid R code when the example spans two or more lines, because Markdown treats newlines like spaces.