Skip to contents

The rd2markdown package

Markdown has become a staple markup syntax and is commonly used as an interface in modern developer tools. Markdown is used for READMEs, for static content generation and as a rich text interchange format for language servers. As these use cases become more common, it becomes increasingly important that R provides an interface to its documentation to more seamlessly integrate with these tools.

The rd2markdown itself is a dependency-less, base R centric package that converts .Rd documentation objects into markdown files. This isn’t the first package to attempt to solve this problem, but we feel this approach is more robust, extensible and maintainable. We aim to provide a solution that, with a help of the R community, will satisfy requirements set by various use cases and groups.

Functionalities

The rd2markdown package provides tools to conveniently extract the documentation objects and then convert them into standard markdown files. Right now, those functionalities are provided by three functions exported for the end-user.

rd2markdown

Overview

The rd2markdown is the core of the rd2markdown package. This interface is modelled after the tools::Rd2* family of functions, filling the gap in this family of functions to target markdown. It is here, that the actual conversion from .Rd into .md happens. It uses the innovative idea of treating particular Rd tags as classes and dispatching to particular methods accordingly. Thanks to that, most of the common tags have dedicated treatment and can be formatted in various ways. On top of that, such a design ensures trouble-free extensibility of the package, should new tags need to be covered.

rd2markdown can work in various types. It accepts .Rd objects extracted with get_rd option but also can directly fetch documentation topics based on the file path or the package. rd2markdown will leverage this functionality when needed to flexibly convert provided Rd files provided as text, file paths or help aliases. It is worth pointing out that the actual output of rd2markdown function is a character vector of length one that uses special signs to format the document. Use writeLines function to create an actual markdown file using this output.

At the beginning, lets set up the paths for examples files we are going to use throughout the vignette.

rd_files <- c("rd_file_sample.Rd", "rd_file_sample_2.Rd")
rd_examples_path <- system.file("examples", package = "rd2markdown")
rd_examples_macro <- file.path(rd_examples_path, "macros", "macros.Rd")
rd_examples <- file.path(rd_examples_path, rd_files)

Examples

Basic usage with previously extracted documentation

rd <- rd2markdown::get_rd(file = rd_examples[[1]])
md <- rd2markdown::rd2markdown(rd)
cat(md)
## # Rd sampler title
## 
## ```r
## rd_sampler(x, y = TRUE, ...)
## ```
## 
## ## Arguments
## 
## - `x`: Rd sampler param
## - `y`: Rd sampler param with default
## - `...`: Rd sampler ellipsis param
## 
## ## Returns
## 
## Rd sampler return
## 
## ## Description
## 
## Rd sampler description with [Rd sampler link](www.example.com), `Rd sampler in-line code`. And Rd dynamic content, **italics text**, **emphasis text**.
## 
## ## Details
## 
## Rd sampler details
## 
## Rd sampler enumerated list
## 
## 1. One
## 2. Two
## 3. Three
## 
## Rd sampler itemized list
## 
##  * One
##  * Two
##  * Three
## 
## ||||
## |:--|:--|:--|
## |Rd|Sampler|Table|
## |rd|sampler|table|
## 
## `Rd + sampler + inline + equation`
## 
## `Rd * sampler * block * equation`
## 
## ## Note
## 
## Rd sampler note
## 
## ## Rd sampler subsection
## 
## Rd sampler subsection text
## 
## ### Rd sampler sub-subsection
## 
##  Rd sampler sub-subsection text
## 
## ## Examples
## 
## ```r
## rd_sampler()
## ```
## 
## ## References
## 
## R.D. Sampler. (2021)
## 
## ## See Also
## 
## base::print
## 
## ## Author(s)
## 
## R.D. Sampler.

The content of the document object can be trimmed to particular sections with fragments parameter. It corresponds to actual R package documentation sections

