Reusing documentation

roxygen2 provides several ways to avoid repeating yourself in code documentation, while assembling information from multiple places in one documentation file:

The chapter concludes by showing you how to update superseded reuse mechanisms that we no longer recommend: @includeRmd, @eval/@evalRd, and @template.

Multiple functions in the same topic

You can document multiple functions in the same file by using either @rdname or @describeIn tag. It’s a technique best used with care: documenting too many functions in one place leads to confusion. Use it when all functions have the same (or very similar) arguments.

@describeIn

Use @describeIn <destination> <description> to document mutiple functions together. It generates a new section named “Related functions and methods”, further divided into subsections by the type of relationship between the source and the destination documentation. Each subsection contains a bulleted list describing the function with the specified <description>.

You can document several functions which perform slight variations of a task or which use different defaults in one documentation file:

#' Power
#' @param x base
#' @param exp exponent
power <- function(x, exp) x ^ exp

#' @describeIn power Square a number
square <- function(x) power(x, 2)

#' @describeIn power Cube a number
cube <- function(x) power(x, 3)

In this case, both destination and source are “normal” functions, and you can use <description> to explain their differences.

@describeIn is also well suited to explain the relationships between functions making up an object oriented (OO) scheme using S3 or S4. In this case, roxygen will automatically detect whether a source function is a method and document the relationship to the relevant class or generic. Your new methods will be organised in one of two ways:

  1. If your new method extends a generic in the <destination>, it will be listed in a section titled “Methods for generic <destination>”. The subsection will include all methods for your new generic, labelled by the class they cover.

  2. If your new method extends another generic, for a class constructed in the destination, it will be listed in a subsection titled “Methods for class <destination>”. It will be labelled by the generic which the method extends.

While you can mix and match (some) different types of functions with @describeIn, the output may quickly become disorienting for users if the functions are not tightly related.

Order of includes

By default, roxygen blocks are processed in the order in which they appear in the file. When you’re combining multiple files, this can sometimes cause the function usage to appear in a suboptimal order. You can override the default ordering with @order. For example, the following the block would place times first in arith.Rd because 1 comes before 2.

#' @rdname arith
#' @order 2
add <- function(x, y) x + y

#' @rdname arith
#' @order 1
times <- function(x, y) x * y

Inheriting documentation

You can inherit documentation from other topics in a few ways:

All of these tags also work to inherit documentation from functions in another package by using pkg::source_function.

Inline code

To insert code inline, enclose it in `r `. Roxygen will interpret the rest of the text within backticks as R code and evaluate it, and replace the backtick expression with its value. Here’s a simple example:

#' Title `r 1 + 1`
#'
#' Description `r 2 + 2`
foo <- function() NULL

This is equivalent to writing:

#' Title 2
#'
#' Description 4
foo <- function() NULL

The resulting text, together with the whole tag is interpreted as markdown, as usual. This means that you can use R to dynamically write markdown. For example if you defined this function in your package:

alphabet <- function(n) {
  paste0("`", letters[1:n], "`", collapse = ", ")
}

You could then write:

#' Title
#' 
#' @param x A string. Must be one of `r alphabet(5)`
foo <- function(x) NULL

The result is equivalent to writing the following by hand:

#' Title
#' 
#' @param x A string. Must be one of `a`, `b`, `c`, `d`, `e`
foo <- function(x) NULL

This is a powerful technique for reducing duplication because you can flexibly parameterise the function however best meets your needs. Note that the evaluation environment is deliberately a child of the package that you’re documenting so you can call internal functions.

Child documents

You can use the same .Rmd or .md document in the documentation, README.Rmd, and vignettes but using child documents:

```{r child = "common.Rmd"}
```

The included Rmd file can have roxygen Markdown-style links to other help topics. E.g. [roxygen2::roxygenize()] will link to the manual page of the roxygenize function in roxygen2. See vignette("rd-formatting") for details.

If the Rmd file contains roxygen (Markdown-style) links to other help topics, then some care is needed, as those links will not work in Rmd files by default. A workaround is to specify external HTML links for them. These external locations will not be used for the manual which instead always links to the help topics in the manual. Example:

See also the [roxygen2::roxygenize()] function.

[roxygen2::roxygenize()]: https://roxygen2.r-lib.org/reference/roxygenize.html

This example will link to the supplied URLs in HTML / Markdown files and it will link to the roxygenize help topic in the manual.

Note that if you add external link targets like these, then roxygen will emit a warning about these link references being defined multiple times (once externally, and once to the help topic). This warning originates in Pandoc, and it is harmless.

Superseded

Over the years, we have experimented with a number of other ways to reduce duplication across documentation files. A number of these are now superseded and we recommend changing them to use the techniques described above:

Inline R markdown can only generate markdown text within a tag so in principle it is less flexible than @eval/@evalRd/@template. However, our experience has revealed that generating multiple tags at once tends to be rather inflexible, and you often end up refactoring into smaller pieces so we don’t believe this reflects a real loss of functionality.