I have a package with many functions that use the same parameters and should have the same documentation for those parameters. I can certainly use @inheritParams, but there is no single function that serves as the "main" or "parent" function in the package that others could inherit from. I could pick a few for this purpose, but it would be on an arbitrary basis. Is there a best practice for handling this situation?
One thought would be to have a helper function that does nothing yet has documentation for many of these parameters that other functions can inherit from. I would think this would mean using @noRd on this helper function and having my real functions reference its @param definitions with @inheritParams, but as can be seen in this Github issue, this does not work and will not be supported.
I've also seen creative ideas like using dynamic R code to generate shared documentation, but the context there was different (item descriptions, not parameters), and I'm not sure how to use it.
Long story short, I'd like to do what @inheritParams was made for, but where the concept of inheritance would be rather artificial and arbitrary. What do you recommend as best practice?
Inline code is the current recommendation.
Their example:
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.
Note they also specifically no longer recommend a few things:
The chapter concludes by showing you how to update superseded reuse mechanisms that we no longer recommend: @includeRmd, @eval/@evalRd, and @template.
Based on this answer, you might actually get closer to what you want.
In R/roxygen.R
#' @param project The project directory. If `NULL`, then the active project will
#' be used. If no project is currently active, then the current working
#' directory is used instead.
#'
#' @param type The type of package to install ("source" or "binary"). Defaults
#' to the value of `getOption("pkgType")`.
#'
#' @return The project directory, invisibly. Note that this function is normally
#' called for its side effects.
#'
#' @name renv-params
NULL
Then you would use inherit for your actual functions.
In R/embed.R
#' Embed a Lockfile
#'
#' Use `embed()` to embed a lockfile directly within a file.
#'
#' This is primarily useful in tandem with [run] -- if you call `renv::run()`
#' on a script containing an inline lockfile, `renv` will first provision
#' a library based on that lockfile definition, and then run the script
#' using that lockfile.
#'
#' @inheritParams renv-params
#'
#' @param path The path to an \R or R Markdown script.
#'
#' Embed a Lockfile
#'
#' Use `embed()` to embed a lockfile directly within a file.
#'
#' This is primarily useful in tandem with [run] -- if you call `renv::run()`
#' on a script containing an inline lockfile, `renv` will first provision
#' a library based on that lockfile definition, and then run the script
#' using that lockfile.
#'
#' @inheritParams renv-params
#'
#' @param path The path to an \R or R Markdown script.
#'
embed <- function(path = NULL,
...,
project = NULL)