rd <- rd2markdown::get_rd(file = rd_examples[[1]])
md <- rd2markdown::rd2markdown(rd, fragments = c("description", "usage"))
cat(md)
## ```r
## rd_sampler(x, y = TRUE, ...)
## ```
## 
## ## Description
## 
## Rd sampler description with [Rd sampler link](www.example.com), `Rd sampler in-line code`. And Rd dynamic content, **italics text**, **emphasis text**.

rd2markdown function can also work with a path to the file taking advantage of the hidden parameter file (and macros if necessary)

md <- rd2markdown::rd2markdown(file = rd_examples[[1]])
cat(md)
## # Rd sampler title
## 
## ```r
## rd_sampler(x, y = TRUE, ...)
## ```
## 
## ## Arguments
## 
## - `x`: Rd sampler param
## - `y`: Rd sampler param with default
## - `...`: Rd sampler ellipsis param
## 
## ## Returns
## 
## Rd sampler return
## 
## ## Description
## 
## Rd sampler description with [Rd sampler link](www.example.com), `Rd sampler in-line code`. And Rd dynamic content, **italics text**, **emphasis text**.
## 
## ## Details
## 
## Rd sampler details
## 
## Rd sampler enumerated list
## 
## 1. One
## 2. Two
## 3. Three
## 
## Rd sampler itemized list
## 
##  * One
##  * Two
##  * Three
## 
## ||||
## |:--|:--|:--|
## |Rd|Sampler|Table|
## |rd|sampler|table|
## 
## `Rd + sampler + inline + equation`
## 
## `Rd * sampler * block * equation`
## 
## ## Note
## 
## Rd sampler note
## 
## ## Rd sampler subsection
## 
## Rd sampler subsection text
## 
## ### Rd sampler sub-subsection
## 
##  Rd sampler sub-subsection text
## 
## ## Examples
## 
## ```r
## rd_sampler()
## ```
## 
## ## References
## 
## R.D. Sampler. (2021)
## 
## ## See Also
## 
## base::print
## 
## ## Author(s)
## 
## R.D. Sampler.
md <- rd2markdown::rd2markdown(
  file = rd_examples[[2]],
  macros = rd_examples_macro # Use macros = NA to automatically discover macros
  )  
cat(md)
## # Rd data sampler
## 
## ## Format
## 
## A data.frame with 3 rows and 2 variables:
## 
## - **x**: Numeric values
## - **y**: Character values
## 
## ## Source
## 
## <r.d.sampler/>
## 
## ```r
## rd_data_sampler
## ```
## 
## ## Description
## 
## An example of dataset documentation and linking to others `rnorm()`
## 
## ## Examples
## 
## ```r
## rd_data_sampler
## ```

or take documentation object directly from the package with a help of topic and package

md <- rd2markdown::rd2markdown(
  topic = "rnorm",
  package = "stats",
  fragments = c("description", "usage")
)

cat(md)
## ## Description
## 
## Density, distribution function, quantile function and random generation for the normal distribution with mean equal to `mean` and standard deviation equal to `sd`.
## 
## ```r
## dnorm(x, mean = 0, sd = 1, log = FALSE)
## pnorm(q, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)
## qnorm(p, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)
## rnorm(n, mean = 0, sd = 1)
## ```

get_rd

Overview

The get_rd function actually extracts the .Rd file from the file or directly from the package. It can be used on its own, but also rd2markdown function u ses it internally. The function itself is using the base function tools::parse_Rd and base::help to extract the documentation while escaping errors with graceful exceptions handling. The function is passing file and macros parameters directly to tools::parse_Rd with one small addition to how macros work. If it is NA, then the get_rd will try to locate macros directory in the same directory the file is and take the first .Rd file in alphabetical order, as tools::parse_Rd accepts only a single file as a macro.

Examples

Extracting documentation directly from the .Rd file and file parameter

rd2markdown::get_rd(file = rd_examples[[1]])
## % Generated by roxygen2: do not edit by hand
## % Please edit documentation in R/rd_sampler.R
## \name{rd_sampler}
## \alias{rd_sampler}
## \title{Rd sampler title}
## \usage{
## rd_sampler(x, y = TRUE, ...)
## }
## \arguments{
## \item{x}{Rd sampler param}
## 
## \item{y}{Rd sampler param with default}
## 
## \item{...}{Rd sampler ellipsis param}
## }
## \value{
## Rd sampler return
## }
## \description{
## Rd sampler description with \href{www.example.com}{Rd sampler link}, \verb{Rd sampler in-line code}. And Rd dynamic content, \emph{italics text},
## \emph{emphasis text}.
## }
## \details{
## Rd sampler details
## 
## Rd sampler enumerated list
## \enumerate{
## \item One
## \item Two
## \item Three
## }
## 
## Rd sampler itemized list
## \itemize{
## \item One
## \item Two
## \item Three
## }\tabular{lll}{
##    Rd \tab Sampler \tab Table \cr
##    rd \tab sampler \tab table \cr
## }
## 
## 
## \eqn{Rd + sampler + inline + equation}
## 
## \deqn{Rd * sampler * block * equation}
## }
## \note{
## Rd sampler note
## }
## \section{Rd sampler subsection}{
## Rd sampler subsection text
## \subsection{Rd sampler sub-subsection}{
## 
## Rd sampler sub-subsection text
## }
## }
## 
## \examples{
## rd_sampler()
## 
## }
## \references{
## R.D. Sampler. (2021)
## }
## \seealso{
## base::print
## }
## \author{
## R.D. Sampler.
## }
## \concept{rd_samplers}

reaching out to the installed package to fetch documentation using topic and package parameters while keeping file as NULL

rd2markdown::get_rd(topic = "rnorm", package = "stats")
## \title{The Normal Distribution}\name{Normal}\alias{Normal}\alias{dnorm}\alias{pnorm}\alias{qnorm}\alias{rnorm}\concept{error function}\concept{erf}\concept{erfc}\concept{erfinv}\concept{erfcinv}\keyword{distribution}\description{
##   Density, distribution function, quantile function and random
##   generation for the normal distribution with mean equal to \code{mean}
##   and standard deviation equal to \code{sd}.
## }\usage{
## dnorm(x, mean = 0, sd = 1, log = FALSE)
## pnorm(q, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)
## qnorm(p, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)
## rnorm(n, mean = 0, sd = 1)
## }\arguments{
##   \item{x, q}{vector of quantiles.}
##   \item{p}{vector of probabilities.}
##   \item{n}{number of observations. If \code{length(n) > 1}, the length
##     is taken to be the number required.}
##   \item{mean}{vector of means.}
##   \item{sd}{vector of standard deviations.}
##   \item{log, log.p}{logical; if TRUE, probabilities p are given as log(p).}
##   \item{lower.tail}{logical; if TRUE (default), probabilities are
##     \eqn{P[X \le x]} otherwise, \eqn{P[X > x]}.}
## }\details{
##   If \code{mean} or \code{sd} are not specified they assume the default
##   values of \code{0} and \code{1}, respectively.
## 
##   The normal distribution has density
##   \deqn{
##     f(x) =
##     \frac{1}{\sqrt{2\pi}\sigma} e^{-(x-\mu)^2/2\sigma^2}}{
##     f(x) = 1/(\sqrt(2 \pi) \sigma) e^-((x - \mu)^2/(2 \sigma^2))
##   }
##   where \eqn{\mu} is the mean of the distribution and
##   \eqn{\sigma} the standard deviation.
## }\value{
##   \code{dnorm} gives the density,
##   \code{pnorm} gives the distribution function,
##   \code{qnorm} gives the quantile function, and
##   \code{rnorm} generates random deviates.
## 
##   The length of the result is determined by \code{n} for
##   \code{rnorm}, and is the maximum of the lengths of the
##   numerical arguments for the other functions.
## 
##   The numerical arguments other than \code{n} are recycled to the
##   length of the result.  Only the first elements of the logical
##   arguments are used.
## 
##   For \code{sd = 0} this gives the limit as \code{sd} decreases to 0, a
##   point mass at \code{mu}.
##   \code{sd < 0} is an error and returns \code{NaN}.
## }\source{
##   For \code{pnorm}, based on
## 
##   Cody, W. D. (1993)
##   Algorithm 715: SPECFUN -- A portable FORTRAN package of special
##   function routines and test drivers.
##   \emph{ACM Transactions on Mathematical Software} \bold{19}, 22--32.
## 
##   For \code{qnorm}, the code is based on a C translation of
## 
##   Wichura, M. J. (1988)
##   Algorithm AS 241: The percentage points of the normal distribution.
##   \emph{Applied Statistics}, \bold{37}, 477--484; \ifelse{text}{doi:10.2307/2347330 <https://doi.org/10.2307/2347330>}{\ifelse{latex}{\href{https://doi.org/10.2307/2347330}{doi:10.2307\out{\slash{}}2347330}}{\href{https://doi.org/10.2307/2347330}{doi:10.2307/2347330}}}.
## 
##   which provides precise results up to about 16 digits for
##   \code{log.p=FALSE}.  For log scale probabilities in the extreme tails,
##   since \R version 4.1.0, extensively since 4.3.0, asymptotic expansions
##   are used which have been derived and explored in
## 
##   Maechler, M. (2022)
##   Asymptotic tail formulas for gaussian quantiles; \href{https://CRAN.R-project.org/package=DPQ}{\pkg{DPQ}} vignette
##   \url{https://CRAN.R-project.org/package=DPQ/vignettes/qnorm-asymp.pdf}.
## 
##   For \code{rnorm}, see \link{RNG} for how to select the algorithm and
##   for references to the supplied methods.
## }\references{
##   Becker, R. A., Chambers, J. M. and Wilks, A. R. (1988)
##   \emph{The New S Language}.
##   Wadsworth & Brooks/Cole.
## 
##   Johnson, N. L., Kotz, S. and Balakrishnan, N. (1995)
##   \emph{Continuous Univariate Distributions}, volume 1, chapter 13.
##   Wiley, New York.
## }\seealso{
##   \link{Distributions} for other standard distributions, including
##   \code{\link{dlnorm}} for the \emph{Log}normal distribution.
## }\examples{
## require(graphics)
## 
## dnorm(0) == 1/sqrt(2*pi)
## dnorm(1) == exp(-1/2)/sqrt(2*pi)
## dnorm(1) == 1/sqrt(2*pi*exp(1))
## 
## ## Using "log = TRUE" for an extended range :
## par(mfrow = c(2,1))
## plot(function(x) dnorm(x, log = TRUE), -60, 50,
##      main = "log { Normal density }")
## curve(log(dnorm(x)), add = TRUE, col = "red", lwd = 2)
## mtext("dnorm(x, log=TRUE)", adj = 0)
## mtext("log(dnorm(x))", col = "red", adj = 1)
## 
## plot(function(x) pnorm(x, log.p = TRUE), -50, 10,
##      main = "log { Normal Cumulative }")
## curve(log(pnorm(x)), add = TRUE, col = "red", lwd = 2)
## mtext("pnorm(x, log=TRUE)", adj = 0)
## mtext("log(pnorm(x))", col = "red", adj = 1)
## 
## ## if you want the so-called 'error function'
## erf <- function(x) 2 * pnorm(x * sqrt(2)) - 1
## ## (see Abramowitz and Stegun 29.2.29)
## ## and the so-called 'complementary error function'
## erfc <- function(x) 2 * pnorm(x * sqrt(2), lower = FALSE)
## ## and the inverses
## erfinv <- function (x) qnorm((1 + x)/2)/sqrt(2)
## erfcinv <- function (x) qnorm(x/2, lower = FALSE)/sqrt(2)
## }

using macros parameter to pass a custom macro that is used while extracting the documentation

rd2markdown::get_rd(
  file = rd_examples[[2]],
  macros = rd_examples_macro
)
## % Generated by roxygen2: do not edit by hand
## % Please edit documentation in R/rd_data_sampler.R
## \name{rd_data_sampler}
## \alias{rd_data_sampler}
## \title{Rd data sampler}
## \format{
## A data.frame with 3 rows and 2 variables:
## \describe{
## \item{x}{Numeric values}
## \item{y}{Character values}
## }
## }
## \source{
## <r.d.sampler/>
## }
## \usage{
## rd_data_sampler
## }
## \description{
## An example of dataset documentation and linking to others \code{\link[=rnorm]{rnorm()}}
## }
## \examples{
## rd_data_sampler
## 
## }
## \keyword{datasets}

or macros to try to automatically discover macros

rd2markdown::get_rd(
  file = rd_examples[[2]],
  macros = NA
)
## % Generated by roxygen2: do not edit by hand
## % Please edit documentation in R/rd_data_sampler.R
## \name{rd_data_sampler}
## \alias{rd_data_sampler}
## \title{Rd data sampler}
## \format{
## A data.frame with 3 rows and 2 variables:
## \describe{
## \item{x}{Numeric values}
## \item{y}{Character values}
## }
## }
## \source{
## <r.d.sampler/>
## }
## \usage{
## rd_data_sampler
## }
## \description{
## An example of dataset documentation and linking to others \function{rnorm}
## }
## \examples{
## rd_data_sampler
## 
## }
## \keyword{datasets}

documentation_to_markdown

Overview

The documentation_to_markdown function merges both and rd2markdown and get_rd, providing a vectorized way of parsing multiple documentation files at once. Simply pass a vector of paths and the function will return a named list of markdown documents created with rd2markdown function.

Examples

It is enough to pass the vector of file paths to get a list of parsed markdown files

rd2markdown::documentation_to_markdown(rd_examples)
## $rd_file_sample.Rd
## [1] "# Rd sampler title\n\n```r\nrd_sampler(x, y = TRUE, ...)\n```\n\n## Description\n\nRd sampler description with [Rd sampler link](www.example.com), `Rd sampler in-line code`. And Rd dynamic content, **italics text**, **emphasis text**.\n\n## Details\n\nRd sampler details\n\nRd sampler enumerated list\n\n1. One\n2. Two\n3. Three\n\nRd sampler itemized list\n\n * One\n * Two\n * Three\n\n||||\n|:--|:--|:--|\n|Rd|Sampler|Table|\n|rd|sampler|table|\n\n`Rd + sampler + inline + equation`\n\n`Rd * sampler * block * equation`"
## 
## $rd_file_sample_2.Rd
## [1] "# Rd data sampler\n\n```r\nrd_data_sampler\n```\n\n## Description\n\nAn example of dataset documentation and linking to others `rnorm()`"

The documentation_to_markdown function also allows extracting only particular parts of the documentation, using fragments parameter. If a given documentation file does not have a specific section, it will become an empty string.

rd2markdown::documentation_to_markdown(rd_examples, fragments = "details")
## $rd_file_sample.Rd
## [1] "## Details\n\nRd sampler details\n\nRd sampler enumerated list\n\n1. One\n2. Two\n3. Three\n\nRd sampler itemized list\n\n * One\n * Two\n * Three\n\n||||\n|:--|:--|:--|\n|Rd|Sampler|Table|\n|rd|sampler|table|\n\n`Rd + sampler + inline + equation`\n\n`Rd * sampler * block * equation`"
## 
## $rd_file_sample_2.Rd
## [1] ""

Summary

The rd2markdown package is an attempt to solve the issue of converting R package documentation objects into readable markdown documents. It is still in early development, so not every single aspect or nuance is covered. Therefore, we would like to welcome community contribution by reporting gaps by opening issues on https://github.com/genentech/rd2markdown and describing the problem or missing functionality. We value any type of input as we aim to provide a tool that will be possible to use in various R applications.