roxygen2/0000755000176200001440000000000014116067732012036 5ustar liggesusersroxygen2/NAMESPACE0000644000176200001440000002145614115762720013263 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method(block_to_rd,default) S3method(block_to_rd,roxy_block) S3method(block_to_rd,roxy_block_r6class) S3method(c,rd) S3method(default_export,"NULL") S3method(default_export,default) S3method(default_export,rcclass) S3method(default_export,s3method) S3method(default_export,s4class) S3method(default_export,s4generic) S3method(default_export,s4method) S3method(format,object) S3method(format,rd_section) S3method(format,rd_section_alias) S3method(format,rd_section_author) S3method(format,rd_section_backref) S3method(format,rd_section_concept) S3method(format,rd_section_description) S3method(format,rd_section_details) S3method(format,rd_section_docType) S3method(format,rd_section_encoding) S3method(format,rd_section_examples) S3method(format,rd_section_family) S3method(format,rd_section_field) S3method(format,rd_section_formals) S3method(format,rd_section_format) S3method(format,rd_section_inherit) S3method(format,rd_section_inherit_dot_params) S3method(format,rd_section_inherit_section) S3method(format,rd_section_keyword) S3method(format,rd_section_minidesc) S3method(format,rd_section_name) S3method(format,rd_section_note) S3method(format,rd_section_param) S3method(format,rd_section_rawRd) S3method(format,rd_section_rcmethods) S3method(format,rd_section_reexport) S3method(format,rd_section_references) S3method(format,rd_section_section) S3method(format,rd_section_seealso) S3method(format,rd_section_slot) S3method(format,rd_section_source) S3method(format,rd_section_title) S3method(format,rd_section_usage) S3method(format,rd_section_value) S3method(format,roxy_tag) S3method(merge,rd_section) S3method(merge,rd_section_inherit) S3method(merge,rd_section_inherit_dot_params) S3method(merge,rd_section_inherit_section) S3method(merge,rd_section_minidesc) S3method(merge,rd_section_param) S3method(merge,rd_section_reexport) S3method(merge,rd_section_section) S3method(object_defaults,"function") S3method(object_defaults,data) S3method(object_defaults,default) S3method(object_defaults,import) S3method(object_defaults,package) S3method(object_defaults,r6class) S3method(object_defaults,rcclass) S3method(object_defaults,s3generic) S3method(object_defaults,s3method) S3method(object_defaults,s4class) S3method(object_defaults,s4generic) S3method(object_defaults,s4method) S3method(object_format,default) S3method(print,object) S3method(print,rd) S3method(print,rd_section) S3method(print,roxy_block) S3method(print,roxy_tag) S3method(roclet_clean,roclet_namespace) S3method(roclet_clean,roclet_rd) S3method(roclet_output,roclet_namespace) S3method(roclet_output,roclet_rd) S3method(roclet_output,roclet_vignette) S3method(roclet_preprocess,default) S3method(roclet_preprocess,roclet_namespace) S3method(roclet_process,roclet_namespace) S3method(roclet_process,roclet_rd) S3method(roclet_process,roclet_vignette) S3method(roxy_tag_ns,default) S3method(roxy_tag_ns,roxy_tag_evalNamespace) S3method(roxy_tag_ns,roxy_tag_export) S3method(roxy_tag_ns,roxy_tag_exportClass) S3method(roxy_tag_ns,roxy_tag_exportMethod) S3method(roxy_tag_ns,roxy_tag_exportPattern) S3method(roxy_tag_ns,roxy_tag_exportS3Method) S3method(roxy_tag_ns,roxy_tag_import) S3method(roxy_tag_ns,roxy_tag_importClassesFrom) S3method(roxy_tag_ns,roxy_tag_importFrom) S3method(roxy_tag_ns,roxy_tag_importMethodsFrom) S3method(roxy_tag_ns,roxy_tag_rawNamespace) S3method(roxy_tag_ns,roxy_tag_useDynLib) S3method(roxy_tag_parse,default) S3method(roxy_tag_parse,roxy_tag_aliases) S3method(roxy_tag_parse,roxy_tag_author) S3method(roxy_tag_parse,roxy_tag_backref) S3method(roxy_tag_parse,roxy_tag_concept) S3method(roxy_tag_parse,roxy_tag_describeIn) S3method(roxy_tag_parse,roxy_tag_description) S3method(roxy_tag_parse,roxy_tag_details) S3method(roxy_tag_parse,roxy_tag_docType) S3method(roxy_tag_parse,roxy_tag_encoding) S3method(roxy_tag_parse,roxy_tag_eval) S3method(roxy_tag_parse,roxy_tag_evalNamespace) S3method(roxy_tag_parse,roxy_tag_evalRd) S3method(roxy_tag_parse,roxy_tag_example) S3method(roxy_tag_parse,roxy_tag_examples) S3method(roxy_tag_parse,roxy_tag_examplesIf) S3method(roxy_tag_parse,roxy_tag_export) S3method(roxy_tag_parse,roxy_tag_exportClass) S3method(roxy_tag_parse,roxy_tag_exportMethod) S3method(roxy_tag_parse,roxy_tag_exportPattern) S3method(roxy_tag_parse,roxy_tag_exportS3Method) S3method(roxy_tag_parse,roxy_tag_family) S3method(roxy_tag_parse,roxy_tag_field) S3method(roxy_tag_parse,roxy_tag_format) S3method(roxy_tag_parse,roxy_tag_import) S3method(roxy_tag_parse,roxy_tag_importClassesFrom) S3method(roxy_tag_parse,roxy_tag_importFrom) S3method(roxy_tag_parse,roxy_tag_importMethodsFrom) S3method(roxy_tag_parse,roxy_tag_include) S3method(roxy_tag_parse,roxy_tag_includeRmd) S3method(roxy_tag_parse,roxy_tag_inherit) S3method(roxy_tag_parse,roxy_tag_inheritDotParams) S3method(roxy_tag_parse,roxy_tag_inheritParams) S3method(roxy_tag_parse,roxy_tag_inheritSection) S3method(roxy_tag_parse,roxy_tag_keywords) S3method(roxy_tag_parse,roxy_tag_md) S3method(roxy_tag_parse,roxy_tag_method) S3method(roxy_tag_parse,roxy_tag_name) S3method(roxy_tag_parse,roxy_tag_noMd) S3method(roxy_tag_parse,roxy_tag_noRd) S3method(roxy_tag_parse,roxy_tag_note) S3method(roxy_tag_parse,roxy_tag_order) S3method(roxy_tag_parse,roxy_tag_param) S3method(roxy_tag_parse,roxy_tag_rawNamespace) S3method(roxy_tag_parse,roxy_tag_rawRd) S3method(roxy_tag_parse,roxy_tag_rdname) S3method(roxy_tag_parse,roxy_tag_references) S3method(roxy_tag_parse,roxy_tag_return) S3method(roxy_tag_parse,roxy_tag_returns) S3method(roxy_tag_parse,roxy_tag_section) S3method(roxy_tag_parse,roxy_tag_seealso) S3method(roxy_tag_parse,roxy_tag_slot) S3method(roxy_tag_parse,roxy_tag_source) S3method(roxy_tag_parse,roxy_tag_template) S3method(roxy_tag_parse,roxy_tag_templateVar) S3method(roxy_tag_parse,roxy_tag_title) S3method(roxy_tag_parse,roxy_tag_usage) S3method(roxy_tag_parse,roxy_tag_useDynLib) S3method(roxy_tag_rd,roxy_tag_.formals) S3method(roxy_tag_rd,roxy_tag_.methods) S3method(roxy_tag_rd,roxy_tag_.reexport) S3method(roxy_tag_rd,roxy_tag_author) S3method(roxy_tag_rd,roxy_tag_backref) S3method(roxy_tag_rd,roxy_tag_concept) S3method(roxy_tag_rd,roxy_tag_description) S3method(roxy_tag_rd,roxy_tag_details) S3method(roxy_tag_rd,roxy_tag_docType) S3method(roxy_tag_rd,roxy_tag_encoding) S3method(roxy_tag_rd,roxy_tag_evalRd) S3method(roxy_tag_rd,roxy_tag_example) S3method(roxy_tag_rd,roxy_tag_examples) S3method(roxy_tag_rd,roxy_tag_examplesIf) S3method(roxy_tag_rd,roxy_tag_family) S3method(roxy_tag_rd,roxy_tag_field) S3method(roxy_tag_rd,roxy_tag_format) S3method(roxy_tag_rd,roxy_tag_includeRmd) S3method(roxy_tag_rd,roxy_tag_inherit) S3method(roxy_tag_rd,roxy_tag_inheritDotParams) S3method(roxy_tag_rd,roxy_tag_inheritParams) S3method(roxy_tag_rd,roxy_tag_inheritSection) S3method(roxy_tag_rd,roxy_tag_keywords) S3method(roxy_tag_rd,roxy_tag_note) S3method(roxy_tag_rd,roxy_tag_param) S3method(roxy_tag_rd,roxy_tag_rawRd) S3method(roxy_tag_rd,roxy_tag_references) S3method(roxy_tag_rd,roxy_tag_return) S3method(roxy_tag_rd,roxy_tag_returns) S3method(roxy_tag_rd,roxy_tag_section) S3method(roxy_tag_rd,roxy_tag_seealso) S3method(roxy_tag_rd,roxy_tag_slot) S3method(roxy_tag_rd,roxy_tag_source) S3method(roxy_tag_rd,roxy_tag_title) S3method(roxy_tag_rd,roxy_tag_usage) export(block_get_tag) export(block_get_tag_value) export(block_get_tags) export(block_has_tags) export(env_file) export(env_package) export(is_s3_generic) export(is_s3_method) export(load_installed) export(load_options) export(load_pkgload) export(load_source) export(namespace_roclet) export(object) export(object_format) export(parse_file) export(parse_package) export(parse_text) export(rd_roclet) export(rd_section) export(roc_proc_text) export(roclet) export(roclet_clean) export(roclet_find) export(roclet_output) export(roclet_preprocess) export(roclet_process) export(roclet_tags) export(roxy_block) export(roxy_meta_get) export(roxy_tag) export(roxy_tag_parse) export(roxy_tag_rd) export(roxy_tag_warning) export(roxygenise) export(roxygenize) export(tag_code) export(tag_examples) export(tag_inherit) export(tag_markdown) export(tag_markdown_with_sections) export(tag_name) export(tag_name_description) export(tag_toggle) export(tag_two_part) export(tag_value) export(tag_words) export(tag_words_line) export(update_collate) export(vignette_roclet) import(rlang) import(stringr) importFrom(R6,R6Class) importFrom(knitr,knit) importFrom(knitr,opts_chunk) importFrom(purrr,keep) importFrom(purrr,map) importFrom(purrr,map2) importFrom(purrr,map_chr) importFrom(purrr,map_int) importFrom(purrr,map_lgl) importFrom(stats,setNames) importFrom(utils,URLdecode) importFrom(utils,URLencode) importFrom(utils,head) importFrom(utils,tail) importFrom(xml2,xml_attr) importFrom(xml2,xml_children) importFrom(xml2,xml_contents) importFrom(xml2,xml_find_all) importFrom(xml2,xml_name) importFrom(xml2,xml_ns_strip) importFrom(xml2,xml_text) importFrom(xml2,xml_type) useDynLib(roxygen2, .registration=TRUE) roxygen2/LICENSE0000644000176200001440000000005614036301727013040 0ustar liggesusersYEAR: 2020 COPYRIGHT HOLDER: roxygen2 authors roxygen2/README.md0000644000176200001440000000476314036314212013314 0ustar liggesusers# roxygen2 [![CRAN status](https://www.r-pkg.org/badges/version/roxygen2)](https://CRAN.R-project.org/package=roxygen2) [![R-CMD-check](https://github.com/r-lib/roxygen2/workflows/R-CMD-check/badge.svg)](https://github.com/r-lib/roxygen2/actions) [![Codecov test coverage](https://codecov.io/gh/r-lib/roxygen2/branch/master/graph/badge.svg)](https://codecov.io/gh/r-lib/roxygen2?branch=master) The premise of roxygen2 is simple: describe your functions in comments next to their definitions and roxygen2 will process your source code and comments to automatically generate `.Rd` files in `man/`, `NAMESPACE`, and, if needed, the `Collate` field in `DESCRIPTION`. ## Installation ```R # Install devtools from CRAN install.packages("roxygen2") # Or the development version from GitHub: # install.packages("devtools") devtools::install_github("r-lib/roxygen2") ``` ## Usage The premise of roxygen2 is simple: describe your functions in comments next to their definitions and roxygen2 will process your source code and comments to produce Rd files in the `man/` directory. Here's a [simple example](https://stringr.tidyverse.org/reference/str_length.html) from the stringr package: ```R #' The length of a string #' #' Technically this returns the number of "code points", in a string. One #' code point usually corresponds to one character, but not always. For example, #' an u with a umlaut might be represented as a single character or as the #' combination a u and an umlaut. #' #' @inheritParams str_detect #' @return A numeric vector giving number of characters (code points) in each #' element of the character vector. Missing string have missing length. #' @seealso [stringi::stri_length()] which this function wraps. #' @export #' @examples #' str_length(letters) #' str_length(NA) #' str_length(factor("abc")) #' str_length(c("i", "like", "programming", NA)) str_length <- function(string) { } ``` When you `roxygenise()` (or `devtools::document()`) your package these comments will be automatically transformed to the `.Rd` that R uses to generate the documentation you see when you type `?str_length`. ## Learn more To get started, first read `vignette("roxygen2")`. Then read more about the specific package component that you want to generate: * For `.Rd` documentation files, read `vignette("rd")`. * For the `NAMESPACE`, read `vignette("namespace")`. * For the `Collate` field in the `DESCRIPTION`, read `update_collate()`. roxygen2/man/0000755000176200001440000000000014047223751012607 5ustar liggesusersroxygen2/man/load_options.Rd0000644000176200001440000000334313675431642015601 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/options.R \name{load_options} \alias{load_options} \alias{roxy_meta_get} \title{Load roxygen2 options} \usage{ load_options(base_path = ".") roxy_meta_get(key = NULL, default = NULL) } \arguments{ \item{base_path}{Path to package.} } \description{ Options can be stored in the \code{Roxygen} field of the \code{DESCRIPTION}, or in \code{man/roxygen/meta.R}. In either case, the code is parsed and evaluated in a child of the base environment. Call \code{roxy_meta_get()} to access current option values from within tag and roclet methods. Options in \code{man/roxygen/meta.R} override those present in \code{DESCRIPTION}. } \section{Possible options}{ \itemize{ \item \code{roclets} \verb{}: giving names of roclets to run. See \code{\link[=roclet_find]{roclet_find()}} for details. \item \code{packages} \verb{}: packages to load that implement new tags. \item \code{load} \verb{}: how to load R code. See \link{load} for details. \item \code{old_usage} \verb{}: use old style usage formatting? \item \code{markdown} \verb{}: translate markdown syntax to Rd? \item \code{r6} \verb{}: document R6 classes? \item \code{current_package} \verb{} (read only): name of package being documented. \item \code{rd_family_title} \verb{}: overrides for \verb{@family} titles. See the \emph{rd} vignette for details: \code{vignette("rd", package = "roxygen2")} } } \section{How to set}{ Either set in \code{DESCRIPTION}:\preformatted{Roxygen: list(markdown = TRUE, load = "installed") } Or if longer, you can put in \verb{/man/roxygen/meta.R}:\preformatted{list( markdown = TRUE, load = "installed" ) } } \keyword{internal} roxygen2/man/load.Rd0000644000176200001440000000303514047223751014016 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/load.R \name{load} \alias{load} \alias{load_pkgload} \alias{load_installed} \alias{load_source} \title{Load package code} \usage{ load_pkgload(path) load_installed(path) load_source(path) } \arguments{ \item{path}{Path to source package} } \description{ roxygen2 is a dynamic documentation system, which means it works with the objects inside your package, not just the source code used to create them. These functions offer various ways of loading your package to suit various constraints: \itemize{ \item \code{load_pkgload()} uses \code{pkgload::load_all()} to simulate package loading as closely as we know how. It offers high fidelity handling of code that uses S4, but requires that the package be compiled. \item \code{load_source()} simulates package loading by attaching packages listed in \code{Depends} and \code{Imports}, then sources all files in the \verb{R/} directory. This was the default strategy used in roxygen2 6.0.0 and earlier; it's primary advantage is that it does not need compilation. \item \code{load_installed()} uses the installed version of the package. Use this strategy if you have installed a development version of the package already. This is the highest fidelity strategy, but requires work outside of roxygen2. } You can change the default strategy for your function with roxygen2 \code{load} option. Override the default off \code{pkgload} to use the \code{source} or \code{installed} strategies:\preformatted{Roxygen: list(load = "source") } } roxygen2/man/tag_parsers.Rd0000644000176200001440000000274013545643447015425 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tag-parser.R \name{tag_parsers} \alias{tag_parsers} \alias{tag_value} \alias{tag_inherit} \alias{tag_name} \alias{tag_two_part} \alias{tag_name_description} \alias{tag_words} \alias{tag_words_line} \alias{tag_toggle} \alias{tag_code} \alias{tag_examples} \alias{tag_markdown} \alias{tag_markdown_with_sections} \title{Parse tags} \usage{ tag_value(x) tag_inherit(x) tag_name(x) tag_two_part(x, first, second, required = TRUE, markdown = TRUE) tag_name_description(x) tag_words(x, min = 0, max = Inf) tag_words_line(x) tag_toggle(x) tag_code(x) tag_examples(x) tag_markdown(x) tag_markdown_with_sections(x) } \arguments{ \item{x}{A \link{roxy_tag} object to parse} \item{first, second}{Name of first and second parts of two part tags} \item{required}{Is the second part required (TRUE) or can it be blank (FALSE)?} \item{markdown}{Should the second part be parsed as markdown?} \item{min, max}{Minimum and maximum number of words} } \value{ A \link{roxy_tag} object with the \code{val} field set to the parsed value. } \description{ These functions parse the \code{raw} tag value, convert a string into a richer R object and storing it in \code{val}, or provide an informative warning and returning \code{NULL}. } \section{New tag}{ To create a new \verb{@mytag} define \code{roxy_tag_parse.roxy_tag_mytag()}. It should either call one of the functions here, or directly set \code{x$val}. } \keyword{internal} roxygen2/man/RoxyTopic.Rd0000644000176200001440000001752613631761325015053 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/topic.R \name{RoxyTopic} \alias{RoxyTopic} \title{A \code{RoxyTopic} is an ordered collection of unique rd_sections} \description{ A \code{RoxyTopic} object corresponds to a generated \code{.Rd} file. } \keyword{internal} \section{Public fields}{ \if{html}{\out{
}} \describe{ \item{\code{sections}}{Named list of sections. Each item must be an \code{\link[=rd_section]{rd_section()}} object.} \item{\code{filename}}{Path to the \code{.Rd} file to generate.} } \if{html}{\out{
}} } \section{Methods}{ \subsection{Public methods}{ \itemize{ \item \href{#method-format}{\code{RoxyTopic$format()}} \item \href{#method-is_valid}{\code{RoxyTopic$is_valid()}} \item \href{#method-has_section}{\code{RoxyTopic$has_section()}} \item \href{#method-get_section}{\code{RoxyTopic$get_section()}} \item \href{#method-get_value}{\code{RoxyTopic$get_value()}} \item \href{#method-get_rd}{\code{RoxyTopic$get_rd()}} \item \href{#method-get_name}{\code{RoxyTopic$get_name()}} \item \href{#method-inherits_from}{\code{RoxyTopic$inherits_from()}} \item \href{#method-inherits_section_from}{\code{RoxyTopic$inherits_section_from()}} \item \href{#method-add}{\code{RoxyTopic$add()}} \item \href{#method-add_section}{\code{RoxyTopic$add_section()}} \item \href{#method-clone}{\code{RoxyTopic$clone()}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-format}{}}} \subsection{Method \code{format()}}{ Format the \code{.Rd} file. It considers the sections in particular order, even though Rd tools will reorder them again. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{RoxyTopic$format(...)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{...}}{Passed to the \code{format()} methods of the \code{\link[=rd_section]{rd_section()}} objects, the sections.} } \if{html}{\out{
}} } \subsection{Returns}{ Character string. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-is_valid}{}}} \subsection{Method \code{is_valid()}}{ Check if an \code{.Rd} file is valid \subsection{Usage}{ \if{html}{\out{
}}\preformatted{RoxyTopic$is_valid()}\if{html}{\out{
}} } \subsection{Returns}{ Logical flag, \code{TRUE} for valid \code{.Rd} files } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-has_section}{}}} \subsection{Method \code{has_section()}}{ Check if an \code{.Rd} file has a certain section. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{RoxyTopic$has_section(type)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{type}}{Section type, a character scalar.} } \if{html}{\out{
}} } \subsection{Returns}{ Logical flag. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-get_section}{}}} \subsection{Method \code{get_section()}}{ Query a section. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{RoxyTopic$get_section(type)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{type}}{Section type, a character scalar.} } \if{html}{\out{
}} } \subsection{Returns}{ The \link{rd_section} object representing the section, or \code{NULL} if the topic has no such section. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-get_value}{}}} \subsection{Method \code{get_value()}}{ Query the value of a section. This is the value of the \link{rd_section} object. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{RoxyTopic$get_value(type)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{type}}{Section type, a character scalar.} } \if{html}{\out{
}} } \subsection{Returns}{ Value. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-get_rd}{}}} \subsection{Method \code{get_rd()}}{ Get the Rd code of a section. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{RoxyTopic$get_rd(type)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{type}}{Section type, a character scalar.} } \if{html}{\out{
}} } \subsection{Returns}{ Character vector, one element per line. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-get_name}{}}} \subsection{Method \code{get_name()}}{ Get the value of the \code{name} section. This is the name of the Rd topic. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{RoxyTopic$get_name()}\if{html}{\out{
}} } \subsection{Returns}{ Character scalar. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-inherits_from}{}}} \subsection{Method \code{inherits_from()}}{ Query the topics this topic inherits \code{type} from. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{RoxyTopic$inherits_from(type)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{type}}{Section type, a character scalar.} } \if{html}{\out{
}} } \subsection{Returns}{ A character vector of topic names. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-inherits_section_from}{}}} \subsection{Method \code{inherits_section_from()}}{ Query the topics this topic inherits sections from. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{RoxyTopic$inherits_section_from()}\if{html}{\out{
}} } \subsection{Returns}{ A character vector of topic names. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-add}{}}} \subsection{Method \code{add()}}{ Add one or more sections to the topic. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{RoxyTopic$add(x, overwrite = FALSE)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{x}}{Section(s) to add. It may be another \code{RoxyTopic} object, all of its sections will be added; or an \link{rd_section} object; or a list of \link{rd_section} objects to add.} \item{\code{overwrite}}{Whether to overwrite an existing section. If \code{FALSE} then the two sections will be merged.} } \if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-add_section}{}}} \subsection{Method \code{add_section()}}{ Add a section. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{RoxyTopic$add_section(section, overwrite = FALSE)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{section}}{\link{rd_section} object to add.} \item{\code{overwrite}}{Whether to overwrite an existing section. If \code{FALSE} then the two sections will be merged.} } \if{html}{\out{
}} } \subsection{Details}{ Ensures that each type of name (as given by its name), only appears once in \code{self$sections}. This method if for internal use only. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{RoxyTopic$clone(deep = FALSE)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{deep}}{Whether to make a deep clone.} } \if{html}{\out{
}} } } } roxygen2/man/update_collate.Rd0000644000176200001440000000330513541216367016067 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/collate.R \name{update_collate} \alias{update_collate} \alias{@include} \title{Update Collate field in DESCRIPTION} \usage{ update_collate(base_path) } \arguments{ \item{base_path}{Path to package directory.} } \description{ By default, R loads files in alphabetical order. Unfortunately not every alphabet puts letters in the same order, so you can't rely on alphabetic ordering if you need one file loaded before another. (This usually doesn't matter but is important for S4, where you need to make sure that classes are loaded before subclasses and generics are defined before methods.). You can override the default alphabetical ordering with \verb{@include before.R}, which specify that \code{before.R} must be loaded before the current file. Generally, you will not need to run this function yourself; it should be run automatically by any package that needs to load your R files in collation order. } \section{Collate}{ This is not a roclet because roclets need the values of objects in a package, and those values can not be generated unless you've sourced the files, and you can't source the files unless you know the correct order. If there are no \verb{@include} tags, roxygen2 will leave collate as is. This makes it easier to use roxygen2 with an existing collate directive, but if you remove all your \verb{@include} tags, you'll need to also manually delete the collate field. } \examples{ #' If `example-a.R', `example-b.R' and `example-c.R' live in R/ #' and we're in `example-a.R`, then the following @include statement #' ensures that example-b and example-c are sourced before example-a. #' @include example-b.R example-c.R NULL } roxygen2/man/rd_roclet.Rd0000644000176200001440000000167214115762720015061 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/rd.R \name{rd_roclet} \alias{rd_roclet} \title{Roclet: make Rd files.} \usage{ rd_roclet() } \description{ This roclet is the workhorse of \code{roxygen}, producing the \code{.Rd} files that R uses to document that functions, datasets, packages, classes, and other objects. See \code{vignette("rd")} for details. Generally you will not call this function directly but will instead use roxygenise() specifying the rd roclet } \examples{ #' The length of a string (in characters) #' #' @param x String input character vector #' @return An integer vector the same length as `x`. #' `NA` strings have `NA` length. #' @seealso [nchar()] #' @export #' @examples #' str_length(letters) #' str_length(c("i", "like", "programming", NA)) str_length <- function(x) { } } \seealso{ Other roclets: \code{\link{namespace_roclet}()}, \code{\link{vignette_roclet}()} } \concept{roclets} roxygen2/man/namespace_roclet.Rd0000644000176200001440000000222013560327422016375 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/namespace.R \name{namespace_roclet} \alias{namespace_roclet} \title{Roclet: make \code{NAMESPACE}} \usage{ namespace_roclet() } \description{ This roclet automates the production of a \code{NAMESPACE} file, which controls the functions imported and exported by your package, as described in \href{https://cran.r-project.org/doc/manuals/r-release/R-exts.html}{Writing R extensions}. The \code{NAMESPACE} is generated in two passes: the first generates only import directives (because this can be computed without evaluating package code), and the second generates everything (after the package has been loaded). See \code{vignette("namespace")} for details. } \examples{ # The most common namespace tag is @export, which declares that a function # is part of the external interface of your package #' @export foofy <- function(x, y, z) { } # You'll also often find global imports living in a file called # R/{package}-package.R. #' @importFrom magrittr \%>\% #' @import rlang NULL } \seealso{ Other roclets: \code{\link{rd_roclet}()}, \code{\link{vignette_roclet}()} } \concept{roclets} roxygen2/man/roxy_block.Rd0000644000176200001440000000325613675431020015253 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/block.R \name{roxy_block} \alias{roxy_block} \alias{block_has_tags} \alias{block_get_tags} \alias{block_get_tag} \alias{block_get_tag_value} \title{Blocks} \usage{ roxy_block(tags, file, line, call, object = NULL) block_has_tags(block, tags) block_get_tags(block, tags) block_get_tag(block, tag) block_get_tag_value(block, tag) } \arguments{ \item{tags}{A list of \link{roxy_tag}s.} \item{file, line}{Location of the \code{call} (i.e. the line after the last line of the block).} \item{call}{Expression associated with block.} \item{object}{Optionally, the object associated with the block, found by inspecting/evaluating \code{call}.} \item{block}{A \code{roxy_block} to manipulate.} \item{tag, tags}{Either a single tag name, or a character vector of tag names.} } \description{ A \code{roxy_block} represents a single roxygen2 block. The \verb{block_*} functions provide a few helpers for common operations: \itemize{ \item \code{block_has_tag(blocks, tags)}: does \code{block} contain any of these \code{tags}? \item \code{block_get_tags(block, tags)}: get all instances of \code{tags} \item \code{block_get_tag(block, tag)}: get single tag. Returns \code{NULL} if 0, throws warning if more than 1. \item \code{block_get_tag_value(block, tag)}: gets \code{val} field from single tag. } } \examples{ # The easiest way to see the structure of a roxy_block is to create one # using parse_text: text <- " #' This is a title #' #' @param x,y A number #' @export f <- function(x, y) x + y " # parse_text() returns a list of blocks, so I extract the first block <- parse_text(text)[[1]] block } \keyword{internal} roxygen2/man/roxygenize.Rd0000644000176200001440000000323713545643447015320 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/roxygenize.R \name{roxygenize} \alias{roxygenize} \alias{roxygenise} \title{Process a package with the Rd, namespace and collate roclets.} \usage{ roxygenize(package.dir = ".", roclets = NULL, load_code = NULL, clean = FALSE) roxygenise(package.dir = ".", roclets = NULL, load_code = NULL, clean = FALSE) } \arguments{ \item{package.dir}{Location of package top level directory. Default is working directory.} \item{roclets}{Character vector of roclet names to use with package. The default, \code{NULL}, uses the roxygen \code{roclets} option, which defaults to \code{c("collate", "namespace", "rd")}.} \item{load_code}{A function used to load all the R code in the package directory. The default, \code{NULL}, uses the strategy defined by the \code{load} roxygen option, which defaults to \code{\link[=load_pkgload]{load_pkgload()}}. See \link{load} for more details.} \item{clean}{If \code{TRUE}, roxygen will delete all files previously created by roxygen before running each roclet.} } \value{ \code{NULL} } \description{ This is the workhorse function that uses roclets, the built-in document transformation functions, to build all documentation for a package. See the documentation for the individual roclets, \code{\link[=rd_roclet]{rd_roclet()}}, \code{\link[=namespace_roclet]{namespace_roclet()}}, and for \code{\link[=update_collate]{update_collate()}}, for more details. } \details{ Note that roxygen2 is a dynamic documentation system: it works by inspecting loaded objects in the package. This means that you must be able to load the package in order to document it: see \link{load} for details. } roxygen2/man/roxygen2-package.Rd0000644000176200001440000000314713631764732016260 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/roxygen.R \docType{package} \name{roxygen2-package} \alias{roxygen2} \alias{roxygen2-package} \title{roxygen2: In-Line Documentation for R} \description{ \if{html}{\figure{logo.png}{options: align='right' alt='logo' width='120'}} Generate your Rd documentation, 'NAMESPACE' file, and collation field using specially formatted comments. Writing documentation in-line with code makes it easier to keep your documentation up-to-date as your requirements change. 'Roxygen2' is inspired by the 'Doxygen' system for C++. } \details{ See \code{vignette("roxygen2", package = "roxygen2")} for an overview of the package, \code{vignette("rd", package = "roxygen2")} for generating documentation, and \code{vignette("namespace", package = "roxygen2")} for generating the namespace specification. If you have existing Rd files, check out the \code{Rd2roxygen} package for a convenient way of converting Rd files to roxygen comments. } \seealso{ Useful links: \itemize{ \item \url{https://roxygen2.r-lib.org/} \item \url{https://github.com/r-lib/roxygen2} \item Report bugs at \url{https://github.com/r-lib/roxygen2/issues} } } \author{ \strong{Maintainer}: Hadley Wickham \email{hadley@rstudio.com} (\href{https://orcid.org/0000-0003-4757-117X}{ORCID}) [copyright holder] Authors: \itemize{ \item Peter Danenberg \email{pcd@roxygen.org} [copyright holder] \item Gábor Csárdi \email{csardi.gabor@gmail.com} \item Manuel Eugster [copyright holder] } Other contributors: \itemize{ \item RStudio [copyright holder] } } \keyword{internal} roxygen2/man/roxygen/0000755000176200001440000000000014115763565014312 5ustar liggesusersroxygen2/man/roxygen/templates/0000755000176200001440000000000013544733176016310 5ustar liggesusersroxygen2/man/roxygen/templates/rd.R0000644000176200001440000000033613540202201017012 0ustar liggesusers#' @description #' This roclet is the workhorse of `roxygen`, producing the `.Rd` files that #' R uses to document that functions, datasets, packages, classes, and #' other objects. #' #' See `vignette("rd")` for details. roxygen2/man/escape_examples.Rd0000644000176200001440000000213713567327052016244 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/rd-examples.R \name{escape_examples} \alias{escape_examples} \title{Escape examples} \usage{ escape_examples(x) } \description{ This documentation topic is used primarily for testing and to record our understanding of the \verb{\\example\{\}} escaping rules. See \url{https://developer.r-project.org/parseRd.pdf} for the details provided by R core. } \examples{ # In examples we automatically escape Rd comments (\%): 100 \%\% 30 # even if they are in strings "50\%" # and \\ and \v inside of strings and symbols "\\v" # vertical tab "\\\\" # but not comments: \l \v # other string escapes are left as is "\"" "\n" # Otherwise, backslashes and parentheses are left as is. This # means that you need to escape unbalanced parentheses, which typically only # occur in \dontshow{}: \dontshow{if (FALSE) \{ } print("Hello") \dontshow{ \} } # You also need to escape backslashes in infix operators and comments # (this is generally rare) `\%\\\\\%` <- function(x, y) x + y 10 \%\\\% 20 # \\\\ (renders as two backslashes) } \keyword{internal} roxygen2/man/roclet_find.Rd0000644000176200001440000000140013541216367015364 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/roclet.R \name{roclet_find} \alias{roclet_find} \title{Create a roclet from a string.} \usage{ roclet_find(x) } \arguments{ \item{x}{Arbitrary R code evaluated in roxygen2 package.} } \description{ This provides a flexible way of specifying a roclet in a string. } \examples{ # rd, namespace, and vignette work for backward compatibility roclet_find("rd") # But generally you should specify the name of a function that # returns a roclet roclet_find("rd_roclet") # If it lives in another package, you'll need to use :: roclet_find("roxygen2::rd_roclet") # If it takes parameters (which no roclet does currently), you'll need # to call the function roclet_find("roxygen2::rd_roclet()") } roxygen2/man/figures/0000755000176200001440000000000014115762717014261 5ustar liggesusersroxygen2/man/figures/logo.png0000644000176200001440000005035713523072405015727 0ustar liggesusersPNG  IHDRxb]esRGB pHYs  iTXtXML:com.adobe.xmp Adobe ImageReady 1 ).=@IDATx^EOʦͦ i*R|UTTTtD^EX_QAD:zMH!=!uMwf>ylHHݹ̜993sνæ65Q^%62sC$ V$v?T dsF.#ܝLlE6M!K)I o+{ dɳ1/#s% Ud_M(6d~@OF#ڳ]j yv_= n)"栝(|r B-ſ@ T}d"y\3ԭi^kW-(D}ł;.W@7l'WA3O/[- Av݆Ƈ5x{)6vϴkR!DH3PWjQDPY6ـ>AηdGY'+U5o5jg\nmH[ݰѦ@{QލSf O?f8 vkeOXxB+co.Zewu]ۅfmپ=[ZF[M¹cE3{v޾rr6rX%e$k$WE/Q}rᇩbfIp둚\*EYb[FؕceX̺uqޠO'vqwN+;v Ks="WX\fXƤ NaEH|vBYv׿V.C*Ms[\ܼcٱU3Z^vPaן9:oi4]#oZ{$3ڹSKR}bx j(fH.h7/4ˮڬ ۻƮE٘{3&Uk!NzAF:+l[8x^b Ala@ܻiu%xϳF(S?iszB';cCl{8jv4?ϒrF. ulv a4s완e1-ra5̶OJlAL[L]6 ǡ]3`h*h7nYYYVa,Tpd Glk{y.g=*q^r4븑_ɽJMXX G *fu<;G K3bTl5aDNvF^zSObzwph-ʓ!2_^")-oxܦB"S~S/+ƞ1!c|8V#fnF{?e>^o5vҐ:lmۺL3$=2B}_Smگ3Mhz6ooS<=ƻVqe1'E&N]j7>~eli{TlŅ]2?/cE/jo9ޯox,8?C@2x}}M%=ƛpޙv 45q}5ja#h4w&pܚY@LwϜ6F [n~FZ %;mV%~(g bz2YdDE,l;'f#c C@)?-ullNMB;wϷ|,yb!6H[=lo)2zl2>Yzط=}`Ua=oŐo^Vhō4V!0]5?Xru{xAvԡC9FXnn}[%߲+i1jٽd1c)Ӗ~?ݾS=j{ o-6w<"[VK#0Q'PNMJ=cF[ }}S~{F g7gU%XgSi*/οʹ/,~Ԣ*g*(pYrmVka[, V6@ˍkme;6zXy9S/>[[ .\SIp¶g۞onΪO:ԆmcK(6;?S&L9e e[&쪆ucs7ʹE/!{FTkgGh`{5кX"Z[.4 2ØIuZ:o=ki:4Mc_Pe<31۰VN=̷'0/d{^^: ;i:H;Ek$J@'V3,{E=8>Y>LWa aLX/rihSգ6o]q^OCmP|,jSFO;<ƻH6l|l]Yc~tZc2Me74ps*ٶM|e}v9#%V"ĩ357M[c[ےաD2Ėx|P¥PRu4dLܾ~vwْǒ+$9hI \/;4TY{m +_n{>N/J0# SnJɫ/m|fϯI[0C<x˫vبqN`zHA\~V.BHs5570Ԏ8d@~4l-ϕVIA '77&T'R}Y'N;YZ4.k S44or*9crsQ ⤃tGVd ݴa5-kjKYp30;筧.P-fܙM`9wdSh,I'ѕsPgU;]y˂ok1ʨ/XIw(m찲&Myg-i E6v (C2CGD^)K6CkI ɑ ʛ(< F6h1PbQuJ\8wKH{oof-鞤j3?nҐ7E醷 : ikn\ٞunZڹ_d|zd_+Mx?I[a9׆^ڙl"4,Kh%K4dY ު#1 Mh9Yi{l@83xchPkw ;ٸQU^Ӹo BwU_uKF>2}v33TK;Jk&ƌfgnyq}>GktlA*7%Lj uFFuͺǞr[Mba, 1bT1C*ZMq"‘+܎qg;٪7g(: XlF{J;0:%=qc{r-ìܑg{UD́i4LƋ@!tqVOq"hMf1AEUR̸.fYM&dB1BzZV"?<{iod(-n..-Xآ 0qnp2#) !d;i4-?4 E}ݭ #nt`ԤzuogfN ΔImDKefe tE dģ0b%?K .oh4[B4[2^; i[m,*+ Cp+km=YI>w"{v^ 8ozL #P  ;fA1R:n@eABmK.2398UWi|Smqlv`5z?rmHpL'c4-C760 KMA<k&O.XgaL+jmb_ox\p>3a9H/ܧ=^_m=4jVMCcޜI#ݿp nBAtE e ɢ "cwjyʙ&pi%BpæE)e6 7j䓯.qZ9J4ؠ(AȽ{|/X}(]mHߎ $^S*UӊXX2&ICG|LpO+9(oԿ6J6n7"WrEMsT܂ u݊{J>"-~/72oS\Z J@vi| 鈅MAچ!=P[&YQ6cGt@6EA5mVJ!7 WY LKoc䮼t.q*\ܘ8"7㑁_Zj:,١ YigW~Ӓ߫ ~O'YxDoU@SFɱ$b\> 2 Bfx+ży|JLrJ)',E*0$@&*;hp`Le/c 6-^+$FS1@n1hUKO,&/vqAs/m hzey(7u<_<62C "3p*OAIxbr2QqenN*,+ v&<>&I~ϓMn*gS!jGŚb^xlќ 2:iod7Ng;j/ڎ_K RBy bi1I ܰSlrDe&ΐ= RFsx=/咖@ uhw5KitK<6RԱX C>]k6Zh`W5CjC;k+ms^>ۙ6iV]*x{LE-S4,4;wl'/Ŷo PC'M|6{{S\pC2ڝQ.ք4M/[b$d&U'RTZa CKc2f1ӜXvcAcxvEXT"ۘ&@3Fo .?bylUvځ=Y+t[ V9D/]KK2IY^BYyU %Fh*Cȣ=. *U˟gJ~j%2(<fO^1'Pyl}zJ~U:){@fC% ijY+WTVz ϽQkCz_$lM&ލ\%f8¾iΥxɂpF%W$Wl8ŒD.XNDWaUD`FH|~OeƲ_tqG(VY` XnFwx˘X4~UשuvCϣ׭o:ALGeS+l)fU z (HE\D*d!D,A+H9+Uo1T)\63TBΉSo!N̔drR.%-*x)_ di0K9 NEPn0l_=\t zFIԁpKd_xŌScRaX3#Ytq 10) p N]* B:s2g.d>bycp/"0ZY YH<Ѩ^Y(3Y~܂@eh`9* dGmsgF tR; + eʋeEb8($DWO^ҝ.s.).3HGz<3b(Iښ\@*W9`4:c^.yAzaNCzR}9OR`iP.PIAIDZB8G_JZ'DaL8~0-$>\2GO.Y M8hJGV I8EB&קOf| (e Q cTBٵ<$ǂh$|\!<6\L" 颏!/FV> M;]>Ey`'Ԅp|bsm`=-R`Ȥ4`9۠Jꠧ(8@#Uj\ 2P) xfwɄ': 1٣87Q|ZY?zMOaT' mxj)ZGZ١ևpx*J^؁-˓KM}۷]b=ZSlC ݿ;O1@|%,prz$P"SŸ1PpbvB!1qџ&m(&N£. ZU0Kpk> ݺ*sJQ /@}e'9OvJGLsÞ]᝭xϾ^kWx2= + Rpxo.1 PbPB'%UpMVbҷEGqR=c//F|%.4Ny qixNk9_| LX2.Ba{.%g,H*WмkK|ύh(\ڊ_60im`}B_ѷлst숓*{ ̀maxȑ:D|'$BĔX``J̅K*^!r*ՀP䀘M)~Td\::f9ͯ $^|S= BWX/𛀔l§+IP]BAû)6ZTuPUOKƶH/T? rh3Z"yNi}s.>OEA:7cQ]j{S_ݥ}6Z?tx}yj;TG=/gFe#cUQi#4O͛A%P*P=?}-ҼrrvW?LМ~O9B\2u I٥kA}z/&lk&Z6, ih? >B 5Bt|8w.t<^)O ~uX+qzfo'pɣ>jT釵3Wg\W /-X֮4ԯwK[kmW Gt]UW\{}B~WWÖ1{v1- 4š[i>@4$gT( 8Q*/tTڧ`o}L;>N37oOfNګuҧ 5*+m>>]/ FC|Gt_4"7ctOO#թ>5 G|\_Uss|];Y>Y^?U 'mkgQ8ѮQMZnW<_c} QS4~OCU=>7!$JW 1X`KLA% W ch=!c9;e}X*ÑUv+ynM1ԁ:uqvݬSۖv"nkǎj]&Z={Lg!3 v`6+TJ9 uD:[uySH&vn]5 X+,M/?x:ug.Ku:z.Z8~mj S oM2E|pD- FA"3Q p?gCJ6x'Q ̋pgz避kc4l.&.{iz!okuyî=2ڳ&i4rNݩ+l/\i 3gY)BӹvrЇ<|qRTGt~ɗjl`zYh?}Q{y?ޞQ&B%w.";榣u ]^lS4^TdFUG6->NpHt_ IkbyZs{I13](oHջlul^lkZ! s믺!Y$7i}49U7ko>$GٵVtO|ɁUV^_Qk׾QodC" b.!Pޔ)3d YGZ%i\ߔ2@Y}p{M\!]R,:s?S lBABV  }t-RsbVk,+UQw VaF ^ʳicZxU pmۢNpmr";E $- &5kTpCtdYNMQ^\ vv}\|'^Nz 81"HKy_ȓଐTFލD|" c6L4W213FngKsU1]sOUma:k|u|nE |Vzpm uV/ |طCa@̫%:QaʷRy1H%sO\}2Cu!_4҉v:uZggΨ7bv#ǍªK;]Y:eZj Izj$D(sEѻQJ14!Q£.Q̒`Ptʧ VÚ7gJlZcFuկ0b% Փ5GN/1(ͷp$~fdvU]ǫ1rhhMt̡hz~^R1W蘾k_}uQ  Ie0Ѻ//w/%\S phH@iqZV2DҢuJZ[vv۵?}/Z~^E/0篿~Gx}g hG 9Pndb5Z&1.W" }xy[$ !ܝ =#fjx{sԐyrǙ(4NU7~v\Gxn6Tohw?)ͻSC+h{62 f엕~=XpC-[W™Z,a[1U!fݮU9CZ^[4[ :]Y|}LU  . mEZw|! #ţ# mu%uH9;0&rv01M{o"[L"]i+enbxf;S훧ɃEǯY$ و[%7̎=sW{{׍lc$: #D9\L.ўyTwUN%{vߎ0Silzٙ:4WtK{C]ZM*w~f$0LsbFe Dr1U6G#;qUv@諼cVa}jEa=Kzivҋg=4g8U* <].͟#P)̍[6GV⩃XH5ʭJWEZʭSV+}mo)woeϛ _O൥E/F#f̦(Q: y#*7|SCml-f=] "U/HY~_)$YX_4>9M@NJ*Fkix])O ,eЧ$P`0 AoUQg{~VѺ /b^Vn/53ZۛҠ״"OjԘ%#ZVb B< i8.FiPr&*BE" ~F<3虞:p[/ ^.R[ԧz2UCwJL!&[DƫqyGȥeyݍ4yuUL:K_j^@8ѠTj)UVͷkg*j#^GsJeRx]RzrCjZ'fJId(5eN.OGM_"}z;nr'+r7Iތ,>?=q}yI6g O]|>??>)>Іm(%<ʕe(Ghg-Kx]+^(":-;S=Ybmf2}̆O40 qm"4iu7 0]8=0Z}qn-{emuΨo_}W @jE-sP$DMr̓0ExtlB]UTd8խ :k;^n޹iQro/`-<y]p,ZG˸R$# ,[`qPfPXA9]{4E#C#XaqY>^o..T2@8 G`* 2#K ٜ(eAC8Q {(h,a+q=Q'`?ԁ U|J̥JLhfUn'DQI7K9ȞHXxmg~q}F}^=;Xۀmu3?Zv&pK򀕂6r9ܠt@Lkb!Xt 37`:BL~F|oՎ: #/y.*?Ͼ0M.0)Yu˛2M'{> dGa QB}v}[,a0`ԟ2n'TB(njsnb ʿ,\/I2?7JĞQCICs AB\n\.P5_NٻJyVieVUfGu/Vlm+syKSϗH!óyz%vє6RH|/>qN3<.A/"sGhrQ 0q;s d"2?T{8Ĺ&faOHݙ+0C; t9`x =ҿ.C@F3ǡxMtQ]S! &Pm8 ku}AGS+< {_0,;raW<ϒ֔v7T+[g@dy-4 Pj-"~r<](d`L6̈́=.~srX49aX =yz+2N/PL BW]<&d'vю[i]`>s֦0 a.*C߶Q !+V kd/z];Pmt'(n%r-ˆbW 2Dã%:rFb% f~7z]~@·S)93Amq6h,Cw;w!FMv{Slyf)Q @O_To=Wm룡)HọEvkr. x3d<ć ^Np&͆h"ZONp@hͩhuU; ;G+;c.6~`Glg6[d/sMr7!mkv OvZmRJ3d1Qced/93/KGinS6jpڐ1L ĕ3S,@8WBN oBT%gN%;O{2z,pl/>):fkLSMޚ2hŠh~>Tkeq~v(&D g+pAKM ;484SIe ZPƛV)rxb.Z0Jc+5ɱzmQ]^.^$Y4=LM#, 4r@Xfy^SW~*.RWֲQ/9;P-e ;YС6h\|Hew-A:W]/- -y v:T0aT@j?W*Sܭʼ%y<;_(N4j oӫ7/XcctEl>' Kx 9pe2g&]Ɲ(U>yWq[-b7垶kG;@g1O$ Ŕư] :{̳ՔIMm*}ī!ԓwUJ٢ǒRzS3VZ{@OVI9KK E8xu#r(7⁃vЁyP Gk5Dϐƾq:h0-S _"`-gͳٔAQ,رj=#+tSkSWKl׋2e l9iM2wK z`y:z%C{tڨxB:tܮ_lj]+OQ( NvyGN (>fM=>ƏuzWHJc8*``?\ ;Y9h Z9Y,Pg➖Uxoj^) @,oVh~w̔6򍖟=Ke(kWmz:IWy iQby8!:A]Ge̾/pJ[S| bCg0B,XO 4;~L67EC%Xxw)U'!9ضv?ߢ7'hs ="?һ?\BJ20/p2YG^<ۉWkdg/ؿCvc,5eJ%0T5"+GV復v^V爞70C:DJ@JMB>UZ;[/Ÿ]y/a"t#HKC(5CiNR?Wi_-~,7TcЫ+==l|]KÅ idfĹ:J igΖM6nHLThl56ˊˆ=HA4-zȃ!'o&uuzy:oSxX*X~[3HPd3j~8wߛg0vfW@1?>Fd'RoMOr#p]/7g!_]<IENDB`roxygen2/man/figures/test-figure-1.png0000644000176200001440000003260414115762717017370 0ustar liggesusersPNG  IHDR(iCCPkCGColorSpaceGenericRGB8U]hU>+$΃Ԧ5lRфem,lAݝi&3i)>A['!j-P(G 3k~s ,[%,-:t} }-+*&¿ gPG݅ج8"eŲ]A b ;l õWϙ2_E,(ۈ#Zsێ<5)"E6N#ӽEkۃO0}*rUt.iei #]r >cU{t7+ԙg߃xuWB_-%=^ t0uvW9 %/VBW'_tMۓP\>@y0`D i|[` hh)Tj0B#ЪhU# ~yhu fp#1I/I"0! 'Sdd:J5ǖ"sdy#R7wAgdJ7kʕn^:}nWFVst$gj-tԝr_װ_7Z ~V54V }o[G=Nd>-UlaY5V}xg[?k&>srq߀].r_r_qsGjy4k iQܟBZ-<(d=dKO a/zv7]ǰod}sn?TF'|3Nn#I?"mzv~K=گsl<b|_|4>?pߋQrib 2* (Ѧh{28oIyes8';Z9h6g>xRx'b8ՃWOϫ[xn%|^z}%x c8eXIfMM*iNi0IDATx T}?/KX4(h#j#EL]5Qk V瑸g5Z&HTV^"h(9_=sΜ~{?sj͟0 @h]  x/ PB_A%  @@ | U @ @%%T]"@kP@pPux PB_A%  @@ | U @ @%%T]"@kP@pPux PB_A%  @@ | U @ @%%T]"@kP@pPux PB_A%  @@ | U @ @%%T]"@kP@pPux PB_A%  @@ | U @ @%%T]"@kP@pPux PB_A%  @@ | U @ @%%T]"@kP@pPux PB_A%  @@ | U @ @%%T]"@kP@pPumIsOZ%uY_  @ G>҂Vk}Ԝ'GC 38*$@)0{Xzu.w >v @l|J'@\UJ*" saW)VphѢl{t PrB+bѳgh׮]lѩS{cĉ%#@/P5*ϟSN]w5 K /sN,[,FW"(@!|b}Ν;GVK.q5\'O.)n @@~?|YmT36pʔ)ѭ[,$@Y q7/GqD\wuYUI8E'cǎ^zV[mK,_|10ӦMˤ %@n+fK.<8NTۥp }z*y䑘;wnz=>9jO@4ӫnO;gyf @~8.†b-"_,Y.ײlړ:!iVp@z^cƌ?* @@@ ,޽{]>o޼4.(B7;Ok׮|5 @`=N;-ׄ b=HoN>Օ\>+W~YV @HUW]Æ ;g#z uġC_]늘'@^sϺ/D_{݊W믿>*B|>NnK>h1:J(|ҹn\ Т sߢud, 3V<C@确N X @ :  @@>c` @<|$@ Oyd, 3V<C@确N X @ :  @@>c` @<|$@ Oyd, 3V<C@确N X @ :  @@>c` @<|$@ Oyd, 3V<C@确N X P)|3gNە+5@f-Ma @`I?O?{l\zê ُ%xիW hnݺ7tPp 1Fe قI`=7|3^{ԩS.Tb늘'@L:vIЛp >[_ @\|.*%@ l}Nr𹰫d+ U:E@®R W @  J  @@>[_ @\|.*%@ l}Nr𹰫d+ U:E@®R W @  J  @@>[_ @\|.*%@ l}Nr𹰫d+ U:E@®R W @  J  @@>[_ @\|.*%@ l}Nr𹰫d+ U:E@®R @lozW>(:wBI"p7~7h1\ ,/]4x  @ /z(Əw}wm6~i8xW#>;VZ8쩧ѡZhQ,^vK,+WV]g!U wwēO>n\veqI'K/{׮if "={ԩS۱p8ӮG?JC~S7ML6*ɣ>Y$|c=ֆ{Cߒw~6hB>}zr!.>㵣F~o 'OsύW[eVk׮[ĝww~$4&LK.n/P?c1gΜ$f͊3gn~O@ $ۓ˜=z_|1r˘4iRzVt*auiS ^x!{n"9'Fǎ7?#@@iЊ+sIŽ p!>iVVpOo>9䩉6A 騣ڄ-mR 1 @VV!@55Vz @@ | UEj% k% PC_ClU @Z ZIP@[U @VV!@55Vz @@ | UEj% k% PC_ClU @Z ZIP@[U @VV!@55Vz @@ | UEj% k% PC_ClU @Z ZIP@[U @VV!@55Vz @@ | UEj% k% PC5KU+wy'~ŋcw3<3Zv\TW؂ڂ_ l?8oƎ;C Yf+W읬!P _#peYg~z7n8C;,N#p"@ ,\0W0`X`A23* :2E@=zӧWaѳgϊefUMvE"@ WQF.oV~q]wŊ+O̵]*'7Uv(.]v_`7mڴe-O P]vq9dX d'>;[% @|n*&@ lLrѫd' ೳU2M@Fb V @ 7  @@v>;[% @|n*&@ lLrѫd' ೳU2M@Fb V @ 7  @@v>;[% @|n*&@ lLrѫd' ೳU2M@Fb V @ 7  @@v>;[% @|n*&@ lLrѫd' ೳU2M@Fb @V2 <OFNO}s7& ~ٲer&w̎S`„ ( G}4zK,)fc@ "_2dH<;ic뭷ÇNJ+X hxg /{7 \sM|ߏ/a4@!N?w9k+bժUs?a\r%|뭷8maѣGU P#gy&ƌ;w^[#NX; #P~/Rk.リhѢM-v @@A [;\L>ۦ{ĉ l @6$MvgRϟSN]w5 j]sN$?r i zG>`p >_'ݞ|VL7:9 Pl>9?cƌNU[nUYHG`S_|q|1vHfJ/Olq% @ } Gs㓣#9eo"@-^'M1!Rk ]- @F`#:V\ݻwwq  @ >~uСCDwѯ+bO`kcOM @@ T?f̘H>i1 '&;wn  PUK3TtkOW,3CO3oW;LoXh(@SI+]w袋]d(gDlD( @zXoV P]`Mvա,%@$^&z>m%@^Mvձ,%@"|pdW/ç @@#ZJԋN , @zz ^EO>>VZ{wk/+=#@ 7:\F?0>رc$A?qĘ7o^le> ~lB . >m7H胧}2p >#X… cw\ICm6^zZ5C=L@l@4@cڶmmڴ5kT{ED@-sD[ou?.䒵!}/?ƗTWhom T`kŠAbYUVmf wY +@ Sɝ&48oHJ$ K4B|G P"_ $< @   @ H@h0u4  @DD+ @A@7Hx$@%%L]!@ A#(/` h   @@|SW @@oHJ$ K4B|G P"_ $< @   @ H@h0u4  @DD+ @A@7Hx$@%%L]!@ A#(/` h   @@ ˖-KZWQۿ>:oxWL@ (lO4);8$\>Ǝ7xcL2%&L#F7|(M|@\S{,\+VĪU" ;.&NXܹs7ި*?ʕ+@5$/ѣG:92dH{qYgU2FSNC8'OGy$ƌ:u$_~9z衪۾ѥK,$PM࣏>-ܲbV[mn23(@!~㏧GEin!v;w]ve;H~M~̟?*T8DuVZŋ㏏?UE(D' ɑ-wuW 808hӦM $g7ɩc9&z꩸{-LBw G|޷׾#G}ݷaG7.}xSOm\R|Ү䦦_W@!gBC# ~L1- P) += @RR N @J_aB@buT Js @è @R@Wz#@F @(/0 @@)|)Q' @@0GJ! K1:A*|9 P _a  P) += @RR N @J_aB@buT Js @è @R@Wz#@F @(/0 @@)|)Q' @@0GJ!жЉXbE\{cE⢋.vۭ(#Pڷf͚4hPqWȑ#SOMþd]* soyO:5vq7n\կ~5;vlcd( 3UK,C=bXxq23 y~H޽{<˖-[)S[nk=!@p*_|_ݻ/~7o^̜93FbSؘ# Yg}v$GNt5r- @% 8oɣc:H~L #l\Jrd# qU*U@ʯr U @ W+  @@6>W @\|*'@l\Jrd# qU*U@ʯr U @ W+  @@6>W @\|*'@l\Jrd# qU*U@ʯr U @ W+  @@6>W @\|*'@l\Jrd# qU*U@ʯr U @ W+  @@6m)JObժUѾ}+%1uXbEzѧOT @`c87bȐ!ѹs8W^Y;ﮝO<#Fݻ{} PzB;6 (:t[;hq^re/7bŊ8T9sbN;5i٩ Ӿ?ũv 3guվSN9%ƌjDc7￷΍d @z2RI! eS P/^FJ;  @@#|#lJE@Hi'h56M>[|K.ܺi[oݻwCCyvmM6ܺhl^|6 @\ϕ_ @ R  @@>W~ @l|6J%@ \UNٸ** sW9F@gTcUVŚ5k/O^?b}I.g#ߺ9e>2dH_U/nv4 p饗q㚡Ė[ok̙3g-¢Ev#/O&|'1a„4ԓ ͞=;uք `h߾}-"|͆7Q`Ŋ1qĸ{b뭷kڴimG㡇ئh3h#dNqqG645w}z7Ѱf$>;ucǎ]Do(Ѯ7aC 7Ѯ]{99|5۰" U'_iBےkrJz-OlB viHN'2 ZfrԞL.#]xᅑ9.Xk;0_sK… 7Hި&yEF- N:)wwuW#igMm&h]MON'gD)=:ӛ~lz!\Oફ#8"{qWW_}zY4䞑bK_HhHh6,Y)VԡCKQ7.&{r# MbEig={ѺuO$lQ}=hmMޓ Azkìfm"9} GϞ=7lwwoJ?~|zy̔կҀO>ܥ}&ϓw $o<=hJ~GlZJwߝ>O%ϓe8g?Yw5l=l 2(՟?_ߟOOM6SN"ϛ([ӧO{M,n fyRGr8V{l@r .gy&.hO&#<zJ H>=G6m◿ez if/_g @rRr3cijs%t)zX5T kd# qU*U@ʯr U @ W+  @@6>W @\|*'@l\Jrd# qU*U@ʯr U @ W+  @@6>W @\|*'@l\Jrd# qU*U@ʯrxǢk׮tԨQqW4z?; ^ @ 3 [bСq9vm}dYtGc c…o}+zw}c֬Y &qk֬I.~_j+ k6XlYۿ[l3GN_"f̘cĈ1eʔ>ӢSNYgÆ K}M ~q뭷e2d~ P[NmI /8Zj'|rI8ScJً-J_nݺg7 =\1~>|x\2h߾}-ZoQí*va4ܓ;wUV$޿_Mϛ7/=ߧO'3gL̎;ƁXj+}mFPɑ{ivٳg]oϷfh۶m$At筷Z{;s΍义|~j&PX>8&M˗/ o۴={/| qM7)^zœO>~qquŸq2|J?Oѯ_dA֭kɺ4|r~~Fid|Z#-|W+XdIz|rZ~)9|ig_w{V@[m @&NׄY% @j#@55aV  @@M|MUBj+ k6 P_f @ zD@ׄY% @j#@55aV  @@M|MUBj+ k6 P_f @ zD5_tIENDB`roxygen2/man/markdown-internals.Rd0000644000176200001440000000322713565340602016720 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/markdown-escaping.R \name{escape_rd_for_md} \alias{escape_rd_for_md} \alias{unescape_rd_for_md} \title{Escape Rd markup, to avoid interpreting it as markdown} \usage{ escape_rd_for_md(text) unescape_rd_for_md(rd_text, esc_text) } \arguments{ \item{text}{Input text. Potentially contains Rd and/or markdown markup.} \item{rd_text}{The markdown parsed and interpreted text.} \item{esc_text}{The original escaped text from \code{escape_rd_for_md()}.} } \value{ For \code{escape_rd_for_md}: A \dQuote{safe} version of the input text, where each fragile Rd tag is replaced by a placeholder. The original text is added as an attribute for each placeholder. For \code{unescape_rd_for_md}: Rd text. } \description{ This is needed, if we want to stay compatible with existing markup, even if markdown mode is switched on. Fragile Rd tags (tags that may contain markup that can be picked up by the markdown parser), are replaced by placeholders. After the markdown to Rd conversion is done, the original text is put back in place of the placeholders. It puts back the protected fragile Rd commands into the text after the markdown parsing. } \details{ The list of protected Rd tags is in \code{escaped_for_md}. Some Rd macros are treated specially: \itemize{ \item For \code{if}, markdown is only allowed in the second argument. \item For \code{ifelse} markdown is allowed in the second and third arguments. } See also \code{roclet-rd.R} for the list of tags that uses the markdown-enabled parser. Some tags, e.g. \verb{@aliases}, \verb{@backref}, etc. only use the standard Roxygen parser. } \keyword{internal} roxygen2/man/roc_proc_text.Rd0000644000176200001440000000056613544713752015765 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/roclet.R \name{roc_proc_text} \alias{roc_proc_text} \title{Process roclet on string and capture results.} \usage{ roc_proc_text(roclet, input) } \arguments{ \item{roclet}{Name of roclet to use for processing.} \item{input}{Source string} } \description{ Useful for testing. } \keyword{internal} roxygen2/man/is_s3_generic.Rd0000644000176200001440000000137013541216367015616 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/object-s3.R \name{is_s3_generic} \alias{is_s3_generic} \alias{is_s3_method} \title{Determine if a function is an S3 generic or S3 method.} \usage{ is_s3_generic(name, env = parent.frame()) is_s3_method(name, env = parent.frame()) } \arguments{ \item{name}{Name of function.} \item{env}{Base environment in which to look for function definition.} } \description{ \code{is_s3_generic} compares name to \code{.knownS3Generics} and \code{.S3PrimitiveGenerics}, then looks at the function body to see if it calls \code{\link[=UseMethod]{UseMethod()}}. \code{is_s3_method} builds names of all possible generics for that function and then checks if any of them actually is a generic. } roxygen2/man/markdown_pass1.Rd0000644000176200001440000000262514115762720016034 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/markdown.R \name{markdown_pass1} \alias{markdown_pass1} \title{Expand the embedded inline code} \usage{ markdown_pass1(text) } \arguments{ \item{text}{Input text.} } \value{ Text with the inline code expanded. A character vector of the same length as the input \code{text}. } \description{ Expand the embedded inline code } \details{ For example this becomes two: 2. Variables can be set and then reused, within the same tag: The value of \code{x} is 100. We have access to the internal functions of the package, e.g. since this is \emph{roxygen2}, we can refer to the internal \code{markdown} function, and this is \code{TRUE}: TRUE. To insert the name of the current package: roxygen2. The \code{iris} data set has 5 columns: \code{Sepal.Length}, \code{Sepal.Width}, \code{Petal.Length}, \code{Petal.Width}, \code{Species}.\if{html}{\out{
}}\preformatted{# Code block demo x + 1 }\if{html}{\out{
}}\preformatted{## [1] 101 } Chunk options:\if{html}{\out{
}}\preformatted{names(mtcars) nrow(mtcars) }\if{html}{\out{
}}\preformatted{## [1] "mpg" "cyl" "disp" "hp" "drat" "wt" "qsec" "vs" "am" "gear" ## [11] "carb" ## [1] 32 } Plots:\if{html}{\out{
}}\preformatted{plot(1:10) }\if{html}{\out{
}} \figure{test-figure-1.png} } \keyword{internal} roxygen2/man/vignette_roclet.Rd0000644000176200001440000000164513560327422016300 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/vignette.R \name{vignette_roclet} \alias{vignette_roclet} \title{Re-build outdated vignettes.} \usage{ vignette_roclet() } \description{ This rebuilds outdated vignettes with \link[tools:buildVignette]{tools::buildVignette}. By default, it will rebuild all vignettes if the source file is newer than the output pdf or html. (This means it will automatically re-build the vignette if you change the vignette source, but \emph{not} when you change the R code). If you want finer control, add a Makefile to \verb{vignettes/} and roxygen2 will use that instead. } \details{ To prevent RStudio from re-building the vignettes again when checking your package, add \code{--no-build-vignettes} to the "Build Source Package" field in your project options. } \seealso{ Other roclets: \code{\link{namespace_roclet}()}, \code{\link{rd_roclet}()} } \concept{roclets} roxygen2/man/roxy_tag.Rd0000644000176200001440000000166613544731730014745 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tag.R \name{roxy_tag} \alias{roxy_tag} \alias{roxy_tag_parse} \alias{roxy_tag_warning} \title{\code{roxy_tag} S3 constructor} \usage{ roxy_tag(tag, raw, val = NULL, file = NA_character_, line = NA_integer_) roxy_tag_parse(x) roxy_tag_warning(x, ...) } \arguments{ \item{tag}{Tag name. Arguments starting with \code{.} are reserved for internal usage.} \item{raw}{Raw tag value, a string.} \item{val}{Parsed tag value, typically a character vector, but sometimes a list. Usually filled in by \code{tag_parsers}} \item{file, line}{Location of the tag} \item{x}{A tag} } \description{ \code{roxy_tag()} is the constructor for tag objects. \code{roxy_tag_warning()} generates a warning that gives the location of the tag. } \section{Methods}{ Define a method for \code{roxy_tag_parse} to support new tags. See \link{tag_parsers} for more details. } \keyword{internal} roxygen2/man/double_escape_md.Rd0000644000176200001440000000134513567073220016353 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/markdown-escaping.R \name{double_escape_md} \alias{double_escape_md} \title{Check markdown escaping} \usage{ double_escape_md(text) } \arguments{ \item{text}{Input text.} } \value{ Double-escaped text. } \description{ This is a regression test for Markdown escaping. } \details{ Each of the following bullets should look the same when rendered: \itemize{ \item Double escapes: \\, \\\%, \\$, \\_ \item Backticks: \verb{\\}, \verb{\\\%}, \verb{\\$}, \verb{\\_} \item \verb{\verb{}}: \verb{\\}, \verb{\\\%}, \verb{\$}, \verb{\_} } [ this isn't a link ] \[ neither is this \] } \examples{ "\%" # percent "\"" # double quote '\'' # single quote } \keyword{internal} roxygen2/man/object.Rd0000644000176200001440000000101513541216367014344 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/object-from-call.R \name{object} \alias{object} \title{Constructors for S3 object to represent R objects.} \usage{ object(value, alias, type) } \arguments{ \item{value}{The object itself.} \item{alias}{Alias for object being documented, in case you create a generator function with different name.} } \description{ These objects are usually created by the parsers, but it is also useful to generate them by hand for testing. } \keyword{internal} roxygen2/man/object_format.Rd0000644000176200001440000000075513544731730015725 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/object-format.R \name{object_format} \alias{object_format} \title{Default format for data} \usage{ object_format(x) } \arguments{ \item{x}{A data object} } \value{ A \code{character} value with valid \code{Rd} syntax, or \code{NULL}. } \description{ This function is called to generate the default "Format" section for each data object. The default implementation will return the class and dimension information. } roxygen2/man/markdown-test.Rd0000644000176200001440000000163213544741515015703 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/markdown-link.R \name{markdown-test} \alias{markdown-test} \title{Dummy page to test roxygen's markdown formatting} \description{ Links are very tricky, so I'll put in some links here: Link to a function: \code{\link[=roxygenize]{roxygenize()}}. Link to an object: \link{roxygenize} (we just treat it like an object here. } \details{ Link to another package, function: \code{\link[devtools:document]{devtools::document()}}. Link to another package, non-function: \link[devtools:document]{devtools::document}. Link with link text: \link[=roxygenize]{this great function}, \code{\link[=roxygenize]{roxygenize}}, or \link[=roxygenize]{that great function}. In another package: \link[devtools:document]{and this one}. This is a table:\tabular{lr}{ \strong{foo} \tab \strong{bar} \cr 1 \tab 2 \cr 100 \tab 200 \cr } } \keyword{internal} roxygen2/man/rd_section.Rd0000644000176200001440000000212113544473137015231 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/field.R \name{rd_section} \alias{rd_section} \title{Construct an \code{rd_section} object} \usage{ rd_section(type, value) } \arguments{ \item{type}{Section type. Stored in \code{type} field, and in class \verb{rd_section_\{type\}}. To avoid namespace clashes between different extensions, this should include the package name.} \item{value}{Section data. Only used by \code{format()} and \code{merge()} methods.} } \description{ An \code{rd_section} represents an Rd command that can appear at the top-level of an Rd document, like \verb{\\name\{\}}, \verb{\\title\{\}}, \verb{\\description\{\}}, or \verb{\\section\{\}}. } \section{Methods}{ If provide your own \code{rd_section} type, you'll also need to define a \verb{format.rd_section_\{type\}} method that returns formatted Rd output. You may also need to provide a \verb{merge.rd_section_\{type\}} method if two sections can not be combined with \code{rd_section(x$type, c(x$value, y$value))}. See \code{vignette("extending")} for more details. } \keyword{internal} roxygen2/man/roxy_tag_rd.Rd0000644000176200001440000000110013544731730015411 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/rd.R \name{roxy_tag_rd} \alias{roxy_tag_rd} \title{Generate Rd output from a tag} \usage{ roxy_tag_rd(x, base_path, env) } \arguments{ \item{x}{The tag} \item{base_path}{Path to package root directory.} \item{env}{Environment in which to evaluate code (if needed)} } \value{ Methods must return a \link{rd_section}. } \description{ Provide a method for this generic if you want a tag to generate output in \code{.Rd} files. See \code{vignette("extending")} for more details. } \keyword{internal} roxygen2/man/parse_package.Rd0000644000176200001440000000265713544713752015703 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/parse.R \name{parse_package} \alias{parse_package} \alias{parse_file} \alias{parse_text} \alias{env_file} \alias{env_package} \title{Parse a package, file, or inline code} \usage{ parse_package(path = ".", env = env_package(path)) parse_file(file, env = env_file(file), srcref_path = NULL) parse_text(text, env = env_file(file)) env_file(file) env_package(path) } \arguments{ \item{path, file, text}{Either specify a \code{path} to the root directory of a package, an R \code{file}, or a character vector \code{text}.} \item{env}{An environment environment containing the result of evaluating the input code. The defaults will do this for you in a test environment: for real code you'll need to generate the environment yourself. You can also set to \code{NULL} if you only want to get the tokenized code blocks only. This suppresses evaluation of \verb{@eval} tags, and will not find the code object associated with each block.} } \value{ A list of roxy_block objects } \description{ \code{parse_package()}, \code{parse_file()}, and \code{parse_text()} allow you to use roxygen's parsing code to parse the roxygen blocks from a package, file, or character vector of code. \code{env_package()} and \code{env_file()} provide defaults that generate a temporary environment making it possible to associate each block with the corresponding live object. } \keyword{internal} roxygen2/man/roclet.Rd0000644000176200001440000000326513544731730014376 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/roclet.R \name{roclet} \alias{roclet} \alias{roclet_preprocess} \alias{roclet_process} \alias{roclet_output} \alias{roclet_clean} \alias{roclet_tags} \title{Build a new roclet.} \usage{ roclet(subclass, ...) roclet_preprocess(x, blocks, base_path) roclet_process(x, blocks, env, base_path) roclet_output(x, results, base_path, ...) roclet_clean(x, base_path) roclet_tags(x) } \arguments{ \item{x}{A \code{roclet} object.} \item{blocks}{A list of \link{roxy_block} objects.} \item{base_path}{Path to root of source package.} \item{env}{Package environment.} \item{results}{Value returned from your \code{roclet_process()} method.} } \description{ To create a new roclet, you will need to create a constructor function that wraps \code{roclet}, and then implement the methods described below. } \section{Methods}{ \itemize{ \item \code{roclet_preprocess()} is called after blocks have been parsed but before code has been evaluated. This should only be needed if your roclet affects how code will evaluated. Should return a roclet. \item \code{roclet_process()} called after blocks have been evaluated; i.e. the \verb{@eval} tag has been processed, and the object associated with each block has been determined. \item \code{roclet_output()} is given the output from \code{roclet_process()} and should produce files on disk. \item \code{roclet_clean()} called when \code{roxygenise(clean = TRUE)}. Should remove any files created by the roclet. } \subsection{Deprecated methods}{ \code{roclet_tags()} is no longer used; instead provide a \code{\link[=roxy_tag_parse]{roxy_tag_parse()}} method for each tag. } } \keyword{internal} roxygen2/DESCRIPTION0000644000176200001440000000366014116067732013551 0ustar liggesusersPackage: roxygen2 Title: In-Line Documentation for R Version: 7.1.2 Authors@R: c(person(given = "Hadley", family = "Wickham", role = c("aut", "cre", "cph"), email = "hadley@rstudio.com", comment = c("ORCID" = "0000-0003-4757-117X")), person(given = "Peter", family = "Danenberg", role = c("aut", "cph"), email = "pcd@roxygen.org"), person(given = "Gábor", family = "Csárdi", role = c("aut"), email = "csardi.gabor@gmail.com"), person(given = "Manuel", family = "Eugster", role = c("aut", "cph")), person(given = "RStudio", role = "cph")) Description: Generate your Rd documentation, 'NAMESPACE' file, and collation field using specially formatted comments. Writing documentation in-line with code makes it easier to keep your documentation up-to-date as your requirements change. 'Roxygen2' is inspired by the 'Doxygen' system for C++. License: MIT + file LICENSE URL: https://roxygen2.r-lib.org/, https://github.com/r-lib/roxygen2 BugReports: https://github.com/r-lib/roxygen2/issues Depends: R (>= 3.3) Imports: brew, commonmark, desc (>= 1.2.0), digest, knitr, methods, pkgload (>= 1.0.2), purrr (>= 0.3.3), R6 (>= 2.1.2), rlang, stringi, stringr (>= 1.0.0), utils, xml2 Suggests: covr, devtools, rmarkdown, testthat (>= 2.1.0), R.methodsS3, R.oo LinkingTo: cpp11 VignetteBuilder: knitr SystemRequirements: C++11 Encoding: UTF-8 RoxygenNote: 7.1.1.9001 Language: en-GB NeedsCompilation: yes Packaged: 2021-09-07 22:28:06 UTC; hadley Author: Hadley Wickham [aut, cre, cph] (), Peter Danenberg [aut, cph], Gábor Csárdi [aut], Manuel Eugster [aut, cph], RStudio [cph] Maintainer: Hadley Wickham Repository: CRAN Date/Publication: 2021-09-08 08:10:02 UTC roxygen2/build/0000755000176200001440000000000014115763565013143 5ustar liggesusersroxygen2/build/vignette.rds0000644000176200001440000000051314115763565015501 0ustar liggesusers;O0ݼJ)LHa -UՊ4RTQڍD ?k㓼8% [{  |k $Z 9/74nUȜ*$33Ylw  늍f(b>Lg,T4)ǒWoX\(BܚwyJYXju ׯU!moQI0@Fވ5:?ZcgmP_)SO+_}衵yqlxKաӹ{7~' uWh *B`3Tױ8%:B3hp$Vroxygen2/tests/0000755000176200001440000000000014115763566013207 5ustar liggesusersroxygen2/tests/testthat/0000755000176200001440000000000014116067732015040 5ustar liggesusersroxygen2/tests/testthat/test-object-usage-wrap-old.txt0000644000176200001440000000131214115761233022642 0ustar liggesusersf(a = " a", b = " b", c = " c", d = " d") f(a = c("abcdef", "abcdef", "abcdef", "abcdef", "abcdef", "abcdef", "abcdef", "abcdef", "abcdef", "abcdef")) \method{mean}{reallyratherquitelongclassname}(reallyreatherquitelongargument = "reallyratherquitelongvalue_____________________") long_replacement_fun(x, a = "aaaaaaaaaaaaaaaa", b = "aaaaaaaaaaaaaaaa", c = "aaaaaaaaaaaaaaaa") <- value f(xxxxxxxxxxxxxxxxxx1, xxxxxxxxxxxxxxxxxx2, xxxxxxxxxxxxxxxxxx3, x = "\\"'", xxxxxxxxxxxxxxxxxx4, xxxxxxxxxxxxxxxxxx5, xxxxxxxxxxxxxxxxxx6, xxxxxxxxxxxxxxxxxx7) roxygen2/tests/testthat/test-rd-inherit-dots-inherit.txt0000644000176200001440000000026514115761231023227 0ustar liggesusers> out$get_section("param") \arguments{ \item{x}{x} \item{...}{ Arguments passed on to \code{\link[=baz]{baz}} \describe{ \item{\code{y}}{y} \item{\code{z}}{z} }} } roxygen2/tests/testthat/test-rd-template.R0000644000176200001440000000157413542230241020352 0ustar liggesuserstest_that("can find template from name", { base <- test_path("templates/") expect_equal( template_find(base, "UCase"), file.path(base, "man-roxygen", "UCase.R") ) # On case-insentive file systems, will find upper case version first expect_equal( tolower(template_find(base, "lcase")), tolower(file.path(base, "man-roxygen", "lcase.r")) ) expect_equal( template_find(base, "new-path"), file.path(base, "man" , "roxygen", "templates", "new-path.R") ) expect_error( template_find(base, "missing"), "Can't find template" ) }) test_that("templates replace variables with their values", { out <- roc_proc_text(rd_roclet(), " #' @template values #' @templateVar x a #' @templateVar y b #' @templateVar z c x <- 10")[[1]] expect_equal(out$get_value("title"), "a") expect_equal(out$get_value("param"), c(b = "c")) }) roxygen2/tests/testthat/roxygen-block-3-B.Rd0000644000176200001440000000465214115761232020433 0ustar liggesusers> res[[n]] % Generated by roxygen2: do not edit by hand % Please edit documentation in ./roxygen-block-3.R \name{B} \alias{B} \title{Class B} \description{ Class B Description. } \details{ Class B details. } \section{Super class}{ \code{\link[roxygen2:A]{roxygen2::A}} -> \code{B} } \section{Public fields}{ \if{html}{\out{
}} \describe{ \item{\code{field1}}{B field 1.} \item{\code{field4}}{B field 4.} } \if{html}{\out{
}} } \section{Active bindings}{ \if{html}{\out{
}} \describe{ \item{\code{active1}}{B binding 1.} \item{\code{active4}}{B binding 4.} \item{\code{active5}}{B binding 5.} } \if{html}{\out{
}} } \section{Methods}{ \subsection{Public methods}{ \itemize{ \item \href{#method-meth1}{\code{B$meth1()}} \item \href{#method-meth4}{\code{B$meth4()}} \item \href{#method-clone}{\code{B$clone()}} } } \if{html}{ \out{
Inherited methods} \itemize{ \item \out{}\href{../../roxygen2/html/A.html#method-meth2}{\code{roxygen2::A$meth2()}}\out{} \item \out{}\href{../../roxygen2/html/A.html#method-meth3}{\code{roxygen2::A$meth3()}}\out{} } \out{
} } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-meth1}{}}} \subsection{Method \code{meth1()}}{ B method 1. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{B$meth1(Z)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{Z}}{Still zzzzzzzz.} } \if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-meth4}{}}} \subsection{Method \code{meth4()}}{ A method 4. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{B$meth4()}\if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{B$clone(deep = FALSE)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{deep}}{Whether to make a deep clone.} } \if{html}{\out{
}} } } } roxygen2/tests/testthat/Rd-example-3.R0000644000176200001440000000002013523072405017303 0ustar liggesusersx1 <- 1 x2 <- 2 roxygen2/tests/testthat/test-object-format.R0000644000176200001440000000070513631761325020676 0ustar liggesuserstest_that("format has nice defaults for bare vectors", { if (getRversion() >= "4.0.0") { txt <- "test-object-format-r4.txt" } else { txt <- "test-object-format.txt" } verify_output(test_path(txt), { call_to_format(x <- list(a = 1, b = 2)) call_to_format(x <- ordered(letters[1:5])) call_to_format(x <- diag(10)) call_to_format(x <- array(1:27, dim = c(3, 3, 3))) call_to_format(x <- data.frame(a = 1, b = 2)) }) }) roxygen2/tests/testthat/test-object-s3.R0000644000176200001440000000300513541153276017727 0ustar liggesuserstest_that("primitive generics detected", { expect_true(is_s3_generic("[")) expect_true(is_s3_method("[.data.frame")) expect_true(is_s3_generic("mean")) expect_true(is_s3_method("mean.default")) expect_true(is_s3_generic("c")) expect_true(is_s3_method("c.Date")) }) test_that("non-functions are not generics", { a <- TRUE b <- NULL c <- data.frame() expect_false(is_s3_generic("a")) expect_false(is_s3_generic("b")) expect_false(is_s3_generic("c")) }) test_that("user defined generics & methods detected", { my_method <- function(x) UseMethod("mymethod") my_method.character <- function(x) x expect_true(is_s3_generic("my_method")) expect_true(is_s3_method("my_method.character")) }) test_that("methods for group generics detected", { Ops.myclass <- function(x) x expect_false(is_s3_generic("Ops.myclass")) expect_true(is_s3_method("Ops.myclass")) }) test_that("user defined generics detected even if use non-standard", { my_method <- function(x) { x <- 1 if (x > 2) UseMethod("mymethod") } expect_true(is_s3_generic("my_method")) }) test_that("user defined functions override primitives", { c <- function(x) x + 1 c.test <- function(x) x + 3 expect_false(is_s3_generic("c")) expect_false(is_s3_method("c")) }) test_that("@method overrides auto-detection", { out <- parse_text(" #' @export #' @method all.equal data.frame all.equal.data.frame <- function(...) 1 ")[[1]] expect_equal(s3_method_info(out$object$value), c("all.equal", "data.frame")) }) roxygen2/tests/testthat/test-markdown.R0000644000176200001440000003427614047225737020002 0ustar liggesusers# code -------------------------------------------------------------------- test_that("backticks are converted to \\code & \\verb", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some `code` included. `More code.` #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some \\code{code} included. \\verb{More code.} foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("code blocks work", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description #' #' Details with a code block: #' ``` #' x <- 1:10 %>% #' multiply_by(10) %>% #' add(42) #' ``` #' Normal text again. #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description #' #' Details with a code block:\\preformatted{x <- 1:10 \\%>\\% #' multiply_by(10) \\%>\\% #' add(42) #' } #' #' Normal text again. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("code block with language creates HTML tag", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description #' #' Details with a code block: #' ```r #' x <- 1:10 %>% #' multiply_by(10) %>% #' add(42) #' ``` #' Normal text again. #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description #' #' Details with a code block:\\if{html}{\\out{
}}\\preformatted{x <- 1:10 \\%>\\% #' multiply_by(10) \\%>\\% #' add(42) #' }\\if{html}{\\out{
}} #' #' Normal text again. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("inline code escapes %", { expect_equal(markdown("`5%`"), "\\verb{5\\%}") expect_equal(markdown("`'5%'`"), "\\code{'5\\%'}") expect_equal(markdown("`%*%`"), "\\code{\\%*\\%}") }) test_that("inline verbatim escapes Rd special chars", { expect_equal(markdown("`{`"), "\\verb{\\{}") expect_equal(markdown("`}`"), "\\verb{\\}}") expect_equal(markdown("`\\`"), "\\verb{\\\\}") }) test_that("special operators get \\code{}, not \\verb{}", { expect_equal(markdown("`if`"), "\\code{if}") }) test_that("code blocks escape %", { expect_equal( markdown("```\n1:10 %>% mean()\n```"), "\\preformatted{1:10 \\%>\\% mean()\n}" ) }) test_that("inline code works with < and >", { out <- roc_proc_text(rd_roclet(), " #' `SELECT FROM ` #' @md f <- function() 1 ")[[1]] expect_equal(out$get_value("title"), "\\verb{SELECT FROM
}") }) # lists ------------------------------------------------------------------- test_that("itemized lists work", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some #' * itemized #' * list #' #' And then another one: #' * item 1 #' * item 2 #' * item 3 #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some #' \\itemize{ #' \\item itemized #' \\item list #' } #' #' And then another one: #' \\itemize{ #' \\item item 1 #' \\item item 2 #' \\item item 3 #' } foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("numbered lists work", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some #' 1. numbered #' 2. list #' #' And then another one: #' 1. item 1 #' 1. item 2 #' 1. item 3 #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some #' \\enumerate{ #' \\item numbered #' \\item list #' } #' #' And then another one: #' \\enumerate{ #' \\item item 1 #' \\item item 2 #' \\item item 3 #' } foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("nested lists are OK", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some #' 1. numbered #' * itemized #' * sublist #' 2. list #' #' And then another one: #' * item 1 #' * item 2 #' * sublist #' * within #' * item 3 #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some #' \\enumerate{ #' \\item numbered #' \\itemize{ #' \\item itemized #' \\item sublist #' } #' \\item list #' } #' #' And then another one: #' \\itemize{ #' \\item item 1 #' \\item item 2 #' \\itemize{ #' \\item sublist #' \\item within #' } #' \\item item 3 #' } #' @md foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) # tables ------------------------------------------------------------------ test_that("can convert table to Rd", { txt <- " | x | y | | --- | --- | | 1 | 2 | | x | y | | :-: | --: | | 1 | 2 | | x | y | | ----- | --------- | | 1 _2_ | 3 *4* `5` | " txt <- gsub("\n ", "\n", txt) tables <- strsplit(txt, "\n\n")[[1]] verify_output( test_path("test-markdown-table.txt"), { for (table in tables) { cat_line(table) cat_line(markdown(table)) cat_line() } } ) }) # inline formatting ------------------------------------------------------- test_that("emphasis works", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some _emphasis_ included. _More emph._ #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some \\emph{emphasis} included. \\emph{More emph.} foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("strong (bold) text works", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some **bold** included. **More bold.** #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some \\strong{bold} included. \\strong{More bold.} foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("markdown links are converted", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see [http://acme.com]() for details. #' And here is a named link: [igraph](http://igraph.org). #' Here is another kind of link: . #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see \\url{http://acme.com} for details. #' And here is a named link: \\href{http://igraph.org}{igraph}. #' Here is another kind of link: \\url{https://log.r-hub.io}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("images are recognized", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description #' #' Details with a plot: ![](example.jpg \"Plot title\") #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description #' #' Details with a plot: \\figure{example.jpg}{Plot title} foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("markdown is parsed in all fields where it is supported", { out1 <- roc_proc_text(rd_roclet(), " #' @title Title **with bold** #' #' @description Description **with bold** #' #' @details Details **with bold** #' #' @references References **with bold** #' #' @note Note **with bold** #' #' @seealso See also **with bold** #' #' @return Return **with bold** #' #' @author Author **with bold** #' #' @section Foobar: #' With some **bold text**. #' #' @format Format **with bold** #' #' @source Source **with bold** #' #' @param param Param **with bold** #' #' @slot slot Slot **with bold** #' #' @field field Field **with bold** #' #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' @title Title \\strong{with bold} #' #' @description Description \\strong{with bold} #' #' @details Details \\strong{with bold} #' #' @references References \\strong{with bold} #' #' @note Note \\strong{with bold} #' #' @seealso See also \\strong{with bold} #' #' @return Return \\strong{with bold} #' #' @author Author \\strong{with bold} #' #' @section Foobar: #' With some \\strong{bold text}. #' #' @format Format \\strong{with bold} #' #' @source Source \\strong{with bold} #' #' @param param Param \\strong{with bold} #' #' @slot slot Slot \\strong{with bold} #' #' @field field Field \\strong{with bold} foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("markdown emphasis is ok", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some *keywords* included. #' So far so good. \\preformatted{ *these are not #' emphasised*. Or are they? #' } #' @md foo <- function() {}")[[1]] desc1 <- "Description with some \\emph{keywords} included. So far so good. \\preformatted{ *these are not emphasised*. Or are they? }" expect_equal(out1$get_section("description")[[2]], desc1) }) test_that("% is automatically escaped", { expect_equal(markdown("5%"), "5\\%") }) test_that("Escaping is kept", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description. It has \\rd \\commands. #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description. It has \\rd \\commands. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("Do not pick up `` in arguments \\item #519", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description. #' #' @param `_arg1` should not be code. But `this should`. #' @param `_arg2` should not be code, either. `But this.` #' #' @md foo <- function(`_arg1`, `_arg2`) {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description. #' #' @param `_arg1` should not be code. But \\verb{this should}. #' @param `_arg2` should not be code, either. \\verb{But this.} #' foo <- function(`_arg1`, `_arg2`) {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("unhandled markdown generates warning", { text <- " #' Title #' #' > block quotes do not work, #' > sadly #' #' Blabla #' @md #' @name x NULL " expect_warning(roc_proc_text(rd_roclet(), text), "block quotes") }) test_that("level 1 heading in markdown generates warning in some tags", { text <- " #' Title #' #' @seealso this and that #' # This is not good #' #' Blabla #' @md #' @name x NULL " expect_warning( roc_proc_text(rd_roclet(), text), "level 1 markdown headings" ) }) test_that("level >2 markdown headings work in @description", { text <- " #' Title #' #' @description #' ## This is good #' yes #' #' @details #' Blabla #' @md #' @name x NULL " out <- roc_proc_text(rd_roclet(), text)[[1]] expect_equal_strings( out$get_value("description"), "\\subsection{This is good}{\n\nyes\n}" ) }) test_that("level >2 markdown headings work in @details", { text <- " #' Title #' #' Description. #' #' @details #' ## Heading 2 #' ### Heading 3 #' Text. #' @md #' @name x NULL " out <- roc_proc_text(rd_roclet(), text)[[1]] expect_equal_strings( out$get_value("details"), "\\subsection{Heading 2}{\n\\subsection{Heading 3}{\n\nText.\n}\n\n}" ) }) test_that("level >2 markdown headings work in @return", { text <- " #' Title #' #' Description. #' #' @return Even this #' ## Can have a subsection. #' Yes. #' @md #' @name x NULL " out <- roc_proc_text(rd_roclet(), text)[[1]] expect_equal_strings( out$get_value("value"), "Even this\n\\subsection{Can have a subsection.}{\n\nYes.\n}" ) }) test_that("level 1 heading in @details", { text1 <- " #' Title #' #' Description. #' #' @details #' Leading text goes into details. #' # This is its own section #' ## Can have a subsection #' Yes. #' # Another section #' With text. #' @md #' @name x NULL " out1 <- roc_proc_text(rd_roclet(), text1)[[1]] text2 <- " #' Title #' #' Description. #' @details #' Leading text goes into details. #' @section This is its own section:\\subsection{Can have a subsection}{ #' #' Yes. #' } #' #' @section Another section:With text. #' @name x NULL " out2 <- roc_proc_text(rd_roclet(), text2)[[1]] # make sure sections are in the same order expect_equal(sort(names(out1$sections)), sort(names(out2$sections))) out2$sections <- out2$sections[names(out1$sections)] expect_equivalent_rd(out1, out2) }) test_that("headings and empty sections", { text1 <- " #' Title #' #' Description. #' #' @details #' # This is its own section #' With text. #' @md #' @name x NULL " out1 <- roc_proc_text(rd_roclet(), text1)[[1]] expect_false("details" %in% names(out1$fields)) }) test_that("markdown() on empty input", { expect_identical(markdown(""), "") expect_identical(markdown(" "), "") expect_identical(markdown("\n"), "") }) test_that("markup in headings", { text1 <- " #' Title #' #' Description. #' #' @details #' Leading text goes into details. #' # Section with `code` #' ## Subsection with **strong** #' Yes. #' @md #' @name x NULL " out1 <- roc_proc_text(rd_roclet(), text1)[[1]] expect_equal( out1$get_value("section"), list( title = "Section with \\code{code}", content = paste( sep = "\n", "\\subsection{Subsection with \\strong{strong}}{", "", "Yes.", "}" ) ) ) }) roxygen2/tests/testthat/collate/0000755000176200001440000000000014115763566016472 5ustar liggesusersroxygen2/tests/testthat/collate/undershorts.R0000644000176200001440000000000513523072405021153 0ustar liggesusersNULL roxygen2/tests/testthat/collate/tie.R0000644000176200001440000000003113523072405017353 0ustar liggesusers#' @include shirt.R NULL roxygen2/tests/testthat/collate/jacket.R0000644000176200001440000000005213523072405020036 0ustar liggesusers#' @include tie.R #' @include belt.R NULL roxygen2/tests/testthat/collate/watch.R0000644000176200001440000000001513523072405017702 0ustar liggesusersNULL x <- 2 roxygen2/tests/testthat/collate/belt.R0000644000176200001440000000013613523072405017526 0ustar liggesusers# The space before @ is missing on purpose (#342). #'@include pants.R #'@include shirt.R NULL roxygen2/tests/testthat/collate/shoes.R0000644000176200001440000000010713523072405017717 0ustar liggesusers#' @include socks.R #' @include undershorts.R #' @include pants.R NULL roxygen2/tests/testthat/collate/shirt.R0000644000176200001440000000000513523072405017724 0ustar liggesusersNULL roxygen2/tests/testthat/collate/pants.R0000644000176200001440000000003713523072405017725 0ustar liggesusers#' @include undershorts.R NULL roxygen2/tests/testthat/collate/socks.R0000644000176200001440000000000513523072405017715 0ustar liggesusersNULL roxygen2/tests/testthat/test-safety.R0000644000176200001440000000100213540202201017402 0ustar liggesuserstest_that("determine if file is autogenerated", { expect_true(made_by_roxygen("made-by-roxygen/with-header.Rd")) expect_false(made_by_roxygen("made-by-roxygen/without-header.Rd")) expect_false(made_by_roxygen("made-by-roxygen/empty.Rd")) expect_true(check_made_by(made_by("#"))) expect_false(check_made_by(character())) }) test_that("roxygenize stops without side effects if no DESCRIPTION found", { path <- test_path("no-desc") expect_error(first_time(path), "must include a DESCRIPTION file") }) roxygen2/tests/testthat/test-rd-usage.R0000644000176200001440000002123513631734464017656 0ustar liggesuserstest_that("@usage overrides default", { out <- roc_proc_text(rd_roclet(), " #' A #' @usage a(a=2) a <- function(a=1) {}")[[1]] expect_equal(out$get_value("usage"), rd("a(a=2)")) }) test_that("@usage overrides default for @docType data", { out <- roc_proc_text(rd_roclet(), " #' Title. #' #' @name abc #' @docType data #' @usage data(abc) NULL")[[1]] expect_equal(out$get_value("usage"), rd("data(abc)")) }) test_that("@usage NULL suppresses default usage", { out <- roc_proc_text(rd_roclet(), " #' A #' @usage NULL a <- function(a=1) {}")[[1]] expect_equal(out$get_value("usage"), NULL) }) test_that("quoted topics have usage statements", { out <- roc_proc_text(rd_roclet(), " #' Title. \"f\" <- function(a = 1, b = 2, c = a + b) {}")[[1]] expect_equal(out$get_value("usage"), rd("f(a = 1, b = 2, c = a + b)")) expect_equal(out$get_rd("usage"), "\\usage{\nf(a = 1, b = 2, c = a + b)\n}") }) # Escaping -------------------------------------------------------------------- test_that("usage escaping preserved when combined", { out <- roc_proc_text(rd_roclet(), " #' Foo foo <- function(x = '%') x #' @rdname foo bar <- function(y = '%') y ")[[1]] expect_is(out$get_value("usage"), "rd") }) test_that("default usage not double escaped", { out <- roc_proc_text(rd_roclet(), " #' Regular mean.foo <- function(x) 'foo' ")[[1]] expect_equal(out$get_rd("usage"), "\\usage{\n\\method{mean}{foo}(x)\n}") }) test_that("% and \\ are escaped in usage", { out <- roc_proc_text(rd_roclet(), " #' Title. a <- function(a='%\\\\') {}")[[1]] expect_equal(out$get_value("usage"), escape('a(a = "%\\\\")')) expect_equal(out$get_rd("usage"), "\\usage{\na(a = \"\\%\\\\\\\\\")\n}") }) test_that("% and \\ not escaped in manual usage", { out <- roc_proc_text(rd_roclet(), " #' Title. #' @usage %\\ a <- function(a) {} ")[[1]] expect_equal(out$get_value("usage"), rd('%\\')) expect_equal(out$get_rd("usage"), '\\usage{\n%\\\n}') }) test_that("Special vars removed in rc methods usage", { out <- roc_proc_text(rd_roclet(), " #' Class Blob ABCD <- setRefClass('ABC', methods = list( draw = function(x = 1) { \"2\" x }) ) ")[[1]] expect_equal(out$get_value("rcmethods"), list("draw(x = 1)" = "2")) }) # object_usage ------------------------------------------------------------ test_that("usage captured from formals", { expect_equal( call_to_usage(f <- function() {}), "f()" ) expect_equal( call_to_usage(f <- function(a = 1) {}), "f(a = 1)" ) }) test_that("argument containing function is generates correct usage", { expect_equal( call_to_usage(f <- function(a = function(x) 1) {}), "f(a = function(x) 1)" ) }) test_that("backticks retained when needed", { expect_equal( call_to_usage(f <- function(`_a`) {}), "f(`_a`)" ) expect_equal( call_to_usage(`-f` <- function(x) {}), "`-f`(x)" ) }) test_that("% escaped when not in infix function", { expect_equal( call_to_usage(`%foo%bar` <- function(x, table) {}), "`\\%foo\\%bar`(x, table)" ) expect_equal( call_to_usage(`%foo%bar<-` <- function(x, value) {}), "`\\%foo\\%bar`(x) <- value" ) }) test_that("default usage formats data correctly", { expect_equal( call_to_usage(hello <- 1), "hello" ) }) test_that("default usage formats replacement functions correctly", { expect_equal( call_to_usage(`f<-` <- function(x, value) {}), "f(x) <- value" ) expect_equal( call_to_usage(`f<-` <- function(x, y, value) {}), "f(x, y) <- value" ) }) test_that("default usage formats infix functions correctly", { expect_equal( call_to_usage("%.%" <- function(a, b) {}), "a \\%.\\% b" ) # even if it contains <- expect_equal( call_to_usage("%<-%" <- function(a, b) {}), "a \\%<-\\% b" ) }) test_that("default usage formats S3 methods correctly", { expect_equal( call_to_usage(mean.foo <- function(x) {}), "\\method{mean}{foo}(x)" ) expect_equal( call_to_usage(mean.function <- function(x) {}), "\\method{mean}{`function`}(x)" ) expect_equal( call_to_usage("+.foo" <- function(x, b) {}), "\\method{+}{foo}(x, b)" ) expect_equal( call_to_usage("%%.foo" <- function(x, b) {}), "\\method{\\%\\%}{foo}(x, b)" ) expect_equal( call_to_usage("[<-.foo" <- function(x, value) {}), "\\method{[}{foo}(x) <- value" ) }) test_that("S4 classes have no default usage", { expect_equal( call_to_usage({ setClass("Foo") }), character() ) }) test_that("default usage correct for S4 generics", { expect_equal( call_to_usage({ setGeneric("foo", function(x, y) {}) }), "foo(x, y)" ) }) test_that("default usage correct for S4 methods", { expect_equal( call_to_usage({ setClass("Foo") setMethod("sum", "Foo", function(x, ..., na.rm = FALSE) {}) }), "\\S4method{sum}{Foo}(x, ..., na.rm = FALSE)" ) expect_equal( call_to_usage({ setClass("Foo") setMethod("+", "Foo", function(e1, e2) "foo") }), "\\S4method{+}{Foo,ANY}(e1, e2)" ) expect_equal( call_to_usage({ setClass("Foo") setMethod("[<-", "Foo", function(x, i, j, ..., value) "foo") }), "\\S4method{[}{Foo}(x, i, j, ...) <- value" ) expect_equal( call_to_usage({ setGeneric("%&&%", function(x, y) standardGeneric("%&&%")) setMethod("%&&%", signature("logical", "logical"), function(x, y) {}) }), "\\S4method{\\%&&\\%}{logical,logical}(x, y)" ) }) test_that("default usage correct for S4 methods with different args to generic", { expect_equal( call_to_usage({ setGeneric("testfun", function(x, ...) standardGeneric("testfun")) setMethod("testfun", "matrix", function(x, add = FALSE, ...) { x - 1 }) }), "\\S4method{testfun}{matrix}(x, add = FALSE, ...)" ) }) test_that("non-syntactic S4 class names are escaped in usage", { expect_equal( call_to_usage({ setGeneric("rhs", function(x) standardGeneric("rhs")) setMethod("rhs", "<-", function(x) x[[3]]) }), "\\S4method{rhs}{`<-`}(x)" ) }) # Wrapping -------------------------------------------------------------------- test_that("new wrapping style doesn't change unexpectedly", { expect_known_output(file = test_path("test-object-usage-wrap-new.txt"), { cat(call_to_usage({ f <- function(a = ' a', b = ' b', c = ' c', d = ' d') {} }), "\n\n") cat(call_to_usage({ f <- function(a = c('abcdef', 'abcdef', 'abcdef', 'abcdef', 'abcdef', 'abcdef', 'abcdef', 'abcdef', 'abcdef', 'abcdef')) {} }), "\n\n") cat(call_to_usage({ mean.reallyratherquitelongclassname <- function(reallyreatherquitelongargument = 'reallyratherquitelongvalue_____________________') {} }), "\n\n") cat(call_to_usage({ `long_replacement_fun<-` <- function(x, a = 'aaaaaaaaaaaaaaaa', b = 'aaaaaaaaaaaaaaaa', c = 'aaaaaaaaaaaaaaaa', value) {} }), "\n\n") }) }) test_that("old wrapping style doesn't change unexpectedly", { old <- roxy_meta_set("old_usage", TRUE) on.exit(roxy_meta_set("old_usage", old)) expect_known_output(file = test_path("test-object-usage-wrap-old.txt"), { cat(call_to_usage({ f <- function(a = ' a', b = ' b', c = ' c', d = ' d') {} }), "\n\n") cat(call_to_usage({ f <- function(a = c('abcdef', 'abcdef', 'abcdef', 'abcdef', 'abcdef', 'abcdef', 'abcdef', 'abcdef', 'abcdef', 'abcdef')) {} }), "\n\n") cat(call_to_usage({ mean.reallyratherquitelongclassname <- function(reallyreatherquitelongargument = 'reallyratherquitelongvalue_____________________') {} }), "\n\n") cat(call_to_usage({ `long_replacement_fun<-` <- function(x, a = 'aaaaaaaaaaaaaaaa', b = 'aaaaaaaaaaaaaaaa', c = 'aaaaaaaaaaaaaaaa', value) {} }), "\n\n") # breaking works after escapes (#265) cat(call_to_usage({ f <- function( xxxxxxxxxxxxxxxxxx1, xxxxxxxxxxxxxxxxxx2, xxxxxxxxxxxxxxxxxx3, x = "\"'", xxxxxxxxxxxxxxxxxx4, xxxxxxxxxxxxxxxxxx5, xxxxxxxxxxxxxxxxxx6, xxxxxxxxxxxxxxxxxx7 ) {} }), "\n\n") }) }) roxygen2/tests/testthat/testCollateParse/0000755000176200001440000000000013523072405020310 5ustar liggesusersroxygen2/tests/testthat/testCollateParse/DESCRIPTION0000644000176200001440000000062413523072405022020 0ustar liggesusersPackage: testCollateParse Title: Tools to make developing R code easier License: GPL-2 Description: A test to make sure collate field is parsed correctly when it has a file name per line and is indented (#790). This package only has a DESCRIPTION file. Author: Brodie Gaslam Maintainer: Brodie Gaslam Version: 0.1 Collate: 'b.r' 'c.r' roxygen2/tests/testthat/testCollateParse/R/0000755000176200001440000000000013523072405020511 5ustar liggesusersroxygen2/tests/testthat/testCollateParse/R/b.r0000644000176200001440000000002513523072405021112 0ustar liggesusers b <- function() { } roxygen2/tests/testthat/testCollateParse/R/c.r0000644000176200001440000000002513523072405021113 0ustar liggesusers c <- function() { } roxygen2/tests/testthat/test-rd-section.R0000644000176200001440000000217313544473137020216 0ustar liggesuserstest_that("warn if forgotton colom", { expect_warning( roc_proc_text(rd_roclet(), " #' Foo #' #' @section Haz dox #' Here. #' There foo <- function(x = '%') x "), "Section title spans multiple lines" ) }) test_that("@section-s with identical titles are merged", { out <- roc_proc_text(rd_roclet(), " #' Foo #' #' @section Haz dox: Here. #' #' @section TL: DR. foo <- function(x = '%') x #' @rdname foo #' @section RT: FM. #' @section Haz dox: #' Got news. bar <- function(y = '%') y ")[[1]] expect_equal( out$get_section("section"), rd_section_section( c("Haz dox", "TL", "RT"), c(" Here.\n\n\n Got news.", " DR.", " FM.") ) ) }) test_that("@section-s with different titles are kept as they are", { out <- roc_proc_text(rd_roclet(), " #' Foo #' #' @section A: 1 #' @section B: 2 foo <- function(x) x #' @rdname foo #' @section C: 3 bar <- function(x) x ")[[1]] expect_equal( out$get_section("section"), rd_section_section(LETTERS[1:3], c(" 1", " 2", " 3")) ) }) roxygen2/tests/testthat/man-roxygen/0000755000176200001440000000000013540202201017262 5ustar liggesusersroxygen2/tests/testthat/man-roxygen/values.R0000644000176200001440000000005013523072405020713 0ustar liggesusers#' <%= x %> #' @param <%= y %> <%= z %> roxygen2/tests/testthat/test-rd-family.R0000644000176200001440000000550213560327473020031 0ustar liggesuserstest_that("long families are wrapped", { out <- roc_proc_text(rd_roclet(), " #' Title #' @family Long family name #' long_function_name_________________________1 <- function() {} #' Title #' @family Long family name long_function_name_________________________2 <- function() {} #' Title #' @family Long family name #' long_function_name_________________________3 <- function() {} #' Title #' @family Long family name long_function_name_________________________4 <- function() {} ")[[1]] seealso <- out$get_value("seealso") expect_true(grepl("^Other Long family name:", seealso)) expect_equal(str_count(seealso, "\n"), 3) }) test_that("special names escaped in family tag", { out <- roc_proc_text(rd_roclet(), " #' Title #' @family Long family name f <- function() {} #' Title #' @family Long family name '%+%' <- function(a, b) {} ")[[1]] seealso <- out$get_value("seealso") expect_true(grepl("^Other Long family name:", seealso)) expect_match(seealso, "\\\\%\\+\\\\%") }) test_that("family links to name only, not all aliases", { out <- roc_proc_text(rd_roclet(), " #' Title #' @aliases f2 f3 #' #' @family many aliases f <- function() {} #' Title #' @aliases g2 g3 #' #' @family many aliases g <- function() {} ")[[1]] seealso <- out$get_value("seealso") expect_true(grepl("^Other many aliases:", seealso)) expect_equal(str_count(seealso, fixed("\\code{\\link")), 1) }) test_that("families listed in same order as input", { out <- roc_proc_text(rd_roclet(), " #' foo #' @family a foo <- function() {} #' foo #' @family b #' @family a bar <- function() {} #' foo #' @family b baz <- function() {} ")[[2]] seealso <- out$get_value("seealso") expect_match(seealso[1], "^Other b") expect_match(seealso[2], "^Other a") }) test_that("only functions get () suffix", { out <- roc_proc_text(rd_roclet(), " #' foo #' @family a foo <- function() {} #' bar #' @family a bar <- 1:10 ") expect_equal(out[[1]]$get_value("seealso"), "Other a: \n\\code{\\link{bar}}") expect_equal(out[[2]]$get_value("seealso"), "Other a: \n\\code{\\link{foo}()}") }) test_that("family also included in concepts", { out <- roc_proc_text(rd_roclet(), " #' foo #' @family a foo <- function() {} ")[[1]] expect_equal(out$get_value("concept"), "a") }) test_that("custom family prefixes can be set", { owd <- setwd(tempdir()) on.exit(setwd(owd), add = TRUE) roxy_meta_set("rd_family_title", list(a = "Custom prefix: ")) out <- roc_proc_text(rd_roclet(), " #' foo #' @family a foo <- function() {} #' bar #' @family a bar <- function() {} ")[[1]] expect_match(out$get_value("seealso"), "^Custom prefix:") }) roxygen2/tests/testthat/description-example.txt0000644000176200001440000000213713523072405021552 0ustar liggesusersPackage: foobar Version: 1.0 License: GPL (>= 2) Description: The package describe herein is fake, entirely manufactured, utterly contrived, and wholly nonexistent. In no way does it reflect the work, endorsement, or even approval of the creators named, nor is it meant to. It contains no functions, which even if they did exist would take no arguments, and even if such hypothetical functions did exist and took arguments still wouldn't return anything. Title: A fake package for testing purposes Author: Alan Turing , Alonzo Church , Charles Babbage , Ada Lovelace , Grace Murray Hopper Maintainer: Alan Turing Imports: stringr (>= 0.5), tools, brew Suggests: testthat Depends: digest Collate: 'cache.R' 'description.R' 'parse.R' 'parse-preref.R' 'parse-srcref.R' 'parse-registry.R' 'rd-file-api.R' 'rd-tag-api.R' 'roclet-collate.R' 'roclet-namespace.R' 'roclet-rd.R' 'roclet.R' 'roxygen.R' 'roxygenize.R' 'topo-sort.R' 'utils.R' 'template.R' 'rd-parse.R' roxygen2/tests/testthat/templates/0000755000176200001440000000000014115763566017045 5ustar liggesusersroxygen2/tests/testthat/templates/man-roxygen/0000755000176200001440000000000014115763566021311 5ustar liggesusersroxygen2/tests/testthat/templates/man-roxygen/UCase.R0000644000176200001440000000000013540202201022371 0ustar liggesusersroxygen2/tests/testthat/templates/man-roxygen/lcase.r0000644000176200001440000000000013540202201022520 0ustar liggesusersroxygen2/tests/testthat/templates/man/0000755000176200001440000000000014116067732017611 5ustar liggesusersroxygen2/tests/testthat/templates/man/roxygen/0000755000176200001440000000000014115763566021313 5ustar liggesusersroxygen2/tests/testthat/templates/man/roxygen/templates/0000755000176200001440000000000013540202201023260 5ustar liggesusersroxygen2/tests/testthat/templates/man/roxygen/templates/new-path.R0000644000176200001440000000005013540202201025121 0ustar liggesusers#' <%= x %> #' @param <%= y %> <%= z %> roxygen2/tests/testthat/test-object-import.R0000644000176200001440000000304713675431774020734 0ustar liggesuserstest_that("exporting a call to :: produces re-exports documentation", { out <- roc_proc_text(rd_roclet(), " #' @export testthat::auto_test")[[1]] expect_equal( out$get_section("reexport"), rd_section_reexport("testthat", "auto_test") ) expect_equal(out$get_value("title"), "Objects exported from other packages") expect_equal(out$get_value("keyword"), "internal") verify_output(test_path("test-object-import.txt"), cat(format(out))) }) test_that("multiple re-exports are combined", { out <- roc_proc_text(rd_roclet(), " #' @export testthat::expect_lt #' @export testthat::expect_gt ")[[1]] expect_equal( out$get_section("reexport"), rd_section_reexport(c("testthat", "testthat"), c("expect_lt", "expect_gt")) ) }) test_that("description generated correctly", { roc <- rd_roclet() out <- roc_proc_text(rd_roclet(), " #' @importFrom magrittr %>% #' @export magrittr::`%>%` ")[[1]] expect_null(out$get_section("description")) }) test_that("can't set description and re-export", { expect_warning( out <- roc_proc_text(rd_roclet(), " #' @description NOPE #' @export magrittr::`%>%` "), "Can't use description when re-exporting" ) expect_length(out, 0) }) test_that("warnings for unknown packages and objects", { expect_warning( format(rd_section_reexport("11papaya", "fun")), "[uU]navailable package in re-export" ) expect_warning( format(rd_section_reexport("stringr", "12345543221")), "[uU]nknown topic in re-export" ) }) roxygen2/tests/testthat/test-namespace.R0000644000176200001440000002102614115761547020101 0ustar liggesuserstest_that("end-to-end NAMESPACE generation works", { expect_output(roxygenise(test_path("testNamespace"), "namespace", clean = TRUE)) ns <- read_lines(test_path("testNamespace/NAMESPACE")) expect_length(ns, 4) }) # @export ----------------------------------------------------------------- test_that("export quote object name appropriate", { out <- roc_proc_text(namespace_roclet(), "#' @export\na <- function(){}") expect_equal(out, 'export(a)') out <- roc_proc_text(namespace_roclet(), "#' @export\n`+` <- function(){}") expect_equal(out, 'export("+")') out <- roc_proc_text(namespace_roclet(), "#' @export\n`\\`` <- function(){}") expect_equal(out, 'export("`")') }) test_that("export parameter overrides default", { out <- roc_proc_text(namespace_roclet(), "#' @export b\na <- function(){}") expect_equal(out, 'export(b)') }) test_that("multiple export parameters generate multiple exports", { out <- roc_proc_text(namespace_roclet(), " #' @export a b a <- function(){}") expect_equal(out, c('export(a)', 'export(b)')) }) test_that("export trimmed before line test", { out <- roc_proc_text(namespace_roclet(), " #' @export #' a <- function(){}") expect_equal(out, 'export(a)') }) test_that("export detects S4 class", { out <- roc_proc_text(namespace_roclet(), "#' @export\nsetClass('a')") expect_equal(out, 'exportClasses(a)') }) test_that("export detects S4 generic", { out <- roc_proc_text(namespace_roclet(), " #' @export setGeneric('foo', function(x) standardGeneric('foo')) ") expect_equal(out, 'export(foo)') }) test_that("export detects S3 method", { out <- roc_proc_text(namespace_roclet(), "#' @export\nmean.foo <- function(x) 'foo'") expect_equal(out, 'S3method(mean,foo)') }) test_that("export handles non-syntactic names", { out <- roc_proc_text(namespace_roclet(), " #' @export `mean.foo-bar` <- function(x) 'foo' ") expect_equal(out, "S3method(mean,\"foo-bar\")") out <- roc_proc_text(namespace_roclet(), " `foo-bar` <- function(x) UseMethod('foo-bar') #' @export `foo-bar.integer` <- function(x) 'foo' ") expect_equal(out, "S3method(\"foo-bar\",integer)") }) test_that("@exportS3method generatedsS3method()", { out <- roc_proc_text(namespace_roclet(), "#' @exportS3Method mean.foo <- function(x) 'foo' ") expect_equal(out, "S3method(mean,foo)") out <- roc_proc_text(namespace_roclet(), "#' @exportS3Method base::mean mean.foo <- function(x) 'foo' ") expect_equal(out, "S3method(base::mean,foo)") expect_warning( roc_proc_text(namespace_roclet(), "#' @exportS3Method base::mean NULL "), "an S3 method" ) out <- roc_proc_text(namespace_roclet(), "#' @exportS3Method base::mean foo NULL ") expect_equal(out, "S3method(base::mean,foo)") }) test_that("exportClass overrides default class name", { out <- roc_proc_text(namespace_roclet(), "#' @exportClass b\nsetClass('a')") expect_equal(out, 'exportClasses(b)') }) test_that("export detects method name", { out <- roc_proc_text(namespace_roclet(), " #' @export\n setMethod('max', 'a', function(x, ...) x[1])") expect_equal(out, 'exportMethods(max)') }) test_that("export method escapes if needed", { out <- roc_proc_text(namespace_roclet(), " setGeneric('x<-', function(x, value) standardGeneric('x<-')) #' @export\n setMethod('x<-', 'a', function(x, value) value)") expect_equal(out, 'exportMethods("x<-")') }) test_that("export uses name if no object present", { out <- roc_proc_text(namespace_roclet(), " #' Title #' #' @export #' @name x NULL ") expect_equal(out, 'export(x)') }) test_that("default export uses exportClass for RC objects", { out <- roc_proc_text(namespace_roclet(), " #' Title #' #' @export x <- setRefClass('X') ") expect_equal(out, 'exportClasses(X)') }) test_that("exportMethod overrides default method name", { out <- roc_proc_text(namespace_roclet(), " #' @exportMethod c setMethod('max', 'a', function(x, ...) x[1])") expect_equal(out, 'exportMethods(c)') }) test_that("other namespace tags produce correct output", { out <- roc_proc_text(namespace_roclet(), " #' @exportPattern test #' @import test #' @importFrom test test1 test2 #' @importClassesFrom test test1 test2 #' @importMethodsFrom test test1 test2 NULL") expect_equal(sort(out), sort(c( "exportPattern(test)", "import(test)", "importFrom(test,test1)", "importFrom(test,test2)", "importClassesFrom(test,test1)", "importClassesFrom(test,test2)", "importMethodsFrom(test,test1)", "importMethodsFrom(test,test2)" ))) }) test_that("poorly formed importFrom throws error", { expect_warning(roc_proc_text(namespace_roclet(), " #' @importFrom test NULL "), "needs at least 2 words") }) test_that("multiline importFrom parsed correctly", { out <- roc_proc_text(namespace_roclet(), " #' @importFrom test test1 #' test2 NULL ") expect_equal(sort(out), sort(c( "importFrom(test,test1)", "importFrom(test,test2)" ))) }) test_that("useDynLib imports only selected functions", { out <- roc_proc_text(namespace_roclet(), " #' @useDynLib test #' @useDynLib test a #' @useDynLib test a b NULL") expect_equal(sort(out), sort( c("useDynLib(test)", "useDynLib(test,a)", "useDynLib(test,b)"))) }) test_that("useDynLib doesn't quote if comma present", { out <- roc_proc_text(namespace_roclet(), " #' @useDynLib test, .registration = TRUE NULL") expect_equal(sort(out), "useDynLib(test, .registration = TRUE)") }) test_that("empty NAMESPACE generates zero-length vector", { base_path <- test_path("empty") env <- pkgload::load_all(base_path)$env blocks <- parse_package(base_path, env = env) results <- roclet_process(namespace_roclet(), blocks, env = env, base_path) expect_equal(results, character()) }) # Raw --------------------------------------------------------------------- test_that("rawNamespace must be valid code", { expect_warning( roc_proc_text(namespace_roclet(), " #' @rawNamespace if() { #' @name a NULL"), "code failed to parse" ) }) test_that("rawNamespace inserted unchanged", { out <- roc_proc_text(namespace_roclet(), " #' @rawNamespace xyz #' abc NULL") expect_equal(out, "xyz\n abc") }) # @evalNamespace ---------------------------------------------------------- test_that("evalNamespace generates warning when code is invalid", { expect_warning( roc_proc_text(namespace_roclet(), " #' @evalNamespace a + #' @name a #' @title a NULL"), "code failed to parse" # Message generated by tag_code ) }) test_that("evalNamespace generates warning when code raises error", { expect_warning( roc_proc_text(namespace_roclet(), " #' @evalNamespace stop('!') #' @name a #' @title a NULL"), "failed with error" # From block_eval ) }) test_that("evalNamespace generates warning when code doesn't eval to string", { # Not character expect_warning( roc_proc_text(namespace_roclet(), " z <- 10 #' @evalNamespace z * 2 #' @name a #' @title a NULL"), "did not evaluate to a string" # From block_eval ) # NA_character_ not allowed expect_warning( roc_proc_text(namespace_roclet(), " nms <- NA_character_ #' @evalNamespace nms #' @name a #' @title a NULL"), "result contained NA" # From block_eval ) }) test_that("evalNamespace code is inserted when its value is a string", { out1 <- roc_proc_text(namespace_roclet(), " nms <- paste(letters[1:3], collapse = ',') #' @evalNamespace sprintf('export(%s)', nms) #' @name a #' @title a NULL") out2 <- roc_proc_text(namespace_roclet(), " nms <- paste(letters[1:3], collapse = ',') #' @evalNamespace sprintf('export(%s)', #' nms) #' @name a #' @title a NULL") expect_equal(out1, "export(a,b,c)") expect_equal(out2, "export(a,b,c)") }) test_that("evalNamspace can yield a vector", { out <- roc_proc_text(namespace_roclet(), " nms <- letters[1:2] #' @evalNamespace paste0('export(', nms, ')') #' @name a #' @title a NULL") expect_equal(out, c("export(a)", "export(b)")) }) # helpers ----------------------------------------------------------------- test_that("auto_quote behaves as needed", { expect_equal(auto_quote("x"), "x") expect_equal(auto_quote("if"), '"if"') # quotes non-syntactic expect_equal(auto_quote("'if'"), "'if'") # unless already quoted }) roxygen2/tests/testthat/roxygen-block-3-C.Rd0000644000176200001440000000536014115761232020431 0ustar liggesusers> res[[n]] % Generated by roxygen2: do not edit by hand % Please edit documentation in ./roxygen-block-3.R \name{C} \alias{C} \title{Class C} \description{ Class C Description. } \details{ Classs C details. } \section{Super classes}{ \code{\link[roxygen2:A]{roxygen2::A}} -> \code{\link[roxygen2:B]{roxygen2::B}} -> \code{C} } \section{Public fields}{ \if{html}{\out{
}} \describe{ \item{\code{nosuchfield}}{This will warn.} \item{\code{field5}}{C field 5.} \item{\code{duplicatefield}}{Multiple.} \item{\code{duplicatefield}}{times.} } \if{html}{\out{
}} } \section{Active bindings}{ \if{html}{\out{
}} \describe{ \item{\code{nosuchfield}}{This will warn.} \item{\code{active2}}{C binding 2.} \item{\code{active4}}{C binding 4.} \item{\code{active6}}{C binding 6.} \item{\code{duplicate_binding}}{Double.} \item{\code{duplicate_binding}}{Double double.} } \if{html}{\out{
}} } \section{Methods}{ \subsection{Public methods}{ \itemize{ \item \href{#method-meth2}{\code{C$meth2()}} \item \href{#method-meth5}{\code{C$meth5()}} \item \href{#method-undocumented_method}{\code{C$undocumented_method()}} } } \if{html}{ \out{
Inherited methods} \itemize{ \item \out{}\href{../../roxygen2/html/A.html#method-meth3}{\code{roxygen2::A$meth3()}}\out{} \item \out{}\href{../../roxygen2/html/B.html#method-meth1}{\code{roxygen2::B$meth1()}}\out{} \item \out{}\href{../../roxygen2/html/B.html#method-meth4}{\code{roxygen2::B$meth4()}}\out{} } \out{
} } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-meth2}{}}} \subsection{Method \code{meth2()}}{ C method 2. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{C$meth2(Z = 10, ...)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{Z}}{zzzzz} \item{\code{...}}{etc} } \if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-meth5}{}}} \subsection{Method \code{meth5()}}{ C method 5. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{C$meth5()}\if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-undocumented_method}{}}} \subsection{Method \code{undocumented_method()}}{ \subsection{Usage}{ \if{html}{\out{
}}\preformatted{C$undocumented_method()}\if{html}{\out{
}} } } } roxygen2/tests/testthat/roxygen-block-3.R0000644000176200001440000000534513560326573020120 0ustar liggesusers #' Class A #' #' @description #' Class A description. #' #' @details #' Class A details #' #' @param fogbehindme This is not show up in the output at all. #' @param Z zzzzzzz A <- R6::R6Class( "A", public = list( #' @field field1 A field 1. field1 = NULL, #' @description A method 1. #' @examples #' ## Example for meth1 meth1 = function(Z) { }, #' @description Method 2 description. #' @details Method 2 details. #' @param Z Overriding Z argument for meth2. #' @param ... Rest. #' @examples #' ## Example for meth2 meth2 = function(Z = 10, ...) { }, #' @field field2 A field 2. field2 = "foobar", #' @details Method 3 details. #' @param duplicate This one is #' @param duplicate Twice #' @return twice. #' @return really? meth3 = function(duplicate, missing) { }, #' @field field3 A field 3. field3 = "baz" ), active = list( #' @field active1 A binding 1. active1 = function(x) { }, #' @field active2 A binding 2. active2 = function(x) { }, #' @field active3 A binding 2. active3 = function(x) { } ) ) #' Class B #' #' @description #' Class B Description. #' #' @details #' Class B details. B <- R6::R6Class( "B", inherit = A, public = list( #' @field field1 B field 1. field1 = NULL, #' @field field4 B field 4. field4 = NULL, #' @description B method 1. #' @param Z Still zzzzzzzz. meth1 = function(Z) { }, #' @description A method 4. meth4 = function() { } ), active = list( #' @field active1 B binding 1. active1 = function(x) { }, #' @field active4 B binding 4. active4 = function(x) { }, #' @field active5 B binding 5. active5 = function(x) { } ) ) #' Class C #' #' @description #' Class C Description. #' #' @details #' Classs C details. #' #' @field nosuchfield This will warn. C <- R6::R6Class( "C", inherit = B, cloneable = FALSE, public = list( field2 = NULL, #' @description C method 2. #' @param Z zzzzz #' @param ... etc meth2 = function(Z = 10, ...) { }, #' @field field5 C field 5. field5 = "foobar", #' @description C method 5. meth5 = function() { }, undocumented_field = NULL, undocumented_method = function() { }, #' @field duplicatefield Multiple. #' @field duplicatefield times. duplicatefield = NULL ), active = list( #' @field active2 C binding 2. active2 = function(x) { }, #' @field active4 C binding 4. active4 = function(x) { }, #' @field active6 C binding 6. active6 = function(x) { }, undocumented_binding = function(x) { }, #' @field duplicate_binding Double. #' @field duplicate_binding Double double. duplicate_binding = function(x) { } ) ) roxygen2/tests/testthat/test-object-import.txt0000644000176200001440000000064414115761226021336 0ustar liggesusers> cat(format(out)) % Generated by roxygen2: do not edit by hand % Please edit documentation in ./ \docType{import} \name{reexports} \alias{reexports} \alias{auto_test} \title{Objects exported from other packages} \keyword{internal} \description{ These objects are imported from other packages. Follow the links below to see their documentation. \describe{ \item{testthat}{\code{\link[testthat]{auto_test}}} }} roxygen2/tests/testthat/test-rd-name-alias.R0000644000176200001440000000735613542227742020566 0ustar liggesusers# name -------------------------------------------------------------------- test_that("name captured from assignment", { out <- roc_proc_text(rd_roclet(), " #' Title. a <- function() {} ")[[1]] expect_equal(out$get_value("name"), "a") expect_equal(out$get_value("alias"), "a") expect_equal(out$get_value("title"), "Title.") }) test_that("name also captured from assignment by =", { out <- roc_proc_text(rd_roclet(), " #' Title. a = function() {} ")[[1]] expect_equal(out$get_value("name"), "a") expect_equal(out$get_value("alias"), "a") expect_equal(out$get_value("title"), "Title.") }) test_that("`$` not to be parsed as assignee in foo$bar(a = 1)", { out <- roc_proc_text(rd_roclet(), " #' foo object foo <- list(bar = function(a) a) foo$bar(a = 1) ")[[1]] expect_equal(out$get_value("name"), "foo") }) test_that("names escaped, not quoted", { out <- roc_proc_text(rd_roclet(), " #' Title '%a%' <- function(x, y) x + y ")[[1]] expect_equal(out$get_rd("name"), "\\name{\\%a\\%}") }) test_that("quoted names captured from assignment", { out <- roc_proc_text(rd_roclet(), " #' Title. \"myfunction\" <- function(...) {} ")[[1]] expect_equal(out$get_value("name"), "myfunction") expect_equal(out$get_value("alias"), "myfunction") out <- roc_proc_text(rd_roclet(), " #' Title. `myfunction` <- function(...) {} ")[[1]] expect_equal(out$get_value("name"), "myfunction") expect_equal(out$get_value("alias"), "myfunction") out <- roc_proc_text(rd_roclet(), " #' Title. \"my function\" <- function(...) {} ")[[1]] expect_equal(out$get_value("name"), "my function") expect_equal(out$get_value("alias"), "my function") }) test_that("@name overides default", { out <- roc_proc_text(rd_roclet(), " #' A #' @name b a <- function() {} ")[[1]] expect_equal(out$get_value("name"), "b") expect_setequal(out$get_value("alias"), c("a", "b")) }) # alias ------------------------------------------------------------------- test_that("aliases split into pieces", { out <- roc_proc_text(rd_roclet(), " #' @aliases a b #' @title a #' @name a NULL")[[1]] expect_match(out$get_value("alias"), fixed("a"), all = FALSE) expect_match(out$get_value("alias"), fixed("b"), all = FALSE) }) test_that("aliases escaped, not quoted", { out1 <- roc_proc_text(rd_roclet(), " #' @name %a% #' @aliases a #' @title a NULL")[[1]] expect_equal(out1$get_rd("alias"), c("\\alias{\\%a\\%}", "\\alias{a}")) out2 <- roc_proc_text(rd_roclet(), " #' @name a #' @aliases %a% #' @title a NULL")[[1]] expect_equal(out2$get_rd("alias"), c("\\alias{a}", "\\alias{\\%a\\%}")) }) test_that("can use NULL to suppress default aliases", { out <- roc_proc_text(rd_roclet(), " #' @aliases NULL #' @title a #' @name a NULL")[[1]] expect_equal(out$get_value("alias"), character()) }) test_that("aliases get deduplicated", { out <- roc_proc_text(rd_roclet(), " #' @aliases a b a #' @title a #' @name a NULL")[[1]] expect_equal(out$get_rd("alias"), c("\\alias{a}", "\\alias{b}")) }) test_that("aliases get deduplicated with defaults suppressed", { out <- roc_proc_text(rd_roclet(), " #' @aliases NULL b c b #' @title a #' @name a NULL")[[1]] expect_equal(out$get_rd("alias"), c("\\alias{b}", "\\alias{c}")) }) test_that("refclass with assignment gets both aliases", { out <- roc_proc_text(rd_roclet(), " #' Title B3 <- setRefClass('B3') ")[[1]] expect_equal(out$get_value("alias"), c("B3-class", "B3")) }) test_that("refclass gets -class alias", { out <- roc_proc_text(rd_roclet(), " #' Title setRefClass('B2') ")[[1]] expect_equal(out$get_value("alias"), "B2-class") }) roxygen2/tests/testthat/Rd-example-4.txt0000644000176200001440000000002213565514545017740 0ustar liggesusers\dontrun{ 1 + 1 } roxygen2/tests/testthat/test-rd-params.R0000644000176200001440000000246713542230401020022 0ustar liggesuserstest_that("@param documents arguments", { out <- roc_proc_text(rd_roclet(), " #' A #' @param a first #' @param z last a <- function(a=1, z=2) {} ")[[1]] expect_equal(out$get_value("param"), c(a = "first", z = "last")) }) test_that("grouped args get spaces", { out <- roc_proc_text(rd_roclet(), " #' A #' @param a,z Two arguments a <- function(a=1, z=2) {} ")[[1]] expect_match(out$get_rd("param"), "a, z") }) test_that("empty @param generates warning", { expect_warning( roc_proc_text(rd_roclet(), " #' A #' @param #' a <- function() {}"), "requires a value" ) }) test_that("data objects don't get params", { out <- roc_proc_text(rd_roclet(), " #' x #' @rdname xy x <- 'x' ")[[1]] expect_equal(out$get_value("param"), NULL) }) test_that("arguments ordered by usage", { out <- roc_proc_text(rd_roclet(), " #' A #' #' @param y Y #' @param x X #' @rdname rd a <- function(x, y) {} ")[[1]] expect_named(out$get_value("param"), c("x", "y")) }) test_that("multiple arguments ordered by first", { out <- roc_proc_text(rd_roclet(), " #' Title #' #' @param y Y #' @param x,z X,Z #' @param w W b <- function(x, y, z, w) {} ")[[1]] expect_named(out$get_value("param"), c("x,z", "y", "w")) }) roxygen2/tests/testthat/no-desc/0000755000176200001440000000000013523072405016362 5ustar liggesusersroxygen2/tests/testthat/no-desc/NAMESPACE0000644000176200001440000000003713523072405017601 0ustar liggesusersexportPattern("^[[:alpha:]]+") roxygen2/tests/testthat/no-desc/R/0000755000176200001440000000000013523072405016563 5ustar liggesusersroxygen2/tests/testthat/no-desc/R/no-description.R0000644000176200001440000000000513523072405021636 0ustar liggesusersNULL roxygen2/tests/testthat/helper-pkg.R0000644000176200001440000000022513523072405017212 0ustar liggesuserstemp_copy_pkg <- function(pkg) { file.copy(normalizePath(pkg), tempdir(), recursive = TRUE) normalizePath(file.path(tempdir(), basename(pkg))) } roxygen2/tests/testthat/test-rd-inherit-dots-multi.txt0000644000176200001440000000033114115761231022711 0ustar liggesusers> out$get_section("param") \arguments{ \item{...}{ Arguments passed on to \code{\link[=foo]{foo}}, \code{\link[=bar]{bar}} \describe{ \item{\code{x}}{x} \item{\code{y}}{y1} \item{\code{z}}{z} }} } roxygen2/tests/testthat/test-parse.R0000644000176200001440000000055613542150341017247 0ustar liggesuserstest_that("can control processing order with @order", { out <- roc_proc_text(rd_roclet(), " #' @rdname bar #' @details 2 #' @order 2 foo <- function() {} #' @rdname bar #' @details 1 #' @order 1 bar <- function() {} #' @title Title #' @name bar NULL ")[[1]] expect_equal(out$get_value("details"), c("1", "2")) }) roxygen2/tests/testthat/test-load.R0000644000176200001440000000235713544713743017072 0ustar liggesuserstest_that("load_installed retrieves installed package", { skip_if_not(file.exists(test_path("../../DESCRIPTION"))) env <- load_installed(test_path("../..")) expect_identical(env, asNamespace("roxygen2")) }) test_that("can load simple package with load_pkgload()", { env <- load_pkgload(test_path("testRbuildignore")) expect_equal(env_get(env, "a"), 1) }) test_that("can load simple package with load_source()", { env <- load_source(test_path("testRbuildignore")) expect_equal(env_get(env, "a"), 1) }) # find_load_strategy ------------------------------------------------------ test_that("function returned as is", { expect_equal(find_load_strategy(load_installed), load_installed) }) test_that("look up string", { expect_equal(find_load_strategy("installed"), load_installed) expect_equal(find_load_strategy("pkgload"), load_pkgload) expect_equal(find_load_strategy("source"), load_source) expect_error(find_load_strategy("blahblahb"), "Unknown value") }) test_that("NULL uses option", { expect_equal(find_load_strategy(NULL, "installed"), load_installed) }) test_that("informative errors for bad inputs", { expect_error(find_load_strategy(1), "string or function") expect_error(find_load_strategy(NULL, list()), "string") }) roxygen2/tests/testthat/test-block.R0000644000176200001440000001365513544674563017256 0ustar liggesusers # object ------------------------------------------------------------------ test_that("has thoughtful print method", { text <- "#' This is a title #' #' @param x,y A number #' @export f <- function(x, y) x + y " block <- parse_text(text)[[1]] verify_output(test_path("test-block-print.txt"), block) }) # description block ------------------------------------------------------- test_that("title and description taken from first line if only one", { out <- roc_proc_text(rd_roclet(), " #' title #' @name a NULL")[[1]] expect_equal(out$get_value("description"), "title") expect_equal(out$get_value("title"), "title") }) test_that("description taken from multiple titles if merged", { out <- roc_proc_text(rd_roclet(), " #' T1 #' @name a NULL #' T2 #' @name a NULL ")[[1]] expect_equal(out$get_value("title"), c("T1", "T2")) expect_equal(out$get_value("description"), c("T1", "T2")) }) test_that("title, description and details extracted correctly", { out <- roc_proc_text(rd_roclet(), " #' title #' #' description #' #' details #' @name a NULL")[[1]] expect_equal(out$get_value("description"), "description") expect_equal(out$get_value("details"), "details") }) test_that("title taken from first paragraph", { out <- roc_proc_text(rd_roclet(), " #' Description with sentence. #' #' That continueth. #' @name a NULL")[[1]] expect_equal(out$get_value("title"), "Description with sentence.") expect_equal(out$get_value("description"), "That continueth.") }) test_that("@title overrides default title", { out <- roc_proc_text(rd_roclet(), " #' Would be title #' @title Overridden title #' @name a NULL")[[1]] expect_equal(out$get_value("title"), "Overridden title") expect_equal(out$get_value("description"), "Would be title") }) test_that("docs parsed correctly if no blank text", { out <- roc_proc_text(rd_roclet(), " #' @title My title #' @description My description #' @param x value a <- function(x) {}")[[1]] expect_equal(out$get_value("title"), "My title") expect_equal(out$get_value("description"), "My description") }) test_that("question mark ends sentence", { out <- roc_proc_text(rd_roclet(), " #' Is a number odd? is.odd <- function(a) {}")[[1]] expect_equal(out$get_value("title"), "Is a number odd?") }) test_that("no ending punctuation does not produce ellipsis", { out <- roc_proc_text(rd_roclet(), " #' Whether a number is odd is.odd <- function(a) {}")[[1]] expect_equal(out$get_value("title"), "Whether a number is odd") }) test_that("details are merged if needed", { out <- roc_proc_text(rd_roclet(), " #' Title #' #' Description #' #' Details1 #' #' Details2 #' #' @details Details3 #' #' Details4 foo <- function(x) {}")[[1]] expect_equal( out$get_value("details"), "Details1\n\nDetails2\n\nDetails3\n\nDetails4" ) }) test_that("whitespace is not detected as details", { expect_silent( out <- roc_proc_text( rd_roclet(), " #' Title #' #' #' Description #' #' #' foo <- function(x) {}" )[[1]] ) expect_null(out$get_value("details")) }) test_that("@description and @details are merged", { out <- roc_proc_text(rd_roclet(), " #' Foo #' #' This. #' #' OBTW. foo <- function(x = '%') x #' @rdname foo #' @description And that. #' @details ORLY? bar <- function(y = '%') y ")[[1]] expect_equal(out$get_value("description"), c("This.", "And that.")) expect_equal(out$get_value("details"), c("OBTW.", "ORLY?")) }) test_that("empty description block is silently removed", { expect_warning( roc_proc_text(rd_roclet(), " #' #' f <- function() {} " ), NA ) }) test_that("description block preserves whitespace", { out <- parse_text(" #' Title #' #' Line 1 #' Line 2 #' #' Line 1 #' Line 2 f <- function() {} " )[[1]] expect_equal(block_get_tag_value(out, "description"), "Line 1\n Line 2") expect_equal(block_get_tag_value(out, "details"), "Line 1\n Line 2") }) test_that("line numbers offset correctly", { out <- parse_text( "#' Title #' #' Line 3 #' Line 4 #' Line 5 #' #' Line 7 #' Line 8 f <- function() {} " )[[1]] expect_equal(out$tags[[1]]$line, 1) expect_equal(out$tags[[2]]$line, 3) expect_equal(out$tags[[3]]$line, 7) }) test_that("even with explicit title/description", { out <- parse_text( "#' Line 1 #' Line 2 #' Line 3 #' #' Line 5 #' Line 6 #' @title This is a title f <- function() {} " )[[1]] expect_equal(out$tags[[1]]$line, 1) expect_equal(out$tags[[2]]$line, 5) expect_equal(out$tags[[3]]$line, 7) }) # evaluate ---------------------------------------------------------------- test_that("evaluation occurs during parsing", { out <- roc_proc_text(rd_roclet(), " foo <- function() c('@name a', '@title a') #' @eval foo() NULL")[[1]] expect_equal(out$get_value("title"), "a") expect_equal(out$filename, "a.Rd") }) test_that("errors are propagated", { expect_warning( roc_proc_text(rd_roclet(), " foo <- function() stop('Uhoh') #' @eval foo() NULL" ), "failed with error" ) }) test_that("must return non-NA string", { expect_warning( roc_proc_text(rd_roclet(), " foo <- function() NA #' @eval foo() NULL" ), "did not evaluate to a string" ) expect_warning( roc_proc_text(rd_roclet(), " foo <- function() NA_character_ #' @eval foo() NULL" ), "result contained NA" ) }) test_that("also works with namespace roclet", { out <- roc_proc_text(namespace_roclet(), " foo <- function() '@export a' #' @eval foo() #' @name a #' @title a NULL") expect_equal(out, "export(a)") }) roxygen2/tests/testthat/test-rd-markdown.R0000644000176200001440000000222313631761325020364 0ustar liggesuserstest_that("generic keys produce expected output", { out <- roc_proc_text(rd_roclet(), " #' @title a #' @note test #' @author test #' @seealso test #' @references test #' @name a NULL")[[1]] expect_equal(out$get_value("references"), "test") expect_equal(out$get_value("note"), "test") expect_equal(out$get_value("seealso"), "test") expect_equal(out$get_value("author"), "test") }) # format ------------------------------------------------------------------ test_that("@format overrides defaults", { out <- roc_proc_text(rd_roclet(), " #' Title #' #' @format abc #' x <- list(a = 1, b = 2)")[[1]] expect_equal(out$get_value("format"), "abc") }) test_that("@format NULL suppresses default usage", { out <- roc_proc_text(rd_roclet(), " #' Title #' #' @format NULL x <- list(a = 1, b = 2)")[[1]] expect_equal(out$get_value("format"), NULL) }) test_that("@format not escaped", { out <- roc_proc_text(rd_roclet(), " #' Title #' @format % x <- list(a = 1, b = 2)")[[1]] expect_equal(out$get_value("format"), "%") expect_equal(out$get_rd("format"), "\\format{\n%\n}") }) roxygen2/tests/testthat/test-rd-include-rmd.R0000644000176200001440000001573214115751770020757 0ustar liggesuserstest_that("markdown file can be included", { skip_if_not(rmarkdown::pandoc_available()) tmp <- tempfile(fileext = ".md") on.exit(unlink(tmp, recursive = TRUE), add = TRUE) cat("List:\n\n* item1\n* item2\n\nInline `code` and _emphasis_.\n", file = tmp) rox <- sprintf(" #' Title #' @includeRmd %s #' @name foobar NULL", tmp) out1 <- roc_proc_text(rd_roclet(), rox)[[1]] out2 <- roc_proc_text(rd_roclet(), " #' @title Title #' @details List: #' \\itemize{ #' \\item item1 #' \\item item2 #' } #' #' Inline \\code{code} and \\emph{emphasis}. #' @name foobar NULL")[[1]] # make sure sections are in the same order expect_equal(sort(names(out1$sections)), sort(names(out2$sections))) out2$sections <- out2$sections[names(out1$sections)] expect_equivalent_rd(out1, out2) }) test_that("markdown with headers", { skip_if_not(rmarkdown::pandoc_available()) tmp <- tempfile(fileext = ".md") on.exit(unlink(tmp, recursive = TRUE), add = TRUE) cat(sep = "\n", file = tmp, "Text at the front", "", "# Header 1", "", "## Header 2", "", "Text", "", "## Header 22", "", "# Header 11", "", "Text again") rox <- sprintf(" #' Title #' @includeRmd %s #' @name foobar NULL", tmp) out1 <- roc_proc_text(rd_roclet(), rox)[[1]] exp_details <- "Text at the front" exp_secs <- list( title = c("Header 1", "Header 11"), content = c( "\\subsection{Header 2}{\n\nText\n}\n\n\\subsection{Header 22}{\n}", "Text again" ) ) expect_equal_strings(out1$get_value("details"), exp_details) expect_equal_strings(out1$get_value("section"), exp_secs) }) test_that("subsection within details", { skip_if_not(rmarkdown::pandoc_available()) tmp <- tempfile(fileext = ".md") on.exit(unlink(tmp, recursive = TRUE), add = TRUE) cat(sep = "\n", file = tmp, "Text at the front", "", "", "## Subsection in details", "", "Some subsection text") rox <- sprintf(" #' Title #' @includeRmd %s #' @name foobar NULL", tmp) out1 <- roc_proc_text(rd_roclet(), rox)[[1]] exp_details <- paste0( "Text at the front", "\\subsection{Subsection in details}{ Some subsection text }" ) expect_equal_strings(out1$get_value("details"), exp_details) }) test_that("links to functions", { skip_if_not(rmarkdown::pandoc_available()) tmp <- tempfile(fileext = ".md") on.exit(unlink(tmp, recursive = TRUE), add = TRUE) cat(sep = "\n", file = tmp, "This is a link: [roxygenize()].", "Another one: [stringr::str_length()]" ) rox <- sprintf(" #' Title #' @includeRmd %s #' @name foobar NULL", tmp) out1 <- roc_proc_text(rd_roclet(), rox)[[1]] exp_details <- paste0( "This is a link: \\code{\\link[=roxygenize]{roxygenize()}}.", "Another one:\n\\code{\\link[stringr:str_length]{stringr::str_length()}}" ) expect_equal_strings(out1$get_value("details"), exp_details) }) test_that("links to functions, with anchors", { skip_if_not(rmarkdown::pandoc_available()) tmp <- tempfile(fileext = ".md") on.exit(unlink(tmp, recursive = TRUE), add = TRUE) cat(sep = "\n", file = tmp, "This is a link: [roxygenize()].", "Another one: [stringr::str_length()]", "", "[roxygenize()]: https://roxygen2.r-lib.org/reference/roxygenize.html", "[stringr::str_length()]: https://stringr.tidyverse.org/reference/str_length.html" ) rox <- sprintf(" #' Title #' @includeRmd %s #' @name foobar NULL", tmp) out1 <- roc_proc_text(rd_roclet(), rox)[[1]] exp_details <- paste0( "This is a link: \\code{\\link[=roxygenize]{roxygenize()}}.", "Another one:\n\\code{\\link[stringr:str_length]{stringr::str_length()}}" ) expect_equal_strings(out1$get_value("details"), exp_details) }) test_that("empty Rmd", { tmp <- tempfile() on.exit(unlink(tmp), add = TRUE) tag <- roxy_tag("includeRmd", tmp) cat("", sep = "", file = tmp) expect_equal(rmd_eval_rd(tmp, tag), structure("", names = "")) cat(" ", sep = "", file = tmp) expect_equal(rmd_eval_rd(tmp, tag), structure("", names = "")) cat("\n", sep = "", file = tmp) expect_equal(rmd_eval_rd(tmp, tag), structure("", names = "")) }) test_that("inline html", { skip_if_not(rmarkdown::pandoc_available()) tmp <- tempfile(fileext = ".md") on.exit(unlink(tmp, recursive = TRUE), add = TRUE) cat(sep = "\n", file = tmp, "Text at the front", "", "", "## Subsection in details", "", "Some subsection text with inline html.") rox <- sprintf(" #' Title #' @includeRmd %s #' @name foobar NULL", tmp) out1 <- roc_proc_text(rd_roclet(), rox)[[1]] exp_details <- paste0( "Text at the front", "\\subsection{Subsection in details}{", "Some subsection text with ", "\\if{html}{\\out{}}inline html\\if{html}{\\out{}}.\n}" ) expect_equal_strings(out1$get_value("details"), exp_details) }) test_that("html block", { skip_if_not(rmarkdown::pandoc_available()) tmp <- tempfile(fileext = ".md") on.exit(unlink(tmp, recursive = TRUE), add = TRUE) cat(sep = "\n", file = tmp, "Text at the front", "", "", "", "Text") rox <- sprintf(" #' Title #' @includeRmd %s #' @name foobar NULL", tmp) out1 <- roc_proc_text(rd_roclet(), rox)[[1]] exp_details <- paste0( "Text at the front", "\\if{html}{\\out{}}\\if{html}{\\out{}}", "Text" ) expect_equal_strings(out1$get_value("details"), exp_details) }) test_that("include as another section", { skip_if_not(rmarkdown::pandoc_available()) tmp <- tempfile(fileext = ".md") on.exit(unlink(tmp, recursive = TRUE), add = TRUE) cat("List:\n\n* item1\n* item2\n\nInline `code` and _emphasis_.\n", file = tmp) rox <- sprintf(" #' Title #' @includeRmd %s description #' @name foobar NULL", tmp) out1 <- roc_proc_text(rd_roclet(), rox)[[1]] out2 <- roc_proc_text(rd_roclet(), " #' @title Title #' @description List: #' \\itemize{ #' \\item item1 #' \\item item2 #' } #' #' Inline \\code{code} and \\emph{emphasis}. #' @name foobar NULL")[[1]] # make sure sections are in the same order expect_equal(sort(names(out1$sections)), sort(names(out2$sections))) out2$sections <- out2$sections[names(out1$sections)] expect_equivalent_rd(out1, out2) }) test_that("order of sections is correct", { skip_if_not(rmarkdown::pandoc_available()) tmp <- tempfile(fileext = ".md") on.exit(unlink(tmp, recursive = TRUE), add = TRUE) cat("# Rmd\n\nList:\n\n* item1\n* item2\n\nInline `code` and _emphasis_.\n", file = tmp) rox <- sprintf(" #' Title #' @description desc #' @details details #' @includeRmd %s #' @section After: #' This is after. #' @section After2: #' This is even more after. #' @name foobar NULL", tmp) out1 <- roc_proc_text(rd_roclet(), rox)[[1]] expect_match(format(out1), "Rmd.*After.*After2") }) roxygen2/tests/testthat/test-utils-rd.R0000644000176200001440000000145614036314227017704 0ustar liggesuserstest_that("href doesn't get extra parens", { expect_equal(rd2text(parse_rd("\\href{a}{b}")), "\\href{a}{b}\n") }) test_that("has_topic() works as you'd expect", { expect_equal(has_topic("abbreviate", "base"), TRUE) expect_equal(has_topic("abbreviateXXXX", "base"), FALSE) expect_equal(has_topic("foo", "PACKAGEDOESNOTEXIST"), FALSE) }) test_that("can tweak links to point to new package", { rd1 <- tweak_links(parse_rd("\\link{abbreviate}"), package = "base") rd2 <- tweak_links(parse_rd("\\link[base]{abbreviate}"), package = "base") rd3 <- tweak_links(parse_rd("\\link[=abbreviate]{abbr}"), package = "base") expect_equal(rd2text(rd1), "\\link[base]{abbreviate}\n") expect_equal(rd2text(rd2), "\\link[base]{abbreviate}\n") expect_equal(rd2text(rd3), "\\link[base:abbreviate]{abbr}\n") }) roxygen2/tests/testthat/test-rd-examples.R0000644000176200001440000000566014036301727020364 0ustar liggesuserstest_that("@example loads from specified files", { out <- roc_proc_text(rd_roclet(), " #' @name a #' @title a #' #' @example Rd-example-1.R #' @example Rd-example-2.R NULL")[[1]] examples <- out$get_value("examples") expect_match(examples, fixed("example <- 'example1'"), all = FALSE) expect_match(examples, fixed("example <- 'example2'"), all = FALSE) }) test_that("@example captures examples (#470)", { out <- roc_proc_text(rd_roclet(), " #' @name a #' @title a #' @examples #' TRUE #' @examples #' FALSE NULL")[[1]] examples <- out$get_value("examples") expect_equal(examples, rd(c("TRUE", "FALSE"))) }) test_that("@examples and @example interleave", { out <- roc_proc_text(rd_roclet(), " #' @name a #' @title a #' @example Rd-example-1.R #' @examples a <- 2 #' @example Rd-example-2.R NULL")[[1]] verify_output(test_path("test-rd-examples-interleave.txt"), { out$get_section("examples") }) }) test_that("@example does not introduce extra empty lines", { out <- roc_proc_text(rd_roclet(), " #' @name a #' @title a #' @example Rd-example-3.R NULL")[[1]] expect_equal(str_count(out$get_value("examples"), "\n"), 1L) }) test_that("@example gives warning if used instead of @examples", { expect_warning( out <- roc_proc_text(rd_roclet(), " #' @name a #' @title a #' @example #' a <- 1 #' a + b NULL")[[1]], "spans multiple lines" ) expect_null(out$get_value("examples")) }) test_that("warns if path doesn't exist", { expect_warning( roc_proc_text(rd_roclet(), " #' @name a #' @title a #' @example this-path-doesnt-exist.R NULL "), "doesn't exist" ) }) test_that("@examplesIf", { out <- roc_proc_text(rd_roclet(), " #' @name a #' @title a #' @examplesIf foo::bar() #' maybe-run-this-code #' @examplesIf foobar() #' and-this NULL")[[1]] verify_output(test_path("test-rd-examplesIf.txt"), { out$get_section("examples") }) }) test_that("% in @examples escaped before matching braces test (#213)", { out <- roc_proc_text(rd_roclet(), " #' @name a #' @title a #' @examples #' {a %% b} NULL")[[1]] expect_equal(out$get_value("examples"), rd("{a \\%\\% b}")) }) # escapes ------------------------------------------------------------------ test_that("only % escaped in @examples", { expect_equal(escape_examples("x %*% y"), rd("x \\%*\\% y")) expect_equal(escape_examples("# \\x"), rd("# \\x")) expect_equal(escape_examples("'34.00\\'"), rd("'34.00\\'")) }) test_that("multi-line macros in @example", { # https://github.com/r-lib/roxygen2/issues/974 out <- roxygen2:::roc_proc_text(roxygen2:::rd_roclet(), " #' @name a #' @title a #' #' @example Rd-example-4.txt NULL")[[1]] expect_equal( format(out$get_section("examples")), "\\examples{\n\\dontrun{\n1 + 1\n}\n}" ) }) roxygen2/tests/testthat/testUtf8Escape/0000755000176200001440000000000013523072405017701 5ustar liggesusersroxygen2/tests/testthat/testUtf8Escape/DESCRIPTION0000644000176200001440000000032113523072405021403 0ustar liggesusersPackage: testUtf8Escape Title: Check that utf8 escapes are round tripped ok License: GPL-2 Description: Author: Hadley Maintainer: Hadley Encoding: UTF-8 Version: 0.1 roxygen2/tests/testthat/testUtf8Escape/R/0000755000176200001440000000000013523072405020102 5ustar liggesusersroxygen2/tests/testthat/testUtf8Escape/R/a.r0000644000176200001440000000007713523072405020511 0ustar liggesusers#' Title #' #' @param b Some label a <- function(b = '7°C') 1 roxygen2/tests/testthat/description-example_2.txt0000644000176200001440000000315513523072405021774 0ustar liggesusersPackage: foobar Version: 2.0 License: GPL (>= 2) Description: The second version of this nonexistent package only differs in that the maintainer decided to edit the fake author information, using some features of the Authors@R field to see if formatting will be preserved, and removing some inexistent authors that did really not contribute anything to the nonsense. Otherwise, the package described herein is still fake, entirely manufactured, utterly contrived, and wholly nonexistent. In no way does it reflect the work, endorsement, or even approval of the creators named, nor is it meant to. It contains no functions, which even if they did exist would take no arguments, and even if such hypothetical functions did exist and took arguments still wouldn't return anything. Title: A fake package for testing purposes Authors@R: c( person("Alan Turing", role = c("auth", "cre", "cph"), email = "alan@turing.fake", comment = c("As this is a fake package, as you may have guessed, authorship" "information should not be taken seriously either."), person("Alonzo Church", role = "ctb", email = "alonzo@church.fake"), person("Grace Murray Hopper", role = "auth", email = "grace@murray-hopper.fake")) Imports: stringr (>= 0.5), tools, brew Suggests: testthat Depends: digest Collate: 'cache.R' 'description.R' 'parse.R' 'parse-preref.R' 'parse-srcref.R' 'parse-registry.R' 'rd-file-api.R' 'rd-tag-api.R' 'roclet-collate.R' 'roclet-namespace.R' 'roclet-rd.R' 'roclet.R' 'roxygen.R' 'roxygenize.R' 'topo-sort.R' 'utils.R' 'template.R' 'rd-parse.R' roxygen2/tests/testthat/empty/0000755000176200001440000000000013523072405016170 5ustar liggesusersroxygen2/tests/testthat/empty/DESCRIPTION0000644000176200001440000000003613523072405017675 0ustar liggesusersPackage: empty Version: 1.0.0 roxygen2/tests/testthat/empty/R/0000755000176200001440000000000013523072405016371 5ustar liggesusersroxygen2/tests/testthat/empty/R/empty-package.R0000644000176200001440000000000513523072405021236 0ustar liggesusersNULL roxygen2/tests/testthat/test-select-args.R0000644000176200001440000000135313540202201020331 0ustar liggesuserstest_that("errors on invalid input", { expect_error(select_args_text(sum, "-xlab:"), "Failed to parse") expect_error(select_args_text(sum, '"a"'), "numbers") f <- function(x, y, z) {} expect_error(select_args_text(f, "-x:z"), "numbers") }) test_that("positive initial values starts from nothing", { f <- function(x, y, z) {} expect_equal(select_args_text(f, "x y"), c("x", "y")) }) test_that("negative initial starts from everything", { f <- function(x, y, z) {} expect_equal(select_args_text(f, "-z"), c("x", "y")) }) test_that("can alternative exclusion and inclusion", { f <- function(x, y, z) {} expect_equal(select_args_text(f, "-z z"), c("x", "y", "z")) expect_equal(select_args_text(f, "z -z"), character()) }) roxygen2/tests/testthat/test-package_files.R0000644000176200001440000000160013540202201020670 0ustar liggesuserstest_that("respects order in Collate (#790)", { expect_equal( package_files('testCollateParse'), normalizePath(c("testCollateParse/R/b.r", "testCollateParse/R/c.r")) ) }) test_that("roxygen ignores files with matching pattern in .Rbuildignore", { test_pkg <- temp_copy_pkg(test_path("testRbuildignore")) on.exit(unlink(test_pkg, recursive = TRUE)) expect_equal(basename(package_files(test_pkg)), c("a.R", "ignore_me.R")) write_lines("^R/ignore_me.R$\n", file.path(test_pkg, ".Rbuildignore")) expect_equal(basename(package_files(test_pkg)), "a.R") }) test_that("roxygen works with empty lines in .Rbuildignore", { test_pkg <- temp_copy_pkg(test_path("testRbuildignore")) on.exit(unlink(test_pkg, recursive = TRUE)) write_lines("^R/ignore_me.R$\n\n.nonexistentfile", file.path(test_pkg, ".Rbuildignore")) expect_equal(basename(package_files(test_pkg)), "a.R") }) roxygen2/tests/testthat/test-rd-s4.R0000644000176200001440000000112013542230162017052 0ustar liggesuserstest_that("@fields creates a new section and lists fields", { out <- roc_proc_text(rd_roclet(), " #' Important class. #' #' @field a field a #' #' @field b field b #' setRefClass('test') ")[[1]] expect_equal(out$get_value("field"), c(a = "field a", b = "field b")) }) test_that("@slot creates a new section and lists slots", { out <- roc_proc_text(rd_roclet(), " #' Important class. #' #' @slot a slot a #' @slot b slot b setClass('test') ")[[1]] expect_equal(out$get_value("slot"), c(a = "slot a", b = "slot b")) }) roxygen2/tests/testthat/test-markdown-code.R0000644000176200001440000000654713675431642020712 0ustar liggesusers test_that("can eval", { out1 <- roc_proc_text(rd_roclet(), " #' @title Title `r 1 + 1` #' @description Description `r 2 + 2` #' @md foo <- function() {}")[[1]] expect_equal(out1$get_value("title"), "Title 2") expect_equal(out1$get_value("description"), "Description 4") }) test_that("uses the same env for a block, but not across blocks", { out1 <- roc_proc_text(rd_roclet(), " #' Title `r foobarxxx123 <- 420` `r foobarxxx123` #' #' Description `r exists('foobarxxx123', inherits = FALSE)` #' @md #' @name dummy NULL #' Title another #' #' Description `r exists('foobarxxx123', inherits = FALSE)` #' @md #' @name dummy2 NULL") expect_equal(out1$dummy.Rd$get_value("title"), "Title 420 420") expect_equal(out1$dummy.Rd$get_value("description"), "Description TRUE") expect_equal(out1$dummy2.Rd$get_value("description"), "Description FALSE") }) test_that("can create markdown markup", { expect_identical( markdown("Description `r paste0('_', 'keyword', '_')`"), "Description \\emph{keyword}" ) }) test_that("can create markdown markup piecewise", { expect_identical( markdown( "Description [`r paste0('https://url]')`](`r paste0('link text')`)" ), "Description \\link{https://url}](link text)" ) }) test_that("NULL creates no text", { expect_identical( markdown("Description --`r NULL`--"), "Description ----" ) }) test_that("various errors", { verify_output(test_path("markdown-code-errors.txt"), { # multi-line inline code block roc_proc_text(rd_roclet(), " #' Title #' #' Description --`r 1 + #' 1`-- #' @md #' @name dummy NULL" )[[1]] # evaluation errors are reported nicely roc_proc_text(rd_roclet(), " #' Title #' #' Description --`r 1 + 'a'`-- #' @md #' @name dummy NULL")[[1]] # parse errors are reported nicely roc_proc_text(rd_roclet(), " #' Title #' #' Description --`r 1 + `-- #' @md #' @name dummy NULL")[[1]] }) }) test_that("interleaving fences and inline code", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' @details Details `r x <- 10` #' #' ```{r} #' y <- x + 10 #' y #' ``` #' #' @md #' @name dummy NULL")[[1]] details <- out1$get_value("details") expect_match(details, "Details 10", fixed = TRUE) expect_match(details, "## [1] 20", fixed = TRUE) }) test_that("fence options are used", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' @details Details #' #' ```{r eval = FALSE} #' this - would - fail - to - eval #' ``` #' #' @md #' @name dummy NULL")[[1]] details <- out1$get_value("details") expect_false(grepl("Error", details)) }) test_that("dynamic code in fragile tags still runs", { out <- markdown("foo \\out{`r 1+1`} bar") expect_equal(out, "foo \\out{2} bar") }) test_that("fragile tags in dynamic code are left alone", { out <- markdown("foo `r substr('\\\\out{xxx}', 2, 4)` bar") expect_equal(out, "foo out bar") }) test_that("fragile tags in generated code", { out <- markdown("foo `r '\\\\out{*1*}'` bar") expect_equal(out, "foo \\out{*1*} bar") expect_silent(out2 <- markdown("foo `r '\\\\out{}'` bar")) expect_equal(out2, "foo \\out{} bar") }) roxygen2/tests/testthat/test-utils-io.R0000644000176200001440000000322314047223751017703 0ustar liggesuserstest_that("detect_line_ending works", { # write files with various newlines win_nl <- tempfile() win_nl_con <- file(win_nl, "wb") unix_nl <- tempfile() unix_nl_con <- file(unix_nl, "wb") non_existent_file <- tempfile() empty_file <- tempfile() file.create(empty_file) on.exit({ unlink(c(win_nl, unix_nl, empty_file)) }) base::writeLines(c("foo", "bar"), win_nl_con, sep = "\r\n") close(win_nl_con) base::writeLines(c("foo", "bar"), unix_nl_con, sep = "\n") close(unix_nl_con) expect_equal(detect_line_ending(win_nl), "\r\n") expect_equal(detect_line_ending(unix_nl), "\n") expect_equal(detect_line_ending(non_existent_file), "\n") expect_equal(detect_line_ending(empty_file), "\n") }) test_that("write_lines writes windows newlines for files with windows newlines, and unix newlines otherwise", { # write files with various newlines win_nl <- tempfile() win_nl_con <- file(win_nl, "wb") unix_nl <- tempfile() unix_nl_con <- file(unix_nl, "wb") non_existent_file <- tempfile() empty_file <- tempfile() file.create(empty_file) on.exit({ unlink(c(win_nl, unix_nl, empty_file, non_existent_file)) }) base::writeLines(c("foo", "bar"), win_nl_con, sep = "\r\n") close(win_nl_con) base::writeLines(c("foo", "bar"), unix_nl_con, sep = "\n") close(unix_nl_con) write_lines("baz", win_nl) expect_equal(readChar(win_nl, 100), "baz\r\n") write_lines("baz", unix_nl) expect_equal(readChar(unix_nl, 100), "baz\n") write_lines("baz", non_existent_file) expect_equal(readChar(non_existent_file, 100), "baz\n") write_lines("baz", empty_file) expect_equal(readChar(empty_file, 100), "baz\n") }) roxygen2/tests/testthat/test-rd-describe-in.R0000644000176200001440000000532513542230224020722 0ustar liggesuserstest_that("@describeIn generic captures s3 method class", { out <- roc_proc_text(rd_roclet(), " #' Title f <- function(x) UseMethod('f') #' @describeIn f Method for a #' f.a <- function(x) 1 ")[[1]] expect_equal(out$get_value("minidesc")$type, "generic") expect_equal(out$get_value("minidesc")$label, "a") }) test_that("@describeIn generic captures s4 method class", { out <- roc_proc_text(rd_roclet(), " #' Title setGeneric('f', function(x) standardGeneric('f')) #' @describeIn f Method for a setMethod(f, signature('a'), function(x) 1) ")[[1]] expect_equal(out$get_value("minidesc")$label, "a") }) test_that("@describeIn class captures s3 generic name", { out <- roc_proc_text(rd_roclet(), " #' Title boo <- function() structure(list(), class = 'boo') #' @describeIn boo mean method #' mean.boo <- function(x) 1 ")[[1]] expect_equal(out$get_value("minidesc")$label, "mean") }) test_that("@describeIn class captures s4 generic name", { out <- roc_proc_text(rd_roclet(), " setGeneric('mean') #' Title setClass('a') #' @describeIn a mean method setMethod('mean', 'a', function(x) 1) ")[[1]] expect_equal(out$get_value("minidesc")$label, "mean") }) test_that("Multiple @describeIn generic combined into one", { out <- roc_proc_text(rd_roclet(), " #' Title f <- function(x) UseMethod('f') #' @describeIn f A f.a <- function(x) 1 #' @describeIn f B f.b <- function(x) 1 ")[[1]] expect_equal(out$get_value("minidesc")$type, "generic") expect_equal(out$get_value("minidesc")$label, c("a", "b")) expect_equal(out$get_value("minidesc")$desc, c("A", "B")) }) test_that("all other combinations fallback to function list", { out <- roc_proc_text(rd_roclet(), " #' Generic foo <- function(x) UseMethod('foo') #' @describeIn foo related function bar <- function(y) {} ")[[1]] expect_equal(out$get_value("minidesc")$type, "function") }) test_that("@describeIn class captures function name", { out <- roc_proc_text(rd_roclet(), " #' Title f <- function(x) 1 #' @describeIn f A f2 <- function(x) 1 ")[[1]] expect_equal(out$get_value("minidesc")$label, "f2") }) test_that("@describeIn class captures function name with data", { out <- roc_proc_text(rd_roclet(), " #' Title #' @name f NULL #' @describeIn f A f2 <- function(x) 1 ")[[1]] expect_equal(out$get_value("minidesc")$label, "f2") }) test_that("function names are escaped", { out <- roc_proc_text(rd_roclet(), " #' foo foo <- 100 #' @describeIn foo shortcut for foo `%foo%` <- function(x, y) foo(x, y) ")[[1]] expect_match(out$get_rd("minidesc"), "\\\\%foo\\\\%") }) roxygen2/tests/testthat/testCollateNoIncludes/0000755000176200001440000000000013523072405021301 5ustar liggesusersroxygen2/tests/testthat/testCollateNoIncludes/NAMESPACE0000644000176200001440000000003113523072405022512 0ustar liggesusersexportPattern("^[^\\.]") roxygen2/tests/testthat/testCollateNoIncludes/DESCRIPTION0000644000176200001440000000034613523072405023012 0ustar liggesusersPackage: testCollateNoIncludes Title: Test no change to Collate when there are no @includes License: GPL-2 Description: Author: Geoff Maintainer: Geoff Version: 0.1 Collate: b.r a.r roxygen2/tests/testthat/testCollateNoIncludes/R/0000755000176200001440000000000013523072405021502 5ustar liggesusersroxygen2/tests/testthat/testCollateNoIncludes/R/a.r0000644000176200001440000000014513523072405022105 0ustar liggesusers# Manually edited the Collate field in the DESCRIPTION file so this *should* # run after b.r a <- 1 roxygen2/tests/testthat/testCollateNoIncludes/R/b.r0000644000176200001440000000000713523072405022103 0ustar liggesusersa <- 2 roxygen2/tests/testthat/Rd-example-1.R0000644000176200001440000000002613523072405017307 0ustar liggesusersexample <- 'example1' roxygen2/tests/testthat/roxygen-block-3-A.Rd0000644000176200001440000000643614115761232020434 0ustar liggesusers> res[[n]] % Generated by roxygen2: do not edit by hand % Please edit documentation in ./roxygen-block-3.R \name{A} \alias{A} \title{Class A} \description{ Class A description. } \details{ Class A details } \examples{ ## ------------------------------------------------ ## Method `A$meth1` ## ------------------------------------------------ ## Example for meth1 ## ------------------------------------------------ ## Method `A$meth2` ## ------------------------------------------------ ## Example for meth2 } \section{Public fields}{ \if{html}{\out{
}} \describe{ \item{\code{field1}}{A field 1.} \item{\code{field2}}{A field 2.} \item{\code{field3}}{A field 3.} } \if{html}{\out{
}} } \section{Active bindings}{ \if{html}{\out{
}} \describe{ \item{\code{active1}}{A binding 1.} \item{\code{active2}}{A binding 2.} \item{\code{active3}}{A binding 2.} } \if{html}{\out{
}} } \section{Methods}{ \subsection{Public methods}{ \itemize{ \item \href{#method-meth1}{\code{A$meth1()}} \item \href{#method-meth2}{\code{A$meth2()}} \item \href{#method-meth3}{\code{A$meth3()}} \item \href{#method-clone}{\code{A$clone()}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-meth1}{}}} \subsection{Method \code{meth1()}}{ A method 1. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{A$meth1(Z)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{Z}}{zzzzzzz} } \if{html}{\out{
}} } \subsection{Examples}{ \if{html}{\out{
}} \preformatted{## Example for meth1 } \if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-meth2}{}}} \subsection{Method \code{meth2()}}{ Method 2 description. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{A$meth2(Z = 10, ...)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{Z}}{Overriding Z argument for meth2.} \item{\code{...}}{Rest.} } \if{html}{\out{
}} } \subsection{Details}{ Method 2 details. } \subsection{Examples}{ \if{html}{\out{
}} \preformatted{## Example for meth2 } \if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-meth3}{}}} \subsection{Method \code{meth3()}}{ \subsection{Usage}{ \if{html}{\out{
}}\preformatted{A$meth3(duplicate, missing)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{duplicate}}{This one is} \item{\code{duplicate}}{Twice} } \if{html}{\out{
}} } \subsection{Details}{ Method 3 details. } \subsection{Returns}{ twice. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{A$clone(deep = FALSE)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{deep}}{Whether to make a deep clone.} } \if{html}{\out{
}} } } } roxygen2/tests/testthat/test-object-from-call.R0000644000176200001440000001337313631761325021267 0ustar liggesuserstest_that("undocumentable things return null", { expect_null(call_to_object(NULL)) expect_null(call_to_object(10)) expect_null(call_to_object(1 + 2)) }) # data / package ------------------------------------------------------- test_that("finds package description", { obj <- call_to_object("_PACKAGE", file = test_path("testEagerData/R/a.r")) expect_s3_class(obj, "package") expect_equal(obj$alias, "_PACKAGE") expect_equal(obj$value$desc$Package, "testEagerData") }) test_that("Can read UTF-8 DESCRIPTIONS", { expect_equal(read.description("testNonASCII/DESCRIPTION")$Author, "Shr\U00EBktan ") }) test_that("finds datasets given by name", { obj <- call_to_object({ df <- data.frame(x = 1, y = 2) "df" }) expect_s3_class(obj, "data") expect_equal(obj$alias, "df") expect_s3_class(obj$value, "data.frame") }) test_that("can document eager data", { skip_if_not_installed("devtools") test_pkg <- temp_copy_pkg('testEagerData') on.exit(unlink(test_pkg, recursive = TRUE)) expect_output(devtools::document(test_pkg), "a[.]Rd") expect_true(file.exists(file.path(test_pkg, "man", "a.Rd"))) }) test_that("can document lazy data", { skip_if_not_installed("devtools") test_pkg <- temp_copy_pkg('testLazyData') on.exit(unlink(test_pkg, recursive = TRUE)) expect_output(devtools::document(test_pkg), "a[.]Rd") expect_true(file.exists(file.path(test_pkg, "man", "a.Rd"))) }) # imports ----------------------------------------------------------------- test_that("find function imported from another package", { obj <- call_to_object(purrr::map_int) expect_s3_class(obj, "import") expect_equal(obj$alias, "map_int") expect_equal(obj$value$pkg, "purrr") }) # assignment ------------------------------------------------------------ test_that("finds function created with assignment", { obj <- call_to_object({ foo <- function(x, y, z) {} }) expect_s3_class(obj, "function") }) test_that("finds S3 generic created with assignment", { obj <- call_to_object({ foo <- function(x, y, z) UseMethod("foo") }) expect_s3_class(obj, "s3generic") }) test_that("finds S3 method created with assignment", { obj <- call_to_object({ foo <- function(x, y, z) UseMethod("foo") foo.method <- function(x, y, z) {} }) expect_s3_class(obj, "s3method") }) test_that("finds data created with assignment", { obj <- call_to_object({ foo <- 1:10 }) expect_s3_class(obj, "data") }) test_that("finds class generator", { obj <- call_to_object({ newFoo <- setClass("Foo") }) expect_s3_class(obj, "s4class") expect_equal(obj$alias, "newFoo") expect_s4_class(obj$value, "classRepresentation") obj <- call_to_object({ newFoo <- setRefClass("Foo") }) expect_s3_class(obj, "rcclass") expect_equal(obj$alias, "newFoo") expect_s4_class(obj$value, "classRepresentation") }) test_that("ignored compound assignment", { obj <- call_to_object({ foo <- list() foo[[1]] <- function(x, y, z) {} }) expect_null(obj) }) test_that("finds function created with delayed assignment", { obj <- call_to_object({ delayedAssign("foo", function(x, y, z) {}) }) expect_s3_class(obj, "function") }) # S4 ---------------------------------------------------------------------- test_that("finds S4 and RC classes", { obj <- call_to_object(setClass("Foo")) expect_s3_class(obj, "s4class") expect_equal(obj$topic, "Foo-class") expect_equal(obj$alias, NULL) obj <- call_to_object(setRefClass("Foo")) expect_s3_class(obj, "rcclass") expect_equal(obj$topic, "Foo-class") obj <- call_to_object({ setClass("Foo") setClassUnion("Foo2", "Foo") }) expect_s3_class(obj, "s4class") expect_equal(obj$topic, "Foo2-class") }) test_that("finds S4 generics and methods", { obj <- call_to_object({ setGeneric("bar", function(x) standardGeneric("bar")) }) expect_s3_class(obj, "s4generic") obj <- call_to_object({ setGeneric("bar", function(x) standardGeneric("bar")) setMethod('bar', 'Foo', function(x) {}) }) expect_s3_class(obj, "s4method") obj <- call_to_object({ setGeneric("bar<-", function(x, value) standardGeneric("bar<-")) setReplaceMethod("bar", "Foo", function(x, value) {}) }) expect_s3_class(obj, "s4method") }) test_that("finds correct parser even when namespaced", { obj <- call_to_object({ setClass("Foo") setGeneric("baz", function(x) standardGeneric("baz")) methods::setMethod('baz', 'Foo', function(x) {}) }) expect_s3_class(obj, "s4method") }) test_that("finds arguments when S4 method wrapped inside .local()", { obj <- call_to_object({ setClass("Foo") setMethod('subset', 'Foo', function(x, foo, ...) {}) }) expect_s3_class(obj, "s4method") expect_named(formals(obj$value@.Data), c("x", "foo", "...")) }) # R.oo / R.methodsS3 ------------------------------------------------------ test_that("can define constructor with R.oo", { obj <- call_to_object({ R.oo::setConstructorS3("Foo", function(x, y, z) {}) }) expect_s3_class(obj, "function") expect_equal(obj$alias, "Foo") }) test_that("can define method for R.methodsS3", { obj <- call_to_object({ R.methodsS3::setMethodS3("foo", "default", function(x, ...) {}) }) expect_s3_class(obj, "s3method") expect_equal(obj$alias, "foo.default") }) # extract_method_fun ------------------------------------------------------ test_that("fails gracefully on bad inputs", { fun1 <- function() {} fun2 <- function() 1 + 2 fun3 <- function() { 1 + 2 } fun4 <- function() { x <- 1 } fun5 <- function() { .local <- 1 } expect_equal(extract_method_fun(fun1), fun1) expect_equal(extract_method_fun(fun2), fun2) expect_equal(extract_method_fun(fun3), fun3) expect_equal(extract_method_fun(fun4), fun4) expect_equal(extract_method_fun(fun5), fun5) }) roxygen2/tests/testthat/test-object-defaults.R0000644000176200001440000000372314115761547021224 0ustar liggesuserstest_that("@docType data automatically adds sensible defaults", { out <- roc_proc_text(rd_roclet(), " #' Title. #' #' @docType data a <- data.frame(a = 1:10) ")[[1]] expect_equal(out$get_value("usage"), rd("a")) expect_equal(out$get_value("keyword"), "datasets") expect_false(is.null(out$get_value("format"))) }) test_that("@docType data automatically added to data objects", { out <- roc_proc_text(rd_roclet(), " #' Title. a <- data.frame(a = 1:10) ")[[1]] expect_equal(out$get_value("docType"), "data") }) test_that("@docType data automatically added to data objects created elsewhere", { out <- roc_proc_text(rd_roclet(), " a <- data.frame(a = 1:10) #' Title. 'a' ")[[1]] expect_equal(out$get_value("docType"), "data") expect_equal(out$get_value("usage"), rd("a")) expect_equal(out$get_value("keyword"), "datasets") }) # Reference classes ---------------------------------------------------------- test_that("@docType class automatically added to reference class objects", { out <- roc_proc_text(rd_roclet(), " #' Title. #' a <- setRefClass('a')")[[1]] expect_equal(out$get_value("docType"), "class") }) # packages ----------------------------------------------------------------- test_that("can create package documentation", { with_mock( `roxygen2::read.description` = function(...) list(Package = "roxygen_devtest", Title = "Package Title", Description = "Package description."), out <- roc_proc_text(rd_roclet(), " #' @details Details. '_PACKAGE'")[[1]] ) expect_equal(out$get_value("name"), "roxygen_devtest-package") expect_equal(out$get_value("alias"), c("roxygen_devtest", "roxygen_devtest-package")) expect_equal(out$get_value("title"), "roxygen_devtest: Package Title") expect_equal(out$get_value("description"), "Package description.") expect_equal(out$get_value("docType"), "package") expect_equal(out$get_value("details"), "Details.") }) roxygen2/tests/testthat/helper-test.R0000644000176200001440000000052013544473137017420 0ustar liggesusersexpect_equivalent_rd <- function(out1, out2) { out1$sections$backref <- NULL out2$sections$backref <- NULL expect_equal(out1, out2) } expect_equal_strings <- function(s1, s2, ignore_ws = TRUE) { if (ignore_ws) { s1 <- gsub("\\s", "", s1, perl = TRUE) s2 <- gsub("\\s", "", s2, perl = TRUE) } expect_equal(s1, s2) } roxygen2/tests/testthat/test-object-format-r4.txt0000644000176200001440000000112214115761226021627 0ustar liggesusers> call_to_format(x <- list(a = 1, b = 2)) [1] "An object of class \\code{list} of length 2." > call_to_format(x <- ordered(letters[1:5])) [1] "An object of class \\code{ordered} (inherits from \\code{factor}) of length 5." > call_to_format(x <- diag(10)) [1] "An object of class \\code{matrix} (inherits from \\code{array}) with 10 rows and 10 columns." > call_to_format(x <- array(1:27, dim = c(3, 3, 3))) [1] "An object of class \\code{array} of dimension 3 x 3 x 3." > call_to_format(x <- data.frame(a = 1, b = 2)) [1] "An object of class \\code{data.frame} with 1 rows and 2 columns." roxygen2/tests/testthat/test-markdown-link.R0000644000176200001440000003225514115761547020730 0ustar liggesuserstest_that("proper link references are added", { cases <- list( c("foo [func()] bar", "[func()]: R:func()"), c("foo [obj] bar", "[obj]: R:obj"), c("foo [text][func()] bar", "[func()]: R:func()"), c("foo [text][obj] bar", "[obj]: R:obj"), c("foo [pkg::func()] bar", "[pkg::func()]: R:pkg::func()"), c("foo [pkg::obj] bar", "[pkg::obj]: R:pkg::obj"), c("foo [text][pkg::func()] bar", "[pkg::func()]: R:pkg::func()"), c("foo [text][pkg::obj] bar", "[pkg::obj]: R:pkg::obj"), c("foo [linktos4-class] bar", "[linktos4-class]: R:linktos4-class"), c("foo [pkg::s4-class] bar", "[pkg::s4-class]: R:pkg::s4-class") ) for (i in seq_along(cases)) { expect_match( add_linkrefs_to_md(cases[[i]][1]), cases[[i]][2], fixed = TRUE ) } }) test_that("can not have [ inside of link", { expect_equal( markdown("`[[`. [subset()]"), "\\code{[[}. \\code{\\link[=subset]{subset()}}" ) }) test_that("can escape [ to avoid spurious links", { expect_equal( markdown("\\[test\\]"), "[test]" ) expect_equal( markdown("\\[ [test] \\]"), "[ \\link{test} ]", ) }) test_that("\\Sexpr with options not converted to links", { expect_equal( markdown("\\Sexpr[results=rd]{runif(1)}"), "\\Sexpr[results=rd]{runif(1)}" ) }) test_that("% in links are escaped", { expect_equal(markdown("[x][%%]"), "\\link[=\\%\\%]{x}") expect_equal(markdown("[%][x]"), "\\link[=x]{\\%}") expect_equal(markdown("[%%]"), "\\link{\\%\\%}") expect_equal(markdown("[base::%%]"), "\\link[base:Arithmetic]{base::\\%\\%}") }) test_that("commonmark picks up the various link references", { cases <- list( list("foo [func()] bar", c("R:func()", "func()")), list("foo [obj] bar", c("R:obj", "obj")), list("foo [text][func()] bar", c("R:func()", "text")), list("foo [text][obj] bar", c("R:obj", "text")), list("foo [pkg::func()] bar", c("R:pkg::func()", "pkg::func()")), list("foo [pkg::obj] bar", c("R:pkg::obj", "pkg::obj")), list("foo [text][pkg::func()] bar", c("R:pkg::func()", "text")), list("foo [text][pkg::obj] bar", c("R:pkg::obj", "text")), list("foo [linktos4-cl] bar", c("R:linktos4-cl", "linktos4-cl")), list("foo [pkg::s4-cl] bar", c("R:pkg::s4-cl", "pkg::s4-cl")) ) for (i in seq_along(cases)) { x <- commonmark::markdown_xml(add_linkrefs_to_md(cases[[i]][[1]])) xdoc <- xml2::xml_ns_strip(xml2::read_xml(x)) link <- xml2::xml_find_first(xdoc, "//link") expect_equal(xml2::xml_attr(link, "destination"), cases[[i]][[2]][1]) text <- xml2::xml_find_first(link, "./text") expect_equal(xml2::xml_text(text), cases[[i]][[2]][2], info = i) } }) test_that("short and sweet links work", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see [function()]. #' And also [object]. #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see \\code{\\link[=function]{function()}}. #' And also \\link{object}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) expect_warning( out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' See [11pkg::function()], [11pkg::object]. #' @md foo <- function() {}")[[1]], "Link to unavailable package" ) out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' See \\code{\\link[11pkg:function]{11pkg::function()}}, \\link[11pkg:object]{11pkg::object}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see [name][dest]. #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see \\link[=dest]{name}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) expect_warning( out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see [name words][stringr::bar111]. #' @md foo <- function() {}")[[1]], "Link to unknown topic: stringr::bar111" ) out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see \\link[stringr:bar111]{name words}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see [terms][terms.object]. #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see \\link[=terms.object]{terms}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see [abc][abc-class]. #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see \\link[=abc-class]{abc}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) out1 <- roc_proc_text(rd_roclet(), " #' Title. #' #' In another package: [and this one][devtools::document]. #' [name words][devtools::document]. #' #' @md #' @name markdown-test foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title. #' #' In another package: \\link[devtools:document]{and this one}. #' \\link[devtools:document]{name words}. #' #' @name markdown-test foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("a weird markdown link bug is fixed", { out1 <- roc_proc_text(rd_roclet(), " #' Dummy page to test roxygen's markdown formatting #' #' Links are very tricky, so I'll put in some links here: #' Link to a function: [roxygenize()]. #' Link to an object: [roxygenize] (we just treat it like an object here). #' #' Link to another package, function: [devtools::document()]. #' Link to another package, non-function: [devtools::document]. #' #' Link with link text: [this great function][roxygenize()], #' [`roxygenize`][roxygenize()], or [that great function][roxygenize]. #' #' In another package: [and this one][devtools::document]. #' #' @md #' @name markdown-test #' @keywords internal NULL")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Dummy page to test roxygen's markdown formatting #' #' Links are very tricky, so I'll put in some links here: #' Link to a function: \\code{\\link[=roxygenize]{roxygenize()}}. #' Link to an object: \\link{roxygenize} (we just treat it like an object here). #' #' Link to another package, function: \\code{\\link[devtools:document]{devtools::document()}}. #' Link to another package, non-function: \\link[devtools:document]{devtools::document}. #' #' Link with link text: \\link[=roxygenize]{this great function}, #' \\code{\\link[=roxygenize]{roxygenize}}, or \\link[=roxygenize]{that great function}. #' #' In another package: \\link[devtools:document]{and this one}. #' #' @name markdown-test #' @keywords internal NULL")[[1]] expect_equivalent_rd(out1, out2) }) test_that("another markdown link bug is fixed", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see [escape_rd_for_md()]. #' #' And also [object]. #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see \\code{\\link[=escape_rd_for_md]{escape_rd_for_md()}}. #' #' And also \\link{object}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("markdown code as link text is rendered as code", { suppressWarnings(out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see [`name`][dest], #' [`function`][function()], #' [`filter`][stats::filter()], #' [`bar`][pkg::bar], #' [`terms`][terms.object], #' [`abc`][abc-class]. #' @md foo <- function() {}")[[1]]) out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see \\code{\\link[=dest]{name}}, #' \\code{\\link[=function]{function}}, #' \\code{\\link[stats:filter]{filter}}, #' \\code{\\link[pkg:bar]{bar}}, #' \\code{\\link[=terms.object]{terms}}, #' \\code{\\link[=abc-class]{abc}}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("non-code link in backticks works", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see [`foobar`]. #' Also [`this_too`]. #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see \\code{\\link{foobar}}. #' Also \\code{\\link{this_too}}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("[] is not picked up in code", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' @param connect_args `[named list]`\\cr Connection arguments #' Description, see `[foobar]`. #' Also `[this_too]`. #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' @param connect_args \\verb{[named list]}\\cr Connection arguments #' Description, see \\verb{[foobar]}. #' Also \\verb{[this_too]}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("[]() links are still fine", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see [some thing](http://www.someurl.com). #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see \\href{http://www.someurl.com}{some thing}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Link #' text [broken #' across lines](http://www.someurl.com) preserve #' whitespace, even when #' [broken across #' several #' lines](http://www.someurl.com), #' or with varying #' [amounts \ #' of \ #' interspersed \ #' whitespace](http://www.someurl.com). #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Link #' text \\href{http://www.someurl.com}{broken across lines} preserve #' whitespace, even when #' \\href{http://www.someurl.com}{broken across several lines}, #' or with varying #' \\href{http://www.someurl.com}{amounts of interspersed whitespace}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("links to S4 classes are OK", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see [linktos4-class] as well. #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see \\linkS4class{linktos4} as well. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) suppressWarnings(out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see [pkg::linktos4-class] as well. #' @md foo <- function() {}")[[1]]) out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see \\link[pkg:linktos4-class]{pkg::linktos4} as well. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("linebreak in 'text' of [text][foo] turns into single space", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Link #' text [broken #' across lines][fcn] preserve #' whitespace, even when #' [broken across #' several #' lines][fcn], #' or with varying #' [amounts \ #' of \ #' interspersed \ #' whitespace][fcn]. #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Link #' text \\link[=fcn]{broken across lines} preserve #' whitespace, even when #' \\link[=fcn]{broken across several lines}, #' or with varying #' \\link[=fcn]{amounts of interspersed whitespace}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("markup in link text", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see [`code link text`][func]. #' And also [`code as well`](https://external.com). #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description, see \\code{\\link[=func]{code link text}}. #' And also \\href{https://external.com}{\\verb{code as well}}. foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) test_that("linking to self is unqualified", { old <- roxy_meta_set("current_package", "myself") on.exit(roxy_meta_set("current_package", old), add = TRUE) rd <- markdown("foo [myself::fun()] and [myself::obj] bar") expect_equal( rd, "foo \\code{\\link[=fun]{fun()}} and \\link{obj} bar" ) }) test_that("percents are escaped in link targets", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' [link % text](https://foo.bar/link%20target) #' @md foo <- function() {}")[[1]] out2 <- roc_proc_text(rd_roclet(), " #' Title #' #' \\href{https://foo.bar/link%20target}{link % text} #' @md foo <- function() {}")[[1]] expect_equivalent_rd(out1, out2) }) roxygen2/tests/testthat/test-tag.R0000644000176200001440000000420514047223751016712 0ustar liggesusers# Test low-level behaviour ---------------------------------------------------- test_that("braces must balance", { expect_true(rdComplete("{}", is_code = FALSE)) expect_true(rdComplete("{{}}", is_code = FALSE)) expect_false(rdComplete("{", is_code = FALSE)) expect_false(rdComplete("}", is_code = FALSE)) }) test_that("can't end with escape", { expect_false(rdComplete("\\", is_code = FALSE)) }) test_that("escaped brackets are ignored", { expect_true(rdComplete("\\{", is_code = FALSE)) expect_true(rdComplete("\\}", is_code = FALSE)) expect_false(rdComplete("{\\}", is_code = FALSE)) }) test_that("brackets in comments are ignored", { expect_true(rdComplete("% {", is_code = FALSE)) expect_true(rdComplete("% }", is_code = FALSE)) }) test_that("R comments don't close latex-like tags", { expect_true(rdComplete("A comment \\code{#}.", is_code = FALSE)) }) test_that("newline ends comment", { expect_false(rdComplete("%\n{", is_code = FALSE)) }) test_that("escape disables comment", { expect_false(rdComplete("\\%{", is_code = FALSE)) }) test_that("strings must be closed in code", { expect_false(rdComplete("'", is_code = TRUE)) expect_false(rdComplete('"', is_code = TRUE)) }) test_that("strings respect escapes", { expect_false(rdComplete("'\\'", is_code = TRUE)) # '\' expect_true(rdComplete("'\\''", is_code = TRUE)) # '\'' }) test_that("braces in strings don't need to match in code", { expect_true(rdComplete("'{{'", is_code = TRUE)) }) test_that("strings in code comments don't need to be closed", { expect_true(rdComplete("# '", is_code = TRUE)) }) test_that("braces in code must match", { expect_false(rdComplete("# {", is_code = TRUE)) expect_true(rdComplete("# {}", is_code = TRUE)) }) # Test that incomplete Rd is caught in Rd blocks ------------------------------- test_that("incomplete rd in tag raises error", { expect_warning(roc_proc_text(rd_roclet(), " #' Title #' @aliases title{ x <- 1"), "mismatched braces") }) test_that("incomplete rd in prequel raises error", { expect_warning( roc_proc_text(rd_roclet(), " #' Title { x <- 1" ), "mismatched braces" ) }) roxygen2/tests/testthat/roxygen-block-3-warnings.txt0000644000176200001440000000161114115761232022344 0ustar liggesusers> sort(roxy_warnings) [1] "[roxygen-block-3.R:35] @return May only use one @return per R6 method" [2] "[roxygen-block-3.R:36] argument `duplicate` documented multiple times for R6 method `meth3`" [3] "[roxygen-block-3.R:36] argument `missing` undocumented for R6 method `meth3()`" [4] "[roxygen-block-3.R:92] R6 active binding documented multiple times: `duplicate_binding`" [5] "[roxygen-block-3.R:92] R6 field documented multiple times: `duplicatefield`" [6] "[roxygen-block-3.R:92] undocumented R6 active binding: `undocumented_binding`" [7] "[roxygen-block-3.R:92] undocumented R6 fields: `field2`, `undocumented_field`" [8] "[roxygen-block-3.R:92] undocumented R6 method: `undocumented_method`" [9] "[roxygen-block-3.R:92] unknown R6 field: `nosuchfield`" roxygen2/tests/testthat/test-rd-examples-dontrun-escape.txt0000644000176200001440000000012713565531535023730 0ustar liggesusers> out$get_section("examples") \examples{ \dontshow{ \{ } # Hidden! \dontshow{ \} } } roxygen2/tests/testthat/test-tokenize.R0000644000176200001440000000720314047223751017770 0ustar liggesusers# tokenise_block ---------------------------------------------------------- test_that("parses into tag and value", { x <- tokenise_block("#' @xyz abc", file = "", offset = 0) expect_equal(length(x), 1) expect_equal(x[[1]]$tag, "xyz") expect_equal(x[[1]]$raw, "abc") }) test_that("description block gets empty tag", { x <- tokenise_block("#' abc", file = "", offset = 0L) expect_equal(length(x), 1) expect_equal(x[[1]]$tag, "") expect_equal(x[[1]]$raw, "abc") }) test_that("multi line tags collapsed into one", { x <- tokenise_block(c( "#' @tag abc", "#' def"), file = "", offset = 0L) expect_equal(length(x), 1) expect_equal(x[[1]]$raw, "abc\n def") }) test_that("description block gets empty tag when followed by tag", { x <- tokenise_block(c( "#' abc", "#' @xyz abc"), file = "", offset = 0L) expect_equal(length(x), 2) expect_equal(x[[1]]$tag, "") expect_equal(x[[1]]$raw, "abc") expect_equal(x[[2]]$tag, "xyz") expect_equal(x[[2]]$raw, "abc") }) test_that("leading whitespace is ignored", { ref <- tokenise_block("#' abc", file = "", offset = 0L) expect_equal(tokenise_block(" #' abc", file = "", offset = 0L), ref) }) test_that("need one or more #", { ref <- tokenise_block("#' abc", file = "", offset = 0L) expect_equal(tokenise_block("##' abc", file = "", offset = 0L), ref) expect_equal(tokenise_block("###' abc", file = "", offset = 0L), ref) }) test_that("@@ becomes @", { expect_equal(tokenise_block("#' @tag @@", file = "", offset = 0L)[[1]]$raw, "@") }) # Inline comments --------------------------------------------------------- test_that("Inline comments are supported", { out <- roc_proc_text(rd_roclet(), " #' Description a <- function(x) { #' @param x an integer stopifnot(is.integer(x)) }")[[1]] expect_equal(out$get_value("param"), c(x = "an integer")) }) test_that("Inline comments just before the closing brace are allowed", { out <- roc_proc_text(rd_roclet(), " #' Description a <- function(x) { #' @param x an integer stopifnot(is.integer(x)) #' @seealso somewhere }")[[1]] expect_equal(out$get_value("seealso"), "somewhere") }) test_that("Inline comments do not extend past the closing brace", { out <- roc_proc_text(rd_roclet(), " #' Description a <- function(x) { #' @param x an integer stopifnot(is.integer(x)) }; #' @seealso somewhere")[[1]] expect_null(out$get_value("seealso")) }) test_that("Line numbers are ok", { check_line_nums <- function(block, lines) { for (t in names(lines)) { expect_equal(block_get_tag(block, t)$line, lines[[t]], info = t) } } text <- "#' @title #' Foo #' #' @description #' Description #' #' @details #' Details #' #' @param x xyz #' @export NULL" block <- roxygen2::parse_text(text)[[1]] ls <- c(title = 1, description = 4, details = 7, param = 10, export = 11) check_line_nums(block, ls) text <- "#' @title Foo #' #' @description Description #' #' @details Details #' #' @param x xy #' z #' #' @export NULL" block <- roxygen2::parse_text(text)[[1]] ls <- c(title = 1, description = 3, details = 5, param = 7, export = 10) check_line_nums(block, ls) text <- "#' @title Foo #' #' @description Description #' #' @details Details # not - a - roxy - comment #' @param x xy #' z quote(neither - is - #' @export this)" block <- roxygen2::parse_text(text)[[1]] ls <- c(title = 1, description = 3, details = 5, param = 7, export = 10) check_line_nums(block, ls) }) roxygen2/tests/testthat/test-rd-simple.R0000644000176200001440000000133313542227702020031 0ustar liggesuserstest_that("one line per concept", { out <- roc_proc_text(rd_roclet(), " #' @title a #' @name a #' @concept test1 #' @concept test2 NULL")[[1]] expect_equal(out$get_value("concept"), c("test1", "test2")) expect_equal(out$get_rd("concept"), c("\\concept{test1}", "\\concept{test2}")) }) test_that("simple keys produce expected output", { out <- roc_proc_text(rd_roclet(), " #' @title a #' @encoding test #' @name a NULL")[[1]] expect_equal(out$get_value("encoding"), "test") }) test_that("keywords split into pieces", { out <- roc_proc_text(rd_roclet(), " #' @keywords a b #' @title a #' @name a NULL")[[1]] expect_equal(out$get_value("keyword"), c("a", "b")) }) roxygen2/tests/testthat/test-topic.R0000644000176200001440000000107613544473137017266 0ustar liggesuserstest_that("adding tags merges with existing", { rd <- RoxyTopic$new() rd$add(rd_section("x", 1)) rd$add(rd_section("x", 2)) expect_equal(rd$get_value("x"), c(1, 2)) }) test_that("unless overwrite = TRUE", { rd <- RoxyTopic$new() rd$add(rd_section("x", 1)) rd$add(rd_section("x", 2), overwrite = TRUE) expect_equal(rd$get_value("x"), 2) }) test_that("can add a complete file", { rd1 <- RoxyTopic$new() rd2 <- RoxyTopic$new() rd1$add(rd_section("x", 1)) rd2$add(rd_section("x", 2)) rd2$add(rd1) expect_equal(rd2$get_value("x"), c(2, 1)) }) roxygen2/tests/testthat/test-object-rc.R0000644000176200001440000000363513542151251020007 0ustar liggesusers# Docstrings ------------------------------------------------------------------- test_that("base functions don't have docstrings", { expect_equal(docstring(`[`), NULL) expect_equal(docstring(mean), NULL) }) test_that("function return string doesn't have docstring", { expect_equal(docstring(function() "a"), NULL) expect_equal(docstring(function() {"a"}), NULL) }) test_that("first string in function is docstring", { expect_equal(docstring(function() {"a"; 1}), "a") }) test_that("trim_docstring handles indentation correctly", { expect_equal(trim_docstring("a\n b\n c"), "a\nb\nc") expect_equal(trim_docstring("a\nb\nc"), "a\nb\nc") expect_equal(trim_docstring("a\n b\n c"), "a\nb\n c") expect_equal(trim_docstring(" a\n b\n c"), "a\nb\n c") }) # Method documentation --------------------------------------------------------- env <- pkg_env() A1 <- setRefClass("A1", methods = list( f = function() { "This function has a docstring" 1 }, g = function() { "This function doesn't" } ), where = env) B1 <- setRefClass("B1", contains = "A1", methods = list( f1 = function() { "This function has a docstring" 1 }, g1 = function() { "This function doesn't" } ), where = env) classA <- getClass("A1", where = env) classB <- getClass("B1", where = env) test_that("rc_methods only lists methods belong to class (not parents)", { expect_equal(length(rc_methods(classA)), 2) expect_equal(length(rc_methods(classB)), 2) }) test_that("RC methods included included in own section", { out <- roc_proc_text(rd_roclet(), " #' Class ABC setRefClass('ABC', methods = list( f = function() { 'This function has a docstring' 1 } )) ")[[1]] methods <- out$get_value("rcmethods") expect_equal(names(methods), "f()") expect_match(methods[[1]], "This function has a docstring") }) removeClass("B1", where = env) removeClass("A1", where = env) roxygen2/tests/testthat/roxygen-block-2.R0000644000176200001440000000057213523072405020103 0ustar liggesusers#' The length of a string (in characters). #' #' @param string input character vector #' @return numeric vector giving number of characters in each element of the #' character vector. Missing strings have missing length. #' @seealso \code{\link{nchar}} which this function wraps #' @export #' @examples #' str_length(letters) #' str_length(c("i", "like", "programming", NA)) roxygen2/tests/testthat/roxygen-block-1.R0000644000176200001440000000033713523072405020101 0ustar liggesusers##' Title ##' ##' Description ##' ##' Details ##' ##' @param x,y,z Descriptions for x, y, z ##' @param a Description of a ##' @param b ##' Description of b ##' @section Important: ##' Don't run with scissors! ##' @export roxygen2/tests/testthat/testRbuildignore/0000755000176200001440000000000013523072405020357 5ustar liggesusersroxygen2/tests/testthat/testRbuildignore/DESCRIPTION0000644000176200001440000000032713523072405022067 0ustar liggesusersPackage: testRbuildignore Title: Tools to make developing R code easier License: GPL-2 Description: Author: Francois Maintainer: Francois Version: 0.1 roxygen2/tests/testthat/testRbuildignore/R/0000755000176200001440000000000013523072405020560 5ustar liggesusersroxygen2/tests/testthat/testRbuildignore/R/a.R0000644000176200001440000000003013523072405021114 0ustar liggesusers#' function a #' a <- 1 roxygen2/tests/testthat/testRbuildignore/R/ignore_me.R0000644000176200001440000000007013523072405022644 0ustar liggesusers#' Ignore me, I'm not ready #' ignore_me <- "ignore me" roxygen2/tests/testthat/made-by-roxygen/0000755000176200001440000000000013523072405020041 5ustar liggesusersroxygen2/tests/testthat/made-by-roxygen/with-header.Rd0000644000176200001440000000010213523072405022522 0ustar liggesusers# Generated by roxygen2 (4.0.0): Do not edit by hand # Test file roxygen2/tests/testthat/made-by-roxygen/without-header.Rd0000644000176200001440000000001613523072405023256 0ustar liggesusers # Test file roxygen2/tests/testthat/made-by-roxygen/empty.Rd0000644000176200001440000000000013523072405021454 0ustar liggesusersroxygen2/tests/testthat/test-object-usage-wrap-new.txt0000644000176200001440000000106614115761233022663 0ustar liggesusersf( a = " a", b = " b", c = " c", d = " d" ) f( a = c("abcdef", "abcdef", "abcdef", "abcdef", "abcdef", "abcdef", "abcdef", "abcdef", "abcdef", "abcdef") ) \method{mean}{reallyratherquitelongclassname}( reallyreatherquitelongargument = "reallyratherquitelongvalue_____________________" ) long_replacement_fun( x, a = "aaaaaaaaaaaaaaaa", b = "aaaaaaaaaaaaaaaa", c = "aaaaaaaaaaaaaaaa" ) <- value roxygen2/tests/testthat/escapes.Rd0000644000176200001440000000010513523072405016740 0ustar liggesusers\name{x} \alias{x} \title{title} \description{ % Comment \code{\\} } roxygen2/tests/testthat/test-rd-examples-dontrun-escape-2.txt0000644000176200001440000000015213565531535024065 0ustar liggesusers> out$get_section("examples") \examples{ mtcars \%>\% identity() \dontrun{ mtcars \%>\% identity() } } roxygen2/tests/testthat/testNonASCII/0000755000176200001440000000000013523072405017235 5ustar liggesusersroxygen2/tests/testthat/testNonASCII/DESCRIPTION0000644000176200001440000000033213523072405020741 0ustar liggesusersPackage: testNonASCII Title: Test no change to Collate when there are no @includes License: GPL-2 Description: Author: Shrëktan Maintainer: Shrëktan Encoding: UTF-8 Version: 0.1 roxygen2/tests/testthat/testNonASCII/R/0000755000176200001440000000000013523072405017436 5ustar liggesusersroxygen2/tests/testthat/testNonASCII/R/a.r0000644000176200001440000000017013523072405020037 0ustar liggesusers#' 中文注释 #' #' @note 我爱中文。 printChineseMsg <- function() { message("我是UTF8的中文字符。") } roxygen2/tests/testthat/test-object-package-author.txt0000644000176200001440000000115614115761227022717 0ustar liggesusers> # Multiple given/family names > person_desc(c("First", "Second"), c("Family1", "Family2")) [1] "First Second Family1 Family2 \\email{h@w.com}" > # Multiple roles > person_desc(role = "ctb") [1] "H W \\email{h@w.com} [contributor]" > # ORCID comments > person_desc(comment = c(ORCID = "1234")) [1] "H W \\email{h@w.com} (\\href{https://orcid.org/1234}{ORCID})" > person_desc(comment = c(ORCID = "https://orcid.org/1234")) [1] "H W \\email{h@w.com} (\\href{https://orcid.org/1234}{ORCID})" > person_desc(comment = c(ORCID = "1234", "extra")) [1] "H W \\email{h@w.com} (\\href{https://orcid.org/1234}{ORCID}) (extra)" roxygen2/tests/testthat/test-rd-examples-interleave.txt0000644000176200001440000000014014115761227023125 0ustar liggesusers> out$get_section("examples") \examples{ example <- 'example1' a <- 2 example <- 'example2' } roxygen2/tests/testthat/test-rd-examplesIf.txt0000644000176200001440000000050414115761227021254 0ustar liggesusers> out$get_section("examples") \examples{ \dontshow{if (foo::bar()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} maybe-run-this-code \dontshow{\}) # examplesIf} \dontshow{if (foobar()) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} and-this \dontshow{\}) # examplesIf} } roxygen2/tests/testthat/test-options/0000755000176200001440000000000014116067732017510 5ustar liggesusersroxygen2/tests/testthat/test-options/meta-error.R0000644000176200001440000000003213540202201021661 0ustar liggesusersstop("This is an error!") roxygen2/tests/testthat/test-options/man/0000755000176200001440000000000014115763566020272 5ustar liggesusersroxygen2/tests/testthat/test-options/man/roxygen/0000755000176200001440000000000013540202201021734 5ustar liggesusersroxygen2/tests/testthat/test-options/man/roxygen/meta.R0000644000176200001440000000003213540202201023000 0ustar liggesuserslist( markdown = TRUE ) roxygen2/tests/testthat/test-options/DESCRIPTION0000644000176200001440000000004013542232227021203 0ustar liggesusersRoxygen: list(old_usage = TRUE) roxygen2/tests/testthat/test-options/meta-character.R0000644000176200001440000000000413540202201022463 0ustar liggesusers"a" roxygen2/tests/testthat/testLazyData/0000755000176200001440000000000013523072405017443 5ustar liggesusersroxygen2/tests/testthat/testLazyData/NAMESPACE0000644000176200001440000000005613523072405020663 0ustar liggesusers# Generated by roxygen2: do not edit by hand roxygen2/tests/testthat/testLazyData/data/0000755000176200001440000000000013523072405020354 5ustar liggesusersroxygen2/tests/testthat/testLazyData/data/a.rda0000644000176200001440000000011513523072405021261 0ustar liggesusersBZh91AY&SY C1D@  !2B`3(AܩA<^fV"(H_^!roxygen2/tests/testthat/testLazyData/DESCRIPTION0000644000176200001440000000033313523072405021150 0ustar liggesusersPackage: testEagerData Title: Tools to make developing R code easier License: GPL-2 Description: Author: Hadley Maintainer: Hadley Version: 0.1 LazyData: TRUE Encoding: UTF-8 roxygen2/tests/testthat/testLazyData/R/0000755000176200001440000000000013523072405017644 5ustar liggesusersroxygen2/tests/testthat/testLazyData/R/a.r0000644000176200001440000000002713523072405020246 0ustar liggesusers#' Data #' #' Desc "a" roxygen2/tests/testthat/test-rd-r6.R0000644000176200001440000002305013560326573017075 0ustar liggesusers test_that("extract_r6_data without source refs", { txt <- "R6::R6Class( public = list( field1 = NULL, meth1 = function(Z) { }, meth2 = function(Z = 10, ...) { }, field2 = \"foobar\", meth3 = function() { } ) )" C <- eval(parse(text = txt, keep.source = FALSE)) expect_error(extract_r6_data(C), "without source references") }) test_that("extract_r6_methods", { txt <- "R6::R6Class( public = list( field1 = NULL, meth1 = function(Z) { }, meth2 = function(Z = 10, ...) { }, field2 = \"foobar\", meth3 = function() { } ) )" C <- eval(parse(text = txt, keep.source = TRUE)) M <- extract_r6_methods(C) expect_equal(M$type, rep("method", 4)) expect_equal(M$name, c(paste0("meth", 1:3), "clone")) expect_equal(M$line, c(4L, 5L, 7L, NA_integer_)) expect_equal( M$formals, I(list( as.pairlist(alist(Z=)), as.pairlist(alist(Z = 10, ... = )), NULL, as.pairlist(alist(deep = FALSE)) )) ) }) test_that("extract_r6_super_data", { eval(parse(test_path("roxygen-block-3.R"), keep.source = TRUE)) D <- extract_r6_super_data(C) mypkg <- environmentName(topenv()) expect_equal(D$classes$package, rep(mypkg, 2)) expect_equal(D$classes$classname, c("B", "A")) expect_equal(D$members$package, rep(mypkg, 18)) expect_equal(D$members$classname, rep(c("B", "A"), c(8, 10))) expect_equal( D$members$type, c("method", "method", "method", "field", "field", "active", "active", "active", "method", "method", "method", "method", "field", "field", "field", "active", "active", "active") ) expect_equal( D$members$name, c("meth4", "meth1", "clone", "field4", "field1", "active5", "active4", "active1", "meth3", "meth2", "meth1", "clone", "field3", "field2", "field1", "active3", "active2", "active1") ) }) test_that("extract_r6_fields", { C <- R6::R6Class( public = list( field1 = NULL, meth1 = function() { }, field2 = "foobar" ) ) F <- extract_r6_fields(C) expect_equal(F$type, rep("field", 2)) expect_equal(F$name, c("field1", "field2")) C <- R6::R6Class( public = list( meth1 = function() { } ) ) F <- extract_r6_fields(C) expect_s3_class(F, "data.frame") expect_equal(F$type, character()) expect_equal(F$name, character()) C <- R6::R6Class() F <- extract_r6_fields(C) expect_s3_class(F, "data.frame") expect_equal(F$type, character()) expect_equal(F$name, character()) }) test_that("extract_r6_bindings", { C <- R6::R6Class( active = list( bind1 = function(x) { }, bind2 = function(x) { } ), public = list( meth1 = function() { } ) ) F <- extract_r6_bindings(C) expect_equal(F$type, rep("active", 2)) expect_equal(F$name, c("bind1", "bind2")) C <- R6::R6Class( public = list( meth1 = function() { } ) ) F <- extract_r6_bindings(C) expect_s3_class(F, "data.frame") expect_equal(F$type, character()) expect_equal(F$name, character()) C <- R6::R6Class() F <- extract_r6_bindings(C) expect_s3_class(F, "data.frame") expect_equal(F$type, character()) expect_equal(F$name, character()) }) test_that("r6_fields", { text <- " #' @title Title #' @description Description. #' @details Details. #' @field field1 Foo. #' @field field2 Bar. #' @field bind1 Active binding. C <- R6::R6Class( public = list( field1 = NULL, field2 = \"foobar\" ), active = list( bind1 = function(x) { } ) )" block <- parse_text(text)[[1]] r6data <- block_get_tag_value(block, ".r6data") expect_silent(doc <- r6_fields(block, r6data)) expect_true(any(grepl("code{field1}}{Foo.", doc, fixed = TRUE))) expect_true(any(grepl("code{field2}}{Bar.", doc, fixed = TRUE))) }) test_that("r6_active_bindings", { text <- " #' @title Title #' @description Description. #' @details Details. #' @field bind1 Active binding. #' @field bind2 Active 2. C <- R6::R6Class( public = list( field1 = NULL, field2 = \"foobar\" ), active = list( bind1 = function(x) { }, bind2 = function(x) { } ) )" block <- parse_text(text)[[1]] r6data <- block_get_tag_value(block, ".r6data") expect_silent(doc <- r6_active_bindings(block, r6data)) expect_true(any(grepl("code{bind1}}{Active binding.", doc, fixed = TRUE))) expect_true(any(grepl("code{bind2}}{Active 2.", doc, fixed = TRUE))) }) test_that("R6 edge cases, class without methods", { text <- " #' @title Title #' @description Description. #' @details Details. #' @field field1 Field. #' @field field2 Another field. #' @field bind1 Active binding. #' @field bind2 Active 2. C <- R6::R6Class( cloneable = FALSE, public = list( field1 = NULL, field2 = \"foobar\" ), active = list( bind1 = function(x) { }, bind2 = function(x) { } ) )" block <- parse_text(text)[[1]] rd <- RoxyTopic$new() expect_silent(topic_add_r6_methods(rd, block, environment())) expect_false(grepl("method", format(rd), ignore.case = TRUE)) }) test_that("R6 edge cases, class without (documented) fields", { text <- " #' @title Title #' @description Description. #' @details Details. #' @field bind1 Active binding. #' @field bind2 Active 2. C <- R6::R6Class( public = list( ), active = list( bind1 = function(x) { }, bind2 = function(x) { } ) )" block <- parse_text(text)[[1]] rd <- RoxyTopic$new() expect_silent(topic_add_r6_methods(rd, block, environment())) expect_false(grepl("field", format(rd), ignore.case = TRUE)) text <- " #' @title Title #' @description Description. #' @details Details. #' @field bind1 Active binding. #' @field bind2 Active 2. C <- R6::R6Class( public = list( undocumented_field = NULL ), active = list( bind1 = function(x) { }, bind2 = function(x) { } ) )" block <- parse_text(text)[[1]] rd <- RoxyTopic$new() expect_warning(topic_add_r6_methods(rd, block, environment())) expect_false(grepl("field", format(rd), ignore.case = TRUE)) }) test_that("R6 edge cases, class without active bindings", { text <- " #' @title Title #' @description Description. #' @details Details. #' @field field1 Field. #' @field field2 Another field. C <- R6::R6Class( public = list( field1 = NULL, field2 = \"foobar\" ), active = list( ) )" block <- parse_text(text)[[1]] rd <- RoxyTopic$new() expect_silent(topic_add_r6_methods(rd, block, environment())) expect_false(grepl("active", format(rd), ignore.case = TRUE)) }) test_that("R6 edge cases, class without anything", { text <- " #' @title Title #' @description Description. #' @details Details. C <- R6::R6Class( cloneable = FALSE, public = list( ), active = list( ) )" block <- parse_text(text)[[1]] rd <- RoxyTopic$new() expect_silent(topic_add_r6_methods(rd, block, environment())) doc <- format(rd) expect_false(grepl("method", format(rd), ignore.case = TRUE)) expect_false(grepl("field", format(rd), ignore.case = TRUE)) expect_false(grepl("active", format(rd), ignore.case = TRUE)) }) test_that("warning if no method comes after the docs", { text <- " #' @title Title #' @description Description. #' @details Details. #' @field field1 Yep. C <- R6::R6Class( public = list( #' @description Method 1. method1 = function() { }, #' @description Dangling. field1 = NULL ) )" eval(parse(text = text, keep.source = TRUE)) block <- parse_text(text, env = environment())[[1]] rd <- RoxyTopic$new() expect_warning( topic_add_r6_methods(rd, block, environment()), "Cannot find matching R6 method" ) doc <- format(rd) }) test_that("integration test", { wd <- getwd() on.exit(setwd(wd), add = TRUE) setwd(test_path()) env <- new.env(parent = asNamespace("roxygen2")) eval( parse(test_path("roxygen-block-3.R"), keep.source = TRUE), envir = env ) blocks <- parse_file(test_path("roxygen-block-3.R"), env = env) roc <- roclet_preprocess(roclet_find("rd")) roxy_warnings <- character() withCallingHandlers( res <- roclet_process(roc, blocks = blocks, env = env, base_path = test_path()), warning = function(w) { roxy_warnings <<- c(roxy_warnings, w$message) invokeRestart("muffleWarning") } ) # Warnings verify_output( test_path(paste0("roxygen-block-3-warnings.txt")), sort(roxy_warnings) ) tmp <- tempfile() on.exit(unlink(tmp), add = TRUE) for (n in names(res)) { path <- test_path(paste0("roxygen-block-3-", n)) verify_output(path, res[[n]]) cat(format(res[[n]]), file = tmp) expect_silent(chk <- tools::checkRd(tmp)) expect_equal(length(chk), 0L) } }) test_that("r6 option", { text <- " #' @title Title #' @description Description. C <- R6::R6Class( public = list( field = NULL, #' @description Method desc. #' @param arg Method arg. meth = function(arg) { } ) )" old <- roxy_meta_get("r6") on.exit(roxy_meta_set("r6", old), add = TRUE) roxy_meta_set("r6", FALSE) expect_silent( out <- roc_proc_text(rd_roclet(), text) ) rd <- format(out$C.Rd) expect_false(grepl("section{Methods}", rd, fixed = TRUE)) expect_true(grepl("arguments{", rd, fixed = TRUE)) }) roxygen2/tests/testthat/test-rd-inherit-link.txt0000644000176200001440000000026014115761231021546 0ustar liggesusers> # \link{} should include [digest] > out$get_section("param") \arguments{ \item{algo}{The hashing algoritm to be used by \code{\link[digest]{digest}}. Defaults to "sha1"} } roxygen2/tests/testthat/test-rd-inherit-dots.txt0000644000176200001440000000025014115761231021561 0ustar liggesusers> out$get_section("param") \arguments{ \item{...}{ Arguments passed on to \code{\link[=foo]{foo}} \describe{ \item{\code{x}}{x} \item{\code{y}}{y} }} } roxygen2/tests/testthat/test-block-print.txt0000644000176200001440000000060514115761220020773 0ustar liggesusers> block [:5] $tag [line: 1] @title 'This is a title' {parsed} [line: 3] @param 'x,y A number' {parsed} [line: 4] @export '' {parsed} [????:???] @usage '' {parsed} [????:???] @.formals '' {parsed} [????:???] @backref '' {parsed} $call f <- function(x, y) x + y $object $topic f $alias f roxygen2/tests/testthat/test-rd-raw.R0000644000176200001440000000156413542230252017331 0ustar liggesuserstest_that("rawRd inserted unchanged", { out <- roc_proc_text(rd_roclet(), " #' @rawRd #this is a comment #' @name a #' @title a NULL")[[1]] lines <- strsplit(format(out), "\n")[[1]] expect_equal(lines[[9]], "#this is a comment") }) test_that("evalRd must be valid code", { expect_warning( roc_proc_text(rd_roclet(), " #' @evalRd a + #' @name a #' @title a NULL"), "code failed to parse" ) }) test_that("error-ful evalRd generates warning", { expect_warning( roc_proc_text(rd_roclet(), " #' @evalRd stop('!') #' @name a #' @title a NULL"), "failed with error" ) }) test_that("evalRd inserted unchanged", { out <- roc_proc_text(rd_roclet(), " z <- 10 #' @evalRd as.character(z * 2) #' @name a #' @title a NULL")[[1]] expect_equal(out$get_value("rawRd"), "20") }) roxygen2/tests/testthat/test-options.R0000644000176200001440000000077313542232213017630 0ustar liggesuserstest_that("merged options from can load options from DESCRIPTION", { opts <- load_options(test_path("test-options")) expect_equal(opts$old_usage, TRUE) # from DESCRIPTION expect_equal(opts$markdown, TRUE) # from meta.R }) test_that("warns on invalid meta.R files", { expect_warning( load_options_meta(test_path("test-options"), "meta-error.R"), "Failed to source" ) expect_warning( load_options_meta(test_path("test-options"), "meta-character.R"), "yield a named list" ) }) roxygen2/tests/testthat/testCollateOverwrite/0000755000176200001440000000000013523072405021224 5ustar liggesusersroxygen2/tests/testthat/testCollateOverwrite/DESCRIPTION0000644000176200001440000000032514115761221022731 0ustar liggesusersPackage: testCollateMissing Title: Tools to make developing R code easier License: GPL-2 Description: Author: Hadley Maintainer: Hadley Version: 0.1 Collate: 'b.r' roxygen2/tests/testthat/testCollateOverwrite/R/0000755000176200001440000000000013523072405021425 5ustar liggesusersroxygen2/tests/testthat/testCollateOverwrite/R/a.r0000644000176200001440000000002713523072405022027 0ustar liggesusers#' @include b.r a <- 1 roxygen2/tests/testthat/testCollateOverwrite/R/b.r0000644000176200001440000000000613523072405022025 0ustar liggesusersb <- 2roxygen2/tests/testthat/test-object-package.R0000644000176200001440000000127513631767006021006 0ustar liggesuserstest_that("person turned into meaningful text", { person_desc <- function(given = "H", family = "W", email = "h@w.com", role = "aut", comment = NULL) { out <- person(given = given, family = family, email = email, role = role, comment = comment) author_desc(unclass(out)[[1]]) } verify_output(test_path("test-object-package-author.txt"), { "Multiple given/family names" person_desc(c("First", "Second"), c("Family1", "Family2")) "Multiple roles" person_desc(role = "ctb") "ORCID comments" person_desc(comment = c("ORCID" = "1234")) person_desc(comment = c("ORCID" = "https://orcid.org/1234")) person_desc(comment = c("ORCID" = "1234", "extra")) }) }) roxygen2/tests/testthat/test-utils.R0000644000176200001440000000403313631761132017274 0ustar liggesusers# nice_names -------------------------------------------------------------- test_that("nice_name leaves ok chars unchanged", { expect_equal(nice_name("abc"), "abc") expect_equal(nice_name("a_b-c.R"), "a_b-c.R") }) test_that("nice_name protects against invalid characters", { expect_equal(nice_name("a<-"), "a-set") expect_equal(nice_name("[.a"), "sub-.a") }) test_that("write_if_different and end of line", { cnt_unix <- c("foo\nbar\nbaz", "foobar") cnt_win <- c("foo\r\nbar\r\nbaz", "foobar") cnt_mix <- c("foo\nbar\r\nbaz", "foobar") tmp <- tempfile("roxy-", fileext = ".Rd") on.exit(unlink(tmp), add = TRUE) # do not change unix le write_lines(cnt_unix, tmp, line_ending = "\n") expect_silent(write_if_different(tmp, cnt_unix, check = FALSE)) expect_silent(write_if_different(tmp, cnt_win, check = FALSE)) expect_silent(write_if_different(tmp, cnt_mix, check = FALSE)) # do not change windows le write_lines(cnt_win, tmp, line_ending = "\r\n") expect_silent(write_if_different(tmp, cnt_unix, check = FALSE)) expect_silent(write_if_different(tmp, cnt_win, check = FALSE)) expect_silent(write_if_different(tmp, cnt_mix, check = FALSE)) # change mixed le to windows tmp_win <- tempfile("roxy-", fileext = ".Rd") on.exit(unlink(tmp_win), add = TRUE) write_lines(cnt_win, tmp_win, line_ending = "\r\n") # write_lines changes line endings, so we use writeBin to create a file with mixed # line endings raw_mix <- charToRaw(paste0(paste0(cnt_mix, collapse = "\r\n"), "\r\n")) writeBin(raw_mix, tmp) expect_output(write_if_different(tmp, cnt_unix, check = FALSE), "Writing ") expect_identical(readBin(tmp, "raw", 100), readBin(tmp_win, "raw", 100)) writeBin(raw_mix, tmp) expect_output(write_if_different(tmp, cnt_win, check = FALSE), "Writing ") expect_identical(readBin(tmp, "raw", 100), readBin(tmp_win, "raw", 100)) writeBin(raw_mix, tmp) expect_output(write_if_different(tmp, cnt_mix, check = FALSE), "Writing ") expect_identical(readBin(tmp, "raw", 100), readBin(tmp_win, "raw", 100)) }) roxygen2/tests/testthat/test-rd-inherit.R0000644000176200001440000003203313544473137020212 0ustar liggesusers# Rd parsing -------------------------------------------------------------- test_that("can round-trip Rd", { rd <- tools::parse_Rd(test_path("escapes.Rd")) field <- find_field(rd, "description") lines <- strsplit(field, "\n")[[1]] expect_equal( lines, c( "% Comment", # Latex comments shouldn't be escaped "\\code{\\\\}" # Backslashes in code should be ) ) }) test_that("\\links are transformed", { out <- roc_proc_text(rd_roclet(), " #' Title #' #' @inheritParams digest::sha1 wrapper <- function(algo) {}" )[[1]] verify_output( test_path("test-rd-inherit-link.txt"), { "\\link{} should include [digest]" out$get_section("param") } ) }) # tag parsing ------------------------------------------------------------- test_that("warns on unknown inherit type", { expect_warning( parse_text(" #' @inherit fun blah NULL "), "Unknown inherit type: blah" ) }) test_that("no options gives default values", { block <- parse_text(" #' @inherit fun NULL ")[[1]] expect_equal( block_get_tag_value(block, "inherit")$fields, c( "params", "return", "title", "description", "details", "seealso", "sections", "references", "examples", "author", "source" ) ) }) test_that("some options overrides defaults", { block <- parse_text(" #' @inherit fun return NULL ")[[1]] expect_equal(block_get_tag_value(block, "inherit")$fields, "return") }) # Inherit return values --------------------------------------------------- test_that("can inherit return values from roxygen topic", { out <- roc_proc_text(rd_roclet(), " #' A. #' #' @return ABC a <- function(x) {} #' B #' #' @inherit a b <- function(y) {} ")[[2]] expect_equal(out$get_value("value"), "ABC") }) test_that("takes value from first with return", { out <- roc_proc_text(rd_roclet(), " #' A1 #' @return A a1 <- function(x) {} #' A2 a2 <- function() {} #' B #' @return B b <- function(x) {} #' C #' @inherit a2 #' @inherit b #' @inherit a1 c <- function(y) {} ")[[3]] expect_equal(out$get_value("value"), "B") }) test_that("can inherit return value from external function", { out <- roc_proc_text(rd_roclet(), " #' A1 #' @inherit base::mean a1 <- function(x) {} ")[[1]] expect_match(out$get_value("value"), "before the mean is computed.$") expect_match(out$get_value("value"), "^If \\\\code") }) # Inherit seealso --------------------------------------------------------- test_that("can inherit return values from roxygen topic", { out <- roc_proc_text(rd_roclet(), " #' A. #' #' @seealso ABC a <- function(x) {} #' B #' #' @inherit a b <- function(y) {} ")[[2]] expect_equal(out$get_value("seealso"), "ABC") }) # Inherit description and details ----------------------------------------- test_that("can inherit description from roxygen topic", { out <- roc_proc_text(rd_roclet(), " #' A. #' #' B #' #' @return ABC a <- function(x) {} #' @title C #' @inherit a description b <- function(y) {} ")[[2]] expect_equal(out$get_value("description"), "B") }) test_that("inherits description if omitted", { out <- roc_proc_text(rd_roclet(), " #' A. #' #' B #' #' @return ABC a <- function(x) {} #' C #' @inherit a description b <- function(y) {} ")[[2]] expect_equal(out$get_value("description"), "B") }) test_that("can inherit details from roxygen topic", { out <- roc_proc_text(rd_roclet(), " #' A. #' #' B #' #' C #' #' @return ABC a <- function(x) {} #' D #' #' E #' #' @inherit a details b <- function(y) {} ")[[2]] expect_equal(out$get_value("description"), "E") expect_equal(out$get_value("details"), "C") }) # Inherit sections -------------------------------------------------------- test_that("inherits missing sections", { out <- roc_proc_text(rd_roclet(), " #' A. #' @section A:1 #' @section B:1 a <- function(x) {} #' D #' #' @section A:2 #' @inherit a sections b <- function(y) {} ")[[2]] section <- out$get_value("section") expect_equal(section$title, c("A", "B")) expect_equal(section$content, c("2", "1")) }) test_that("can inherit single section", { out <- roc_proc_text(rd_roclet(), " #' A. #' @section A:1 #' @section B:1 a <- function(x) {} #' D #' #' @inheritSection a B b <- function(y) {} ")[[2]] section <- out$get_value("section") expect_equal(section$title, "B") expect_equal(section$content, "1") }) # Inherit parameters ------------------------------------------------------ test_that("multiple @inheritParam tags gathers all params", { out <- roc_proc_text(rd_roclet(), " #' A. #' #' @param x X a <- function(x) {} #' B #' #' @param y Y b <- function(y) {} #' C #' #' @inheritParams a #' @inheritParams b c <- function(x, y) {} ") params <- out[["c.Rd"]]$get_value("param") expect_equal(length(params), 2) expect_equal(params[["x"]], "X") expect_equal(params[["y"]], "Y") }) test_that("multiple @inheritParam tags gathers all params", { out <- roc_proc_text(rd_roclet(), " #' A. #' #' @param x X a <- function(x) {} #' B #' #' @param .y Y b <- function(.y) {} #' C #' #' @inheritParams a #' @inheritParams b c <- function(.x, y) {} ") params <- out[["c.Rd"]]$get_value("param") expect_equal(length(params), 2) expect_equal(params[[".x"]], "X") expect_equal(params[["y"]], "Y") }) test_that("@inheritParams can inherit from inherited params", { out <- roc_proc_text(rd_roclet(), " #' C #' #' @inheritParams b c <- function(x) {} #' B #' #' @inheritParams a b <- function(x) {} #' A. #' #' @param x X a <- function(x) {} ") expect_equal(out[["c.Rd"]]$get_value("param"), c(x = "X")) }) test_that("multiple @inheritParam inherits from existing topics", { out <- roc_proc_text(rd_roclet(), " #' My mean #' #' @inheritParams base::mean mymean <- function(x, trim) {}")[[1]] params <- out$get_value("param") expect_equal(length(params), 2) expect_equal(sort(names(params)), c("trim", "x")) }) test_that("@inheritParam can cope with multivariable argument definitions", { out <- roc_proc_text(rd_roclet(), " #' My merge #' #' @inheritParams base::merge mymerge <- function(x, y) {}")[[1]] params <- out$get_value("param") expect_equal(length(params), 2) expect_equal(sort(names(params)), c("x", "y")) }) test_that("@inheritParam understands compound docs", { out <- roc_proc_text(rd_roclet(), " #' Title #' #' @param x x #' @param y x x <- function(x, y) {} #' Title #' #' @inheritParams x #' @param y y y <- function(x, y) {}")[[2]] params <- out$get_value("param") expect_equal(params, c(x = "x", y = "y")) }) test_that("warned if no params need documentation", { code <- " #' Title #' #' @param x x #' @param y x #' @inheritParams foo x <- function(x, y) {} " expect_warning(roc_proc_text(rd_roclet(), code), "no parameters to inherit") }) test_that("argument order, also for incomplete documentation", { out <- roc_proc_text(rd_roclet(), " #' A. #' #' @param y Y #' @param x X a <- function(x, y) {} #' B #' #' @param y Y b <- function(x, y) {} #' C #' #' @param x X c <- function(x, y) {} #' D #' #' @inheritParams b #' @param z Z d <- function(x, y, z) {} #' E #' #' @inheritParams c #' @param y Y e <- function(x, y, z) {} ") expect_equal(out[["a.Rd"]]$get_value("param"), c(x="X", y="Y")) expect_equal(out[["b.Rd"]]$get_value("param"), c(y="Y")) expect_equal(out[["c.Rd"]]$get_value("param"), c(x="X")) expect_equal(out[["d.Rd"]]$get_value("param"), c(y="Y", z="Z")) expect_equal(out[["e.Rd"]]$get_value("param"), c(x="X", y="Y")) }) test_that("argument order with @inheritParam", { out <- roc_proc_text(rd_roclet(), " #' A. #' #' @param x X #' @param y Y a <- function(x, y) {} #' B1 #' #' @param y B #' @inheritParams a b1 <- function(x, y) {} #' B2 #' #' @inheritParams a #' @param y B b2 <- function(x, y) {} #' C1 #' #' @param x C #' @inheritParams a c1 <- function(x, y) {} #' C2 #' #' @inheritParams a #' @param x C c2<- function(x, y) {} ") expect_equal(out[["b1.Rd"]]$get_value("param"), c(x = "X", y = "B")) expect_equal(out[["b2.Rd"]]$get_value("param"), c(x = "X", y = "B")) expect_equal(out[["c1.Rd"]]$get_value("param"), c(x = "C", y = "Y")) expect_equal(out[["c2.Rd"]]$get_value("param"), c(x = "C", y = "Y")) }) test_that("inherit params ... named \\dots", { out <- roc_proc_text(rd_roclet(), " #' Foo #' #' @param x x #' @param \\dots foo foo <- function(x, ...) {} #' Bar #' #' @inheritParams foo #' @param \\dots bar bar <- function(x=1, ...) {} ")[[2]] expect_equal( out$get_value("param"), c(x = "x", "\\dots" = "bar") ) }) # inheritDotParams -------------------------------------------------------- test_that("can inherit all from single function", { out <- roc_proc_text(rd_roclet(), " #' Foo #' #' @param x x #' @param y y foo <- function(x, y) {} #' Bar #' #' @inheritDotParams foo bar <- function(...) {} ")[[2]] verify_output( test_path("test-rd-inherit-dots.txt"), out$get_section("param") ) }) test_that("does not produce multiple ... args", { out <- roc_proc_text(rd_roclet(), " #' Foo #' #' @inheritParams bar #' @inheritDotParams baz foo <- function(x, ...) {} #' Bar #' #' @param x x #' @param ... dots bar <- function(x, ...) {} #' Baz #' #' @param y y #' @param z z baz <- function(y, z) {} ")[[1]] verify_output( test_path("test-rd-inherit-dots-inherit.txt"), out$get_section("param") ) }) test_that("can inherit dots from several functions", { out <- roc_proc_text(rd_roclet(), " #' Foo #' #' @param x x #' @param y y1 foo <- function(x, y) {} #' Bar #' #' @param y y2 #' @param z z bar <- function(z) {} #' Foobar #' #' @inheritDotParams foo #' @inheritDotParams bar foobar <- function(...) {} ")[[3]] verify_output( test_path("test-rd-inherit-dots-multi.txt"), out$get_section("param") ) }) test_that("inheritDotParams does not add already-documented params", { out <- roc_proc_text(rd_roclet(), " #' Wrapper around original #' #' @inherit original #' @inheritDotParams original #' @param y some more specific description #' @export wrapper <- function(x = 'some_value', y = 'some other value', ...) { original(x = x, y = y, ...) } #' Original function #' #' @param x x description #' @param y y description #' @param z z description #' @export original <- function(x, y, z, ...) {} ")[[1]] params <- out$get_value("param") dot_param <- params[["..."]] expect_named(params, c("x", "y", "...")) expect_false(grepl("item{x}{x description}", dot_param, fixed = TRUE)) expect_false(grepl("item{y}{y description}", dot_param, fixed = TRUE)) expect_match(dot_param, "item{\\code{z}}{z description}", fixed = TRUE) }) # inherit everything ------------------------------------------------------ test_that("can inherit all from single function", { out <- roc_proc_text(rd_roclet(), " #' Foo #' #' Description #' #' Details #' #' @param x x #' @param y y #' @author Hadley #' @source my mind #' @examples #' x <- 1 foo <- function(x, y) {} #' @inherit foo bar <- function(x, y) {} ")[[2]] expect_named(out$get_value("param"), c("x", "y")) expect_equal(out$get_value("title"), "Foo") expect_equal(out$get_value("description"), "Description") expect_equal(out$get_value("details"), "Details") expect_equal(out$get_value("examples"), rd("x <- 1")) expect_equal(out$get_value("author"), "Hadley") expect_equal(out$get_value("source"), "my mind") }) # get_rd() ----------------------------------------------------------------- test_that("useful warnings if can't find topics", { expect_warning(get_rd("base2::attach"), "Can't find package") expect_warning(get_rd("base::function_not_found"), "Can't find help topic") expect_warning(get_rd("function", RoxyTopics$new()), "Can't find help topic") }) test_that("can find section in existing docs", { out <- find_sections(get_rd("base::attach")) expect_equal(out$title, "Good practice") }) # find_params ------------------------------------------------------------- test_that("find_params parses input", { params <- find_params("utils::`?`", NULL) expect_equal(names(params), c("topic", "type")) }) roxygen2/tests/testthat/test-rd.R0000644000176200001440000001123113631761325016543 0ustar liggesuserstest_that("empty file gives empty list", { out <- roc_proc_text(rd_roclet(), "") expect_identical(out, list()) }) test_that("NULL gives empty list", { out <- roc_proc_text(rd_roclet(), "NULL") expect_identical(out, list()) }) test_that("@noRd inhibits documentation", { out <- roc_proc_text(rd_roclet(), " #' Would be title #' @title Overridden title #' @name a #' @noRd NULL") expect_equal(length(out), 0) }) test_that("deleted objects not documented", { out <- roc_proc_text(rd_roclet(), " f <- function(){ .a <- 0 function(x = 1){ .a <<- .a + x .a } } #' Addition function. f2 <- f() rm(f) ") expect_equal(names(out), "f2.Rd") }) test_that("documenting unknown function requires name", { expect_warning( roc_proc_text(rd_roclet(), " #' Virtual Class To Enforce Max Slot Length setClass('A') #' Validity function. setValidity('A', function(object) TRUE)" ), "Missing name" ) }) test_that("documenting NA gives useful error message (#194)", { expect_warning( roc_proc_text(rd_roclet(), " #' Missing value NA" ), "Missing name" ) }) test_that("@description NULL", { # Just ignore in this case out <- roxygen2::roc_proc_text(roxygen2::rd_roclet(), " #' Title #' #' @description NULL #' @format NULL foobar <- 1:10 ") expect_identical(out[[1]]$get_value("description"), "Title") # Still ignore out <- roxygen2::roc_proc_text(roxygen2::rd_roclet(), " #' Title #' @description NULL #' @description desc #' @format NULL foobar <- 1:10 ") expect_identical(out[[1]]$get_value("description"), "desc") # Still ignore for objects as well out <- roxygen2::roc_proc_text(roxygen2::rd_roclet(), " #' Title #' @description NULL #' @format NULL foobar <- 1:10 ") expect_identical(out[[1]]$get_value("description"), "Title") # But drop for package docs with_mock( `roxygen2::read.description` = function(...) list(Package = "roxygen_devtest", Title = "Package Title", Description = "Package description."), out <- roxygen2::roc_proc_text(roxygen2::rd_roclet(), " #' Title #' #' @docType package #' @description NULL #' @name pkg '_PACKAGE' ") ) expect_null(out[[1]]$get_value("description")) }) test_that("@details NULL", { # Just ignore in this case out <- roxygen2::roc_proc_text(roxygen2::rd_roclet(), " #' Title #' #' @details NULL #' @format NULL foobar <- 1:10 ") expect_null(out[[1]]$get_value("details")) # Still ignore out <- roxygen2::roc_proc_text(roxygen2::rd_roclet(), " #' Title #' @details NULL #' @details desc #' @format NULL foobar <- 1:10 ") expect_identical(out[[1]]$get_value("details"), "desc") # Still ignore for objects as well out <- roxygen2::roc_proc_text(roxygen2::rd_roclet(), " #' Title #' @details NULL #' @format NULL foobar <- 1:10 ") expect_null(out[[1]]$get_value("details")) }) # UTF-8 ------------------------------------------------------------------- test_that("can generate nonASCII document", { test_pkg <- temp_copy_pkg(test_path('testNonASCII')) on.exit(unlink(test_pkg, recursive = TRUE), add = TRUE) expect_output(roxygenise(test_pkg, roclets = "rd"), "printChineseMsg[.]Rd") rd_path <- file.path(test_pkg, "man", "printChineseMsg.Rd") expect_true(file.exists(rd_path)) rd <- read_lines(rd_path) expect_true(any(grepl("\u6211\u7231\u4e2d\u6587", rd))) expect_true(any(grepl("\u4e2d\u6587\u6ce8\u91ca", rd))) # Shouldn't change again expect_output(roxygenise(test_pkg, roclets = "rd"), NA) }) test_that("unicode escapes are ok", { test_pkg <- temp_copy_pkg(test_path('testUtf8Escape')) on.exit(unlink(test_pkg, recursive = TRUE), add = TRUE) expect_output(roxygenise(test_pkg, roclets = "rd"), "a[.]Rd") rd_path <- file.path(test_pkg, "man", "a.Rd") expect_true(file.exists(rd_path)) rd <- read_lines(rd_path) expect_true(any(grepl("7\u00b0C", rd))) # Shouldn't change again expect_output(roxygenise(test_pkg, roclets = "rd"), NA) }) test_that("write_lines writes unix-style line endings.", { path <- test_path("escapes.Rd") # skip if checked on windows with autocrlf = true skip_if(detect_line_ending(path) == "\r\n") temp_filename <- tempfile() old_binary <- readBin(path, "raw", n = file.info(path)$size) old_text <- read_lines(path) write_lines(old_text, temp_filename) on.exit(unlink(temp_filename), add = TRUE) new_binary <- readBin(temp_filename, "raw", n = file.info(temp_filename)$size) expect_identical(new_binary, old_binary) }) roxygen2/tests/testthat/test-rd-markdown-escaping.R0000644000176200001440000000535613542230466022163 0ustar liggesuserstag_df <- function(tag, start, end, argend = NULL) { df <- data.frame( stringsAsFactors = FALSE, tag = tag, start = start, end = end ) if (!is.null(argend)) df$argend <- argend df } test_that("find_all_tag_names", { text <- "blah blah \\mytag blah blah" expect_equal( find_all_tag_names(text), tag_df("\\mytag", 11, 16) ) }) test_that("find_all_rd_tags", { cases <- list( ## No tags list("", character(), numeric(), numeric(), numeric()), list("nothing to see here", character(), numeric(), numeric(), numeric()), list("\nstill\nnothing\n", character(), numeric(), numeric(), numeric()), ## One tag list("blah blah \\mytag blah blah", "\\mytag", 11, 16, 16), list("blah blah \\mytag{arg1} blah blah", "\\mytag", 11, 16, 22), list("blah blah \\mytag{arg1}{arg2} blah blah", "\\mytag", 11, 16, 28), list("blah\\mytag", "\\mytag", 5, 10, 10), list("blah \\mytag", "\\mytag", 6, 11, 11), list("blah\\mytag{arg}", "\\mytag", 5, 10, 15), list("\\mytag hoohoo", "\\mytag", 1, 6, 6), list("\\mytag", "\\mytag", 1, 6, 6), list("\\mytag{arg}", "\\mytag", 1, 6, 11), list("blah \\mytag\nblah blah", "\\mytag", 6, 11, 11), ## Multiple tags list("blah \\tag1 \\tag2{arg} blah", c("\\tag1", "\\tag2"), c(6, 12), c(10, 16), c(10, 21)), list("blah \\tag1{ \\tag2{arg} } blah", c("\\tag1", "\\tag2"), c(6, 13), c(10, 17), c(24, 22)), list("blah \\tag1{\n\\tag2{arg}\n} blah", c("\\tag1", "\\tag2"), c(6, 13), c(10, 17), c(24, 22)) ) for (case in cases) { expect_equal( find_all_rd_tags(case[[1]]), do.call(tag_df, case[-1]), info = case[[1]] ) } }) test_that("find_fragile_rd_tags", { fragile <- c("\\frag", "\\frag1", "\\frag2") cases <- list( list("This is \\frag{here}, \\this{arg} not", "\\frag"), list("Embedded \\frag{ into \\frag1{arg} plus }", "\\frag"), list( "blah \\cmd{ \\frag{arg} \\frag{arg} } \\frag2 blah", c("\\frag", "\\frag", "\\frag2") ) ) for (case in cases) { expect_equal( find_fragile_rd_tags(case[[1]], fragile)$tag, case[[2]], info = case[[1]] ) } }) test_that("str_sub_same", { expect_equal( str_sub_same( "123456789ab", data.frame(start = c(1,6), end = c(2,10), argend = c(2,10)), "xxx" ), "xxx-1-345xxx-2-b" ) expect_equal( str_sub_same( "123456789ab", data.frame(start = c(1,8), end = c(7,10), argend = c(7,10)), "xxx" ), "xxx-1-xxx-2-b", ) expect_equal( str_sub_same( "123456789ab", data.frame(start = numeric(), end = numeric(), argend = numeric()), "xxx" ), "123456789ab" ) }) roxygen2/tests/testthat/test-markdown-table.txt0000644000176200001440000000065014115761224021462 0ustar liggesusers> for (table in tables) { + cat_line(table) + cat_line(markdown(table)) + cat_line() + } | x | y | | --- | --- | | 1 | 2 | \tabular{ll}{ x \tab y \cr 1 \tab 2 \cr } | x | y | | :-: | --: | | 1 | 2 | \tabular{cr}{ x \tab y \cr 1 \tab 2 \cr } | x | y | | ----- | --------- | | 1 _2_ | 3 *4* `5` | \tabular{ll}{ x \tab y \cr 1 \emph{2} \tab 3 \emph{4} \code{5} \cr } roxygen2/tests/testthat/test-object-format.txt0000644000176200001440000000106413675432136021316 0ustar liggesusers> call_to_format(x <- list(a = 1, b = 2)) [1] "An object of class \\code{list} of length 2." > call_to_format(x <- ordered(letters[1:5])) [1] "An object of class \\code{ordered} (inherits from \\code{factor}) of length 5." > call_to_format(x <- diag(10)) [1] "An object of class \\code{matrix} with 10 rows and 10 columns." > call_to_format(x <- array(1:27, dim = c(3, 3, 3))) [1] "An object of class \\code{array} of dimension 3 x 3 x 3." > call_to_format(x <- data.frame(a = 1, b = 2)) [1] "An object of class \\code{data.frame} with 1 rows and 2 columns." roxygen2/tests/testthat/roxygen-example-1.R0000644000176200001440000000071113523072405020436 0ustar liggesusers##' Title ##' ##' Description ##' ##' Details ##' ##' @param x,y,z Descriptions for x, y, z ##' @param a Description of a ##' @param b ##' Description of b ##' @section Important: ##' Don't run with scissors! ##' @export NULL ##' Title ##' ##' Description ##' ##' Details ##' ##' @param x,y,z Descriptions for x, y, z ##' @param a Description of a ##' @param b ##' Description of b ##' @section Important: ##' Don't run with scissors! ##' @export NULL roxygen2/tests/testthat/test-collate.R0000644000176200001440000000325313540202201017544 0ustar liggesuserstest_that("collation as expected", { results <- generate_collate("collate") names <- str_replace(basename(results), "\\..*$", "") before <- function(a, b) { all(which(names %in% a) < which(names %in% b)) } expect_true(before("undershorts", "pants")) expect_true(before(c("tie", "belt"), "jacket")) expect_true(before(c("socks", "undershorts", "pants"), "shoes")) expected <- c('shirt.R', 'undershorts.R','pants.R', 'belt.R', 'tie.R', 'jacket.R', 'socks.R', 'shoes.R', 'watch.R') expect_equal(results, expected) }) test_that("Collate field unchanged when no @includes", { test_pkg <- temp_copy_pkg('testCollateNoIncludes') on.exit(unlink(test_pkg, recursive = TRUE)) old_desc <- read.description(file.path(test_pkg, "DESCRIPTION")) update_collate(test_pkg) new_desc <- read.description(file.path(test_pkg, "DESCRIPTION")) expect_equal(names(old_desc), names(new_desc)) expect_identical(old_desc$Collate,new_desc$Collate) }) test_that("DESCRIPTION file is re-written only if collate changes", { pkg_path <- "testCollateOverwrite" desc_path <- file.path(pkg_path, 'DESCRIPTION') # make backup copy of incomplete DESCRIPTION file (restored on exit) file.copy(desc_path, tmp <- tempfile()) on.exit( file.copy(tmp, desc_path, overwrite = TRUE), add = TRUE) # load package: this should update the DESCRIPTION file (warning) expect_output(update_collate(pkg_path), "Updating collate directive", info = "update_collate on incomplete package: DESCRIPTION file is updated") # should not update anymore expect_true(!length(capture.output(update_collate(pkg_path))), info = "update_collate on complete package: DESCRIPTION file is NOT updated") }) roxygen2/tests/testthat/test-markdown-state.R0000644000176200001440000000607313544714512021105 0ustar liggesuserstest_that("markdown is off by default", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some `code` included. `More code.` foo <- function() {}")[[1]] expect_equal( out1$get_value("description"), "Description with some `code` included. `More code.`" ) }) test_that("turning on/off markdown globally", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some `code` included. `More code.` foo <- function() {}")[[1]] expect_equal( out1$get_value("description"), "Description with some `code` included. `More code.`" ) old <- roxy_meta_set("markdown", TRUE) on.exit(roxy_meta_set("markdown", old)) out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some `code` included. `More code.` foo <- function() {}")[[1]] expect_equal( out1$get_value("description"), "Description with some \\code{code} included. \\verb{More code.}" ) }) test_that("turning on/off markdown locally", { out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some `code` included. `More code.` #' @noMd foo <- function() {}")[[1]] expect_equal( out1$get_value("description"), "Description with some `code` included. `More code.`" ) out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some `code` included. `More code.` #' @md foo <- function() {}")[[1]] expect_equal( out1$get_value("description"), "Description with some \\code{code} included. \\verb{More code.}" ) old <- roxy_meta_set("markdown", TRUE) on.exit(roxy_meta_set("markdown", old)) out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some `code` included. `More code.` #' @noMd foo <- function() {}")[[1]] expect_equal( out1$get_value("description"), "Description with some `code` included. `More code.`" ) ## on / on out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some `code` included. `More code.` #' @md foo <- function() {}")[[1]] expect_equal( out1$get_value("description"), "Description with some \\code{code} included. \\verb{More code.}" ) }) test_that("warning for both @md and @noMd", { expect_warning( out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some `code` included. `More code.` #' @md #' @noMd foo <- function() {}")[[1]], "Both @md and @noMd, no markdown parsing" ) expect_equal( out1$get_value("description"), "Description with some `code` included. `More code.`" ) old <- roxy_meta_set("markdown", TRUE) on.exit(roxy_meta_set("markdown", old)) expect_warning( out1 <- roc_proc_text(rd_roclet(), " #' Title #' #' Description with some `code` included. `More code.` #' @md #' @noMd foo <- function() {}")[[1]], "Both @md and @noMd, no markdown parsing" ) expect_equal( out1$get_value("description"), "Description with some `code` included. `More code.`" ) }) roxygen2/tests/testthat/testEagerData/0000755000176200001440000000000013523072405017547 5ustar liggesusersroxygen2/tests/testthat/testEagerData/data/0000755000176200001440000000000013523072405020460 5ustar liggesusersroxygen2/tests/testthat/testEagerData/data/a.rda0000644000176200001440000000011513523072405021365 0ustar liggesusersBZh91AY&SY C1D@  !2B`3(AܩA<^fV"(H_^!roxygen2/tests/testthat/testEagerData/DESCRIPTION0000644000176200001440000000031413523072405021253 0ustar liggesusersPackage: testEagerData Title: Tools to make developing R code easier License: GPL-2 Description: Author: Hadley Maintainer: Hadley Version: 0.1 Encoding: UTF-8 roxygen2/tests/testthat/testEagerData/R/0000755000176200001440000000000013523072405017750 5ustar liggesusersroxygen2/tests/testthat/testEagerData/R/a.r0000644000176200001440000000002713523072405020352 0ustar liggesusers#' Data #' #' Desc "a" roxygen2/tests/testthat/test-rd-backref.R0000644000176200001440000000103613542155203020131 0ustar liggesuserstest_that("Source reference is included as comment", { out <- roc_proc_text(rd_roclet(), " #' @name a #' @title a #' @docType package NULL")[[1]] expect_match(out$get_rd("backref"), "^% Please edit documentation in ") }) test_that("Explicit @backref is included as comment", { out <- roc_proc_text(rd_roclet(), " #' @name a #' @title a #' @backref back/ref.file #' @backref root.file #' @docType package NULL")[[1]] expect_equal(out$get_value("backref"), c("back/ref.file", "root.file")) }) roxygen2/tests/testthat/testNamespace/0000755000176200001440000000000014115763566017643 5ustar liggesusersroxygen2/tests/testthat/testNamespace/NAMESPACE0000644000176200001440000000010214115761225021041 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(f) export(g) roxygen2/tests/testthat/testNamespace/DESCRIPTION0000644000176200001440000000035014047223751021336 0ustar liggesusersPackage: testNamespace Title: Check that utf8 escapes are round tripped ok License: GPL-2 Description: Author: Hadley Maintainer: Hadley Encoding: UTF-8 Version: 0.1 RoxygenNote: 7.1.1.9001 roxygen2/tests/testthat/testNamespace/R/0000755000176200001440000000000013631761325020035 5ustar liggesusersroxygen2/tests/testthat/testNamespace/R/a.r0000644000176200001440000000012013631761325020431 0ustar liggesusers#' @export f <- function(x) x #' @evalNamespace "export(g)" g <- function() 1 roxygen2/tests/testthat/markdown-code-errors.txt0000644000176200001440000000135714115761221021644 0ustar liggesusers> roc_proc_text(rd_roclet(), + "\n #' Title\n #'\n #' Description --`r 1 +\n #' 1`--\n #' @md\n #' @name dummy\n NULL")[[ + 1]] Error: [:3] @description in inline code: multi-line `r ` markup is not supported > roc_proc_text(rd_roclet(), + "\n #' Title\n #'\n #' Description --`r 1 + 'a'`--\n #' @md\n #' @name dummy\n NULL")[[ + 1]] Error: [:3] @description in inline code: non-numeric argument to binary operator > roc_proc_text(rd_roclet(), + "\n #' Title\n #'\n #' Description --`r 1 + `--\n #' @md\n #' @name dummy\n NULL")[[ + 1]] Error: [:3] @description in inline code: :2:0: unexpected end of input 1: 1 + ^ roxygen2/tests/testthat/Rd-example-2.R0000644000176200001440000000002613523072405017310 0ustar liggesusersexample <- 'example2' roxygen2/tests/testthat.R0000644000176200001440000000036514115761547015173 0ustar liggesuserslibrary(testthat) library(roxygen2) if (requireNamespace("xml2")) { test_check("roxygen2", reporter = MultiReporter$new(reporters = list(JunitReporter$new(file = "test-results.xml"), CheckReporter$new()))) } else { test_check("roxygen2") } roxygen2/src/0000755000176200001440000000000014115763566012634 5ustar liggesusersroxygen2/src/leadingSpaces.cpp0000644000176200001440000000071314047223751016072 0ustar liggesusers#include #include int leadingSpacesOne(std::string line) { int n = line.size(); for(int i = 0; i < n; ++i) { char cur = line[i]; if (cur != ' ') return(i); } return n; } [[cpp11::register]] cpp11::integers leadingSpaces(cpp11::strings lines) { int n = lines.size(); cpp11::writable::integers out(n); for(int i = 0; i < n; ++i) { out[i] = leadingSpacesOne(lines[i]); } return out; } roxygen2/src/parser2.cpp0000644000176200001440000000773414047223751014720 0ustar liggesusers#include #include #include #include #include #include #include #include class RoxygenLine { std::string line_; const char* begin_; const char* end_; const char* cur_; public: RoxygenLine(const std::string& line) : line_(line) { begin_ = cur_ = line_.data(); end_ = begin_ + line_.size(); } bool consumeChar(char c) { if (cur_ == end_ || *cur_ != c) return false; cur_++; return true; } int consumeWhitespace(int max = -1) { int i = 0; while (cur_ != end_ && std::isspace(*cur_)) { cur_++; i++; if (max > 0 && i >= max) break; } return i; } bool consumeRoxygenComment() { consumeWhitespace(); if (!consumeChar('#')) return false; while (consumeChar('#')); if (!consumeChar('\'')) return false; consumeWhitespace(1); return true; } bool consumeTag(std::string* pOut) { if (!consumeChar('@')) return false; while(cur_ != end_ && std::isalnum(*cur_) ) { pOut->push_back(*cur_); cur_++; } return true; } bool consumeText(std::string* pOut) { while (cur_ != end_) { if (isEscapedAt()) { pOut->push_back('@'); cur_ += 2; } else { pOut->push_back(*cur_); cur_++; } } return true; } bool isEscapedAt() { if (cur_ == end_) return false; if (*cur_ != '@') return false; const char* next = cur_ + 1; if (next == end_) return false; return *next == '@'; } }; std::string stripTrailingNewline(std::string x) { if (x[x.size() - 1] == '\n') { x.resize(x.size() - 1); } return x; } [[cpp11::register]] cpp11::list tokenise_block(cpp11::strings lines, std::string file, int offset) { std::vector tags, vals; std::vector rows; int curRow = 1; std::string curTag(""), curVal(""); for (int i = 0; i < lines.size(); ++i) { RoxygenLine line((std::string(lines[i]))); if (!line.consumeRoxygenComment()) continue; std::string tag; if (line.consumeTag(&tag)) { line.consumeWhitespace(1); if (curVal != "" || curTag != "") { rows.push_back(curRow); tags.push_back(curTag); vals.push_back(curVal); } curRow = i + offset; curTag.assign(tag); curVal.assign(""); } line.consumeText(&curVal); curVal.push_back('\n'); } if (curVal != "" || curTag != "") { rows.push_back(curRow); tags.push_back(curTag); vals.push_back(curVal); } // Convert to a list R_xlen_t n = rows.size(); cpp11::writable::list out(n); using namespace cpp11::literals; for (R_xlen_t i = 0; i < n; ++i) { cpp11::writable::list x({ "file"_nm = file, "line"_nm = rows[i], "tag"_nm = tags[i], "raw"_nm = stripTrailingNewline(vals[i]), "val"_nm = R_NilValue }); std::string tag("roxy_tag_"); tag += tags[i]; x.attr("class") = {tag.c_str(), "roxy_tag"}; out[i] = x; } return out; } [[cpp11::register]] cpp11::strings find_includes(std::string path) { std::vector includes; std::ifstream file(path.c_str()); if (!file.good()) cpp11::stop("Failed to open %s", path.c_str()); std::string rawline; while (std::getline(file, rawline)) { RoxygenLine line(rawline); if (!line.consumeRoxygenComment()) continue; std::string tag, value; if (!line.consumeTag(&tag)) continue; if (tag != "include") continue; line.consumeWhitespace(1); // Split value by whitespace // http://stackoverflow.com/questions/236129/split-a-string-in-c line.consumeText(&value); std::istringstream words(value); copy( std::istream_iterator(words), std::istream_iterator(), back_inserter(includes) ); } return cpp11::as_sexp(includes); } roxygen2/src/isComplete.cpp0000644000176200001440000000477014047223751015443 0ustar liggesusers#include #include // From http://developer.r-project.org/parseRd.pdf: The characters \, %, {, // and } have special meaning in almost all parts of an Rd file. In code, // strings must also match, except in comments. // The two functions are very similar, so we use a common // implementation and select the functionality via the // mode argument: // mode == 0: rdComplete // mode == 1: findEndOfTag int roxygen_parse_tag(std::string string, bool is_code = false, int mode = 0) { int n = string.length(); char in_string = '\0'; bool in_escape = false; bool in_r_comment = false; bool in_latex_comment = false; int braces = 0, r_braces = 0; for(int i = 0; i < n; i++) { char cur = string[i]; if (in_escape) { // Swallow escaped characters in_escape = false; } else if (in_string != '\0') { // Look for end of string if (cur == in_string) { in_string = false; } else if (cur == '\\') { in_escape = true; } } else if (in_r_comment) { // Inside R comments, braces must match. // R comments are terminated by newline or } not matched by { if (cur == '\n') { in_r_comment = false; r_braces = 0; } else if (cur == '{') { braces++; r_braces++; } else if (cur == '}') { braces--; r_braces--; if (r_braces == 0) in_r_comment = false; } } else if (in_latex_comment) { if (cur == '\n') { in_latex_comment = false; } } else { switch(cur) { case '{': braces++; break; case '}': braces--; break; case '\\': in_escape = true; break; case '#': if (is_code) in_r_comment = true; break; case '%': in_latex_comment = true; break; case '\'': if (is_code) in_string = '\''; break; case '"': if (is_code) in_string = '"'; break; } } if (mode == 1) { bool complete = braces == 0 && !in_escape && !in_string; if (complete && i + 1 < n && string[i + 1] != '{') { return i; } } } bool complete = braces == 0 && !in_escape && !in_string; if (mode == 0) { if (complete) return 1; else return 0; } else { if (complete) return n - 1; else return -1; } } [[cpp11::register]] int findEndOfTag(std::string string, bool is_code) { return roxygen_parse_tag(string, is_code, 1); } [[cpp11::register]] bool rdComplete(std::string string, bool is_code) { return roxygen_parse_tag(string, is_code, 0) == 1 ? true : false; } roxygen2/src/wrapUsage.cpp0000644000176200001440000000300014047223751015256 0ustar liggesusers#include #include #include std::vector splitByWhitespace(std::string string) { std::vector out; std::string acc = ""; char in_string = '\0'; int in_escape = 0; std::string::const_iterator cur = string.begin(), end = string.end(); while(cur != end) { if (in_string != '\0') { acc += *cur; if (in_escape) { in_escape--; } else if (*cur == '\\' && cur + 1 != end && *(cur + 1) == '\\') { in_escape = 2; } else if (*cur == in_string) { // String terminates in_string = '\0'; } } else if (*cur == ' ' || *cur == '\t' || *cur == '\n') { out.push_back(acc); acc = ""; } else if (*cur == '"' || *cur == '\'') { in_string = *cur; acc += *cur; } else { acc += *cur; } cur++; } out.push_back(acc); return out; } [[cpp11::register]] std::string wrapUsage(std::string string, int width, int indent) { std::vector pieces = splitByWhitespace(string); int n = pieces.size(); int cur_width = 0; std::string out; for (int i = 0; i < n; ++i) { int piece_width = pieces[i].size(); // Need to include space for a space if (piece_width + cur_width + 1 < width) { cur_width += piece_width; if (i != 0) { out += " "; cur_width++; } } else { cur_width = piece_width + indent; out += "\n" + std::string(indent, ' '); } out += pieces[i]; } return out; } roxygen2/src/escapeExamples.cpp0000644000176200001440000000213314047223751016265 0ustar liggesusers#include #include [[cpp11::register]] std::string escapeExamples(std::string x) { std::string out; out.reserve(x.length() * 1.1); char in_string = '\0'; bool in_escape = false; bool in_comment = false; std::string::const_iterator cur, end = x.end(); for (cur = x.begin(); cur != end; cur++) { if (in_comment) { // inside comment if (*cur == '\n') { in_comment = false; } } else if (in_string == '\0') { // regular code if (*cur == '#') { in_comment = true; } else if (*cur == '\'' || *cur == '"' || *cur == '`') { in_string = *cur; } } else { // inside string/symbol if (in_escape) { in_escape = false; if (*cur == 'l' || *cur == 'v') { out += '\\'; } else if (*cur == '\\') { out += "\\\\"; } } else { if (*cur == in_string) { in_string = '\0'; } else if (*cur == '\\') { in_escape = true; } } } if (*cur == '%') { out += '\\'; } out += *cur; } return out; } roxygen2/src/cpp11.cpp0000644000176200001440000000635614047226733014270 0ustar liggesusers// Generated by cpp11: do not edit by hand // clang-format off #include "cpp11/declarations.hpp" // escapeExamples.cpp std::string escapeExamples(std::string x); extern "C" SEXP _roxygen2_escapeExamples(SEXP x) { BEGIN_CPP11 return cpp11::as_sexp(escapeExamples(cpp11::as_cpp>(x))); END_CPP11 } // isComplete.cpp int findEndOfTag(std::string string, bool is_code); extern "C" SEXP _roxygen2_findEndOfTag(SEXP string, SEXP is_code) { BEGIN_CPP11 return cpp11::as_sexp(findEndOfTag(cpp11::as_cpp>(string), cpp11::as_cpp>(is_code))); END_CPP11 } // isComplete.cpp bool rdComplete(std::string string, bool is_code); extern "C" SEXP _roxygen2_rdComplete(SEXP string, SEXP is_code) { BEGIN_CPP11 return cpp11::as_sexp(rdComplete(cpp11::as_cpp>(string), cpp11::as_cpp>(is_code))); END_CPP11 } // leadingSpaces.cpp cpp11::integers leadingSpaces(cpp11::strings lines); extern "C" SEXP _roxygen2_leadingSpaces(SEXP lines) { BEGIN_CPP11 return cpp11::as_sexp(leadingSpaces(cpp11::as_cpp>(lines))); END_CPP11 } // parser2.cpp cpp11::list tokenise_block(cpp11::strings lines, std::string file, int offset); extern "C" SEXP _roxygen2_tokenise_block(SEXP lines, SEXP file, SEXP offset) { BEGIN_CPP11 return cpp11::as_sexp(tokenise_block(cpp11::as_cpp>(lines), cpp11::as_cpp>(file), cpp11::as_cpp>(offset))); END_CPP11 } // parser2.cpp cpp11::strings find_includes(std::string path); extern "C" SEXP _roxygen2_find_includes(SEXP path) { BEGIN_CPP11 return cpp11::as_sexp(find_includes(cpp11::as_cpp>(path))); END_CPP11 } // wrapUsage.cpp std::string wrapUsage(std::string string, int width, int indent); extern "C" SEXP _roxygen2_wrapUsage(SEXP string, SEXP width, SEXP indent) { BEGIN_CPP11 return cpp11::as_sexp(wrapUsage(cpp11::as_cpp>(string), cpp11::as_cpp>(width), cpp11::as_cpp>(indent))); END_CPP11 } extern "C" { /* .Call calls */ extern SEXP _roxygen2_escapeExamples(SEXP); extern SEXP _roxygen2_find_includes(SEXP); extern SEXP _roxygen2_findEndOfTag(SEXP, SEXP); extern SEXP _roxygen2_leadingSpaces(SEXP); extern SEXP _roxygen2_rdComplete(SEXP, SEXP); extern SEXP _roxygen2_tokenise_block(SEXP, SEXP, SEXP); extern SEXP _roxygen2_wrapUsage(SEXP, SEXP, SEXP); static const R_CallMethodDef CallEntries[] = { {"_roxygen2_escapeExamples", (DL_FUNC) &_roxygen2_escapeExamples, 1}, {"_roxygen2_find_includes", (DL_FUNC) &_roxygen2_find_includes, 1}, {"_roxygen2_findEndOfTag", (DL_FUNC) &_roxygen2_findEndOfTag, 2}, {"_roxygen2_leadingSpaces", (DL_FUNC) &_roxygen2_leadingSpaces, 1}, {"_roxygen2_rdComplete", (DL_FUNC) &_roxygen2_rdComplete, 2}, {"_roxygen2_tokenise_block", (DL_FUNC) &_roxygen2_tokenise_block, 3}, {"_roxygen2_wrapUsage", (DL_FUNC) &_roxygen2_wrapUsage, 3}, {NULL, NULL, 0} }; } extern "C" void R_init_roxygen2(DllInfo* dll){ R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); R_forceSymbols(dll, TRUE); } roxygen2/vignettes/0000755000176200001440000000000014115763565014054 5ustar liggesusersroxygen2/vignettes/roxygen2.Rmd0000644000176200001440000001346613631761325016301 0ustar liggesusers--- title: "Introduction to roxygen2" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Getting started with roxygen2} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ``` Documentation is one of the most important aspects of good code. Without it, users won't know how to use your package, and are unlikely to do so. Documentation is also useful for you in the future (so you remember what the heck you were thinking!), and for other developers working on your package. The goal of roxygen2 is to make documenting your code as easy as possible. R provides a standard way of documenting packages: you write `.Rd` files in the `man/` directory. These files use a custom syntax, loosely based on latex. Roxygen2 provides a number of advantages over writing `.Rd` files by hand: * Code and documentation are adjacent so when you modify your code, it's easy to remember that you need to update the documentation. * Roxygen2 dynamically inspects the objects that it's documenting, so it can automatically add data that you'd otherwise have to write by hand. * It abstracts over the differences in documenting S3 and S4 methods, generics and classes so you need to learn fewer details. As well as generating `.Rd` files, roxygen will also create a `NAMESPACE` for you, and will manage the `Collate` field in `DESCRIPTION`. This vignette provides a high-level description of roxygen2 and how the three main components work. The other vignettes provide more detail on the most important individual components: * [Generating .Rd files](rd.html) and [text formatting](rd-formatting.html) describe how to generate function documentation via `.Rd` files * [Managing your `NAMESPACE`](namespace.html) describes how to generate a `NAMESPACE` file, how namespacing works in R, and how you can use Roxygen2 to be specific about what your package needs and supplies. * See [update_collate()] for the details of `@include`, which for complicated reasons is not implemented as a roclet. ## Running roxygen There are three main ways to run roxygen: * `roxygen2::roxygenise()`. * `devtools::document()`. * `Ctrl + Shift + D`, if you're using RStudio. You can mix handwritten Rd and roxygen2; roxygen2 will never overwrite a file it didn't create. ## Basic process There are three steps in the transformation from roxygen comments in your source file to human readable documentation: 1. You add roxygen comments to your source file. 2. `roxygen2::roxygenise()` converts roxygen comments to `.Rd` files. 3. R converts `.Rd` files to human readable documentation. The process starts when you add specially formatted roxygen comments to your source file. Roxygen comments start with `#'` so you can continue to use regular comments for other purposes. ```{r} #' Add together two numbers #' #' @param x A number #' @param y A number #' @return The sum of \code{x} and \code{y} #' @examples #' add(1, 1) #' add(10, 1) add <- function(x, y) { x + y } ``` For the example, above, this will generate `man/add.Rd` that looks like: ``` % Generated by roxygen2 (3.2.0): do not edit by hand \name{add} \alias{add} \title{Add together two numbers} \usage{ add(x, y) } \arguments{ \item{x}{A number} \item{y}{A number} } \value{ The sum of \code{x} and \code{y} } \description{ Add together two numbers } \examples{ add(1, 1) add(10, 1) } ``` Rd files are a special file format loosely based on LaTeX. You can read more about the Rd format in the [R extensions](https://cran.r-project.org/doc/manuals/R-exts.html#Rd-format) manual. With roxygen2, there are few reasons to know about Rd files, so here I'll avoid discussing them as much as possible, focussing instead on what you need to know about roxygen2. When you use `?x`, `help("x")` or `example("x")` R looks for an Rd file containing `\alias{x}`. It then parses the file, converts it into html and displays it. These functions look for an Rd file in _installed_ packages. This isn't very useful for package development, because you want to use the `.Rd` files in the _source_ package. For this reason, we recommend that you use roxygen2 in conjunction with devtools: `devtools::load_all()` automatically adds shims so that `?` and friends will look in the development package. Note, however, that this preview does not work with intra-package links. To preview those, you'll need to install the package. If you use RStudio, the easiest way to do this is to click the "Build & Reload button". ### Rcpp You can also use roxygen2 with Rcpp. Simply include roxygen2 comments in your C++ code (using `//` instead of `#`), and Rcpp will automatically carry the comments along into `RcppExports.R` where roxygen2 will find them. For example, dplyr has `between.cpp` which starts: ```cpp //' Do values in a numeric vector fall in specified range? //' //' This is a shortcut for `x >= left & x <= right`, implemented //' efficiently in C++ for local values, and translated to the //' appropriate SQL for remote tables. //' //' @param x A numeric vector of values //' @param left,right Boundary values //' @export //' @examples //' between(1:12, 7, 9) //' //' x <- rnorm(1e2) //' x[between(x, -1, 1)] // [[Rcpp::export(rng = false)]] Rcpp::LogicalVector between(Rcpp::NumericVector x, double left, double right) { } ``` This is automatically translated to the following R code in `RcppExports.R`: ```{r, eval = FALSE} #' Do values in a numeric vector fall in specified range? #' #' This is a shortcut for `x >= left & x <= right`, implemented #' efficiently in C++ for local values, and translated to the #' appropriate SQL for remote tables. #' #' @param x A numeric vector of values #' @param left,right Boundary values #' @export #' @examples #' between(1:12, 7, 9) #' #' x <- rnorm(1e2) #' x[between(x, -1, 1)] between <- function(x, left, right) { } ``` roxygen2/vignettes/rd-formatting.Rmd0000644000176200001440000005073214115761663017301 0ustar liggesusers--- title: "Rd formatting" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Rd formatting} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ``` # Introduction Starting from version 6.0.0, roxygen supports markdown markup within most roxygen tags. Roxygen uses the [commonmark package](https://github.com/r-lib/commonmark), which is based on the CommonMark Reference Implementation to parse these tags. See for more about the parser and the markdown language it supports. You can also still use the `.Rd` syntax, some of which we will present below in the [Rd syntax](#rd-syntax) section. # Turning on markdown support There are two ways to turn on markdown support for a package: globally, at the package level, and locally at the block level. To turn on markdown for the whole package, insert this entry into the `DESCRIPTION` file of the package: ``` Roxygen: list(markdown = TRUE) ``` The position of the entry in the file does not matter. After this, all Roxygen documentation will be parsed as markdown. Alternatively, you can use the `@md` tag to turn on markdown support for a single documentation chunk. This is a good option to write any new documentation for existing packages in markdown. There is also a new `@noMd` tag. Use this if you turned on markdown parsing globally, but need to avoid it for a single chunk. This tag is handy if the markdown parser interferes with more complex Rd syntax. Here is an example roxygen chunk that uses markdown. ```r #' Use roxygen to document a package #' #' This function is a wrapper for the [roxygen2::roxygenize()] function from #' the roxygen2 package. See the documentation and vignettes of #' that package to learn how to use roxygen. #' #' @param pkg package description, can be path or package name. See #' [as.package()] for more information #' @param clean,reload Deprecated. #' @inheritParams roxygen2::roxygenise #' @seealso [roxygen2::roxygenize()], `browseVignettes("roxygen2")` #' @export #' @md ``` # Syntax ## Sections The usual markdown heading markup creates sections and subsections. Top level headings, i.e. '`#`' create sections, via the `\section{}` Rd tag. '`#`' may only appear after the `@description` and `@details` tags. Since `@details` can appear multiple times in a block, you can always precede a '`#`' section with `@details`, if you prefer to place it towards the end of the block, after `@return` for example: ```r #' @details #' Trim the leading and trailing whitespace from a character vector. #' #' @param x Character vector. #' @return Character vector, with the whitespace trimmed. #' #' @details # This will be a new section #' ... ``` Top level sections are always placed at a fixed position in the manual page, after the parameters and the details, but before `\note{}`, `\seealso{}` and the `\examples{}`. Their order will be the same as in the roxygen block. ## Subsections Headings at level two and above may appear inside any roxygen tag that formats lines of text. E.g. `@description`, `@details`, `@return`, etc. They create subsections, via the `\subsection{}` Rd tag. They are allowed within top level sections as well, i.e. after '`#`'. Subsections can be nested. Example: ```r #' @details #' ## Subsection within details #' ### Sub-subsection #' ... text ... ``` ## Emphasis *Emphasis* and **strong** (bold) text are supported. For emphasis, put the text between asterisks or underline characters. For strong text, use two asterisks at both sides. ```r #' @references #' Robert E Tarjan and Mihalis Yannakakis. (1984). Simple #' linear-time algorithms to test chordality of graphs, test acyclicity #' of hypergraphs, and selectively reduce acyclic hypergraphs. #' *SIAM Journal of Computation* **13**, 566-579. ``` ```r #' See `::is_falsy` for the definition of what is _falsy_ #' and what is _truthy_. ``` ## Code Inline code is supported via backticks. ```r #' @param ns Optionally, a named vector giving prefix-url pairs, as #' produced by `xml_ns`. If provided, all names will be explicitly #' qualified with the ns prefix, i.e. if the element `bar` is defined ... ``` You can also use this syntax to run custom R code and insert its output into the manual page. See section 'Dynamic R code' below. For blocks of code, put your code between triple backticks: ```r #' ``` #' pkg <- make_packages( #' foo1 = { f <- function() print("hello!") ; d <- 1:10 }, #' foo2 = { f <- function() print("hello again!") ; d <- 11:20 } #' ) #' foo1::f() #' foo2::f() #' foo1::d #' foo2::d #' dispose_packages(pkg) #' ``` ``` Note that this is not needed in `@examples`, since its contents are formatted as R code, anyway. You can use similar syntax to include a block of R code and/or its output in the manual page. See section 'Dynamic R code' below. ## Lists Regular Markdown lists are recognized and converted to `\enumerate{}` or `\itemize{}` lists: ```r #' There are two ways to use this function: #' 1. If its first argument is not named, then it returns a function #' that can be used to color strings. #' 1. If its first argument is named, then it also creates a #' style with the given name. This style can be used in #' `style`. One can still use the return value #' of the function, to create a style function. ``` ```r #' The style (the `...` argument) can be anything of the #' following: #' * An R color name, see `colors()`. #' * A 6- or 8-digit hexa color string, e.g. `#ff0000` means #' red. Transparency (alpha channel) values are ignored. #' * A one-column matrix with three rows for the red, green #' and blue channels, as returned by [grDevices::col2rgb()] ``` Nested lists are also supported. Note that you do not have to leave an empty line before the list. This is different from some markdown parsers. ## Tables Use [GFM table formatting](https://github.github.com/gfm/#tables-extension-): ```r | foo | bar | | --- | --- | | baz | bim | ``` By default, columns are left-aligned. Use colons to generate right and center aligned columns: ```r | left | center | right | | :--- | :----: | ----: | | 1 | 2 | 3 | ``` ## Links Markdown hyperlinks work as usual: ```r #' See more about the markdown markup at the #' [Commonmark web site](http://commonmark.org/help) ``` URLs inside angle brackets are also automatically converted to hyperlinks: ```r #' The main R web site is at . ``` Markdown notation can also be used to create links to other help topics. There are two basic forms: * `[ref]`: The target topic and the link text are one and the same. * `[text][ref]`: Link text differs from the target. First we explore the simplest form: `[ref]`. The presence of trailing parentheses, e.g., `[func()]`, signals that the target `func` is a function, which causes two things to happen: * The link text `func()` is automatically typeset as code. * The parentheses are stripped in the derived Rd link target. +--------------------+------------------------+---------------------------------------------+ | `[ref]`\ | Links to help\ | Notes | | examples | topic for ... | | +:===================+:=======================+:============================================+ | `[func()]`\ | a function in same\ | Always typeset as code.\ | | `[pkg::func()]` | package or in `pkg` | Produces Rd: `\code{\link[=func]{func()}}`\ | | | | or `\code{\link[pkg:func]{pkg::func()}}` | +--------------------+------------------------+---------------------------------------------+ | `[thing]`\ | a topic in same\ | Use for a topic that documents `NULL` and name is set\ | | `[pkg::thing]` | package or in `pkg` | via `@name`, e.g., a dataset or concept.\ | | | | Not typeset as code.\ | | | | Produces Rd: `\link{thing}` or\ | | | | `\link[pkg:thing]{pkg::thing}` | +--------------------+------------------------+---------------------------------------------+ | ``[`thing`]``\ | a topic in same\ | Same as above, but explicit backticks\ | | ``[`pkg::thing`]`` | package or in `pkg` | mean that it **is** typeset as code.\ | | | | Good for documenting a class.\ | | | | Produces Rd: `\code{\link{thing}}` or\ | | | | `\code{\link[pkg:thing]{pkg::thing}`} | +--------------------+------------------------+---------------------------------------------+ Use the second form `[text][ref]` to link to the topic specified by `ref`, but with `text` as the link text. +-----------------------+------------------------+-----------------------------+ | `[text][ref]`\ | Links to help\ | Notes | | examples | topic for ... | | +:======================+:=======================+:============================+ | `[text][func()]`\ | a function in same\ | Text is not typeset as code.\ | | `[text][pkg::func()]` | package or in `pkg` | Produces Rd: `\link[=func]{text}` or\ | | | | `\link[pkg:func]{text}` | +-----------------------+------------------------+-----------------------------+ | `[text][thing]`\ | a topic in same\ | Text is not typeset as code.\ | | `[text][pkg::thing]` | package or in `pkg` | Use for a topic that documents `NULL`\ | | | | and name is set via `@name`,\ | | | | e.g., a dataset or concept.\ | | | | Produces Rd: `\link[=thing]{text}` or\ | | | | `\link[pkg:thing]{text}` | +-----------------------+------------------------+-----------------------------+ In the `[text][ref]`, the link text is treated like normal text by default. * Use backticks to typeset the link text as code: ``[`text`][ref]``. It is never appropriate to use backticks around the `ref` in this form. * No, do not do this: ``[text][`blah-blah`]`` * Yes, do this instead: `[text][blah-blah]` S3 and S4 class *not done yet* +-----------------------+------------------------+--------------------------+ | Examples | Help topic\ | Notes | | | for what? | | +:======================+:=======================+:=========================+ | `[abc-class]`\ | an S4 class named\ | In Rd: `\linkS4class{abc}` or\ | | `[pkg::abc-class]` | "abc" in same package\ | `\link[pkg:abc-class]{pkg::abc}` | | | or in `pkg` | | +-----------------------+------------------------+--------------------------+ | `[abc][abc-class]` | *is this a thing? | ??? `\link[=abc-class]{abc}` | +-----------------------+------------------------+--------------------------+ ## Images Markdown syntax for inline images works. The image files must be in the `man/figures` directory: ```r #' Here is an example plot: #' ![](example-plot.jpg "Example Plot Title") ``` # Dynamic R code Similarly to the knitr package, you can use the markdown inline code markup or markdown code blocks to evaluate R code and insert its output into the manual page. ## Inline code To do this, prefix the code with `r `, i.e. the lowercase letter 'r' and a space character. Roxygen will interpret the rest of the text within backticks as R code and evaluate it, and replace the backtick expression with its value. After all such substitutions, the text of the whole tag is interpreted as markdown, as usual. For example, the following will insert the date and the R version of the roxygen run. ```r #' Roxygen created this manual page on `r "\x60r Sys.Date()\x60"` using R version #' `r "\x60r getRversion()\x60"`. ``` The value of the R expression is converted to a character string, with `paste(collapse = "\n")`. So you don't need explicitly convert to a character value, numeric values or any R object with an `as.character()` S3 method is fine. Also, you can insert multiple lines by returning a character vector. If you want to run R code without inserting any output, return an empty string or `NULL`. The value of the expression is inserted into the text of the tag without interpreting it, before the markdown to `.Rd` conversion, so you can create markdown markup dynamically: ```r #' The `iris` data set has `r "\x60r ncol(iris)\x60"` columns: #' `r "\x60r paste0(\"\x60\x60\", colnames(iris), \"\x60\x60\", collapse = \", \")\x60"`. ``` Note that you need to escape backtick characters, if they appear in the R expression, by doubling them, like above. The result after the dynamic R code evaluation will be: ``` The `iris` data set has 5 columns: `Sepal.Length`, `Sepal.Width`, `Petal.Length`, `Petal.Width`, `Species`. ``` And the final result in the `.Rd` file will look as: ``` The \code{iris} data set has 5 columns: \code{Sepal.Length}, \code{Sepal.Width}, \code{Petal.Length}, \code{Petal.Width}, \code{Species}. ``` The R code is evaluated in a new environment that is the child of the package environment of the package you are documenting. This means that you can call (internal or exported) functions of the package. `packageName()` will also report the name of the package: ```r #' To insert the name of the current package: `r "\x60r packageName()\x60"`. ``` A new evaluation environment is created for each roxygen _block_. So the output of this code: ```r #' @title ... `r "\x60r myvar <- \"foo\"; NULL\x60"` `r "\x60r myvar\x60"` #' #' @description ... `r "\x60r myvar\x60"` ``` will be: ```r #' @title ... foo #' #' @description ... foo ``` Currently the whole code expression must be on the same line, multi-line expressions are not supported. ## Code blocks Markdown code blocks can be dynamic as well, if you use `r "\x60\x60\x60{r}"` to start them, just like in knitr documents. ```r #' ```{r} #' # This block of code will be evaluated #' summary(iris) #' ``` ``` Within a roxygen block, code blocks and inline code use the same evaluation environment, so variables created in one of them can be used in others. Code blocks support knitr chunk options, e.g. to keep the output of several expressions together, you can specify `results= "hold"`: ```r #' ```{r results = "hold"} #' names(mtcars) #' nrow(mtcars) #' ``` ``` Plots will create `.png` files in the `man/figures` directory. The file names are created from the chunk names: ```r #' ```{r iris-pairs-plot} #' pairs(iris[1:4], main = "Anderson's Iris Data -- 3 species", #' pch = 21, bg = c("red", "green3", "blue")[unclass(iris$Species)]) #' ``` ``` Note that the generated `.png` files will be added to the package, and they can considerably increase the size of the package. Note that code block support is currently experimental, and somewhat limited. Some of the known limitations: * Because the code blocks are evaluated individually, they cannot refer to each other. * Some knitr chunk options are reset at the start of every code block, so if you want to change these, you'll have to specify them for every chunk. These are currently `error`, `fig.path`, `fig.process`. * Some knitr options might not create meaningful output. * The markdown code runs every time you call `roxygenize()` (or `devtools::document()`) to generated the Rd files. This potentially makes `roxygenize()` (much) slower. You can turn on knitr caching as usual, but make sure to omit the cache from the package. # Roxygen and Rd tags *not* parsed as markdown Some of the roxygen tags are not parsed as markdown. Most of these are unlikely to contain text that needs markup, so this is not an important restriction. Tags without markdown support: `@aliases`, `@backref`, `@docType`, `@encoding`, `@evalRd`, `@example`, `@examples`, `@family`, `@inheritParams`, `@keywords`, `@method` `@name`, `@md`, `@noMd`, `@noRd`, `@rdname`, `@rawRd`, `@usage`. When mixing `Rd` and markdown notation, most `Rd` tags may contain markdown markup, the ones that can *not* are: `r paste0("\x60", roxygen2:::escaped_for_md, "\x60", collapse = ", ")`. # Possible problems ## Mixing markdown and `Rd` markup Note that turning on markdown does *not* turn off the standard `Rd` syntax. We suggest that you use the regular `Rd` tags in a markdown roxygen chunk only if necessary. The two parsers do occasionally interact, and the markdown parser can pick up and reformat Rd syntax, causing an error, or corrupted manuals. ## Leading whitespace Leading whitespace is interpreted by the commonmark parser, whereas it is ignored by the `Rd` parser (except in `\preformatted{}`). Make sure that you only include leading whitespace intentionally, for example for nested lists. ## Spurious lists The Commonmark parser does not require an empty line before lists, and this might lead to unintended lists if a line starts with a number followed by a dot, or with an asterisk followed by whitespace: ```r #' You can see more about this topic in the book cited below, on page #' 42. Clearly, the numbered list that starts here is not intentional. ``` ## Links to operators Links to operators or objects that contain special characters, do not work currently. E.g. to link to the `%>%` operator in the `magrittr` package, instead of `[magrittr::%>%]`, you will need to use the `Rd` notation: `\code{\link[magrittr]{\%>\%}}`. # Rd syntax Within roxygen tags, you can use `.Rd` syntax to format text. Below we show you examples of the most important `.Rd` markup commands. The full details are described in [R extensions](https://cran.r-project.org/doc/manuals/R-exts.html#Marking-text). Before roxygen version 6.0.0 this was the only supported syntax. Now all of the formatting described below can be achived more easily with markdown syntax, with the important exception of [mathematical expressions](https://cran.r-project.org/doc/manuals/R-exts.html#Mathematics). Note that `\` and `%` are special characters. To insert literals, escape with a backslash: `\\`, `\%`. ## Character formatting * `\emph{italics}` * `\strong{bold}` * `\code{r_function_call(with = "arguments")}`, `\code{NULL}`, `\code{TRUE}` * `\pkg{package_name}` ## Links To other documentation: * `\code{\link{function}}`: function in this package * `\code{\link[MASS]{abbey}}`: function in another package * `\link[=dest]{name}`: link to dest, but show name * `\code{\link[MASS:abbey]{name}}`: link to function in another package, but show name. * `\linkS4class{abc}`: link to an S4 class To the web: * `\url{http://rstudio.com}` * `\href{http://rstudio.com}{Rstudio}` * `\email{hadley@@rstudio.com}` (note the doubled `@`) ## Lists * Ordered (numbered) lists: ```{r} #' \enumerate{ #' \item First item #' \item Second item #' } ``` * Unordered (bulleted) lists ```{r} #' \itemize{ #' \item First item #' \item Second item #' } ``` * Definition (named) lists ```{r} #' \describe{ #' \item{One}{First item} #' \item{Two}{Second item} #' } ``` ## Mathematics Standard LaTeX (with no extensions): * `\eqn{a + b}`: inline equation * `\deqn{a + b}`: display (block) equation ## Tables Tables are created with `\tabular{}`. It has two arguments: 1. Column alignment, specified by letter for each column (`l` = left, `r` = right, `c` = centre.) 2. Table contents, with columns separated by `\tab` and rows by `\cr`. The following function turns an R data frame into the correct format, adding a row consisting of the (bolded) column names and prepending each row with `#' ` for pasting directly into the documentation. ```{r} tabular <- function(df, ...) { stopifnot(is.data.frame(df)) align <- function(x) if (is.numeric(x)) "r" else "l" col_align <- purrr::map_chr(df, align) cols <- lapply(df, format, ...) contents <- do.call("paste", c(cols, list(sep = " \\tab ", collapse = "\\cr\n#' "))) paste("#' \\tabular{", paste(col_align, collapse = ""), "}{\n#' ", paste0("\\strong{", names(df), "}", sep = "", collapse = " \\tab "), " \\cr\n#' ", contents, "\n#' }\n", sep = "") } cat(tabular(mtcars[1:5, 1:5])) ``` roxygen2/vignettes/extending.Rmd0000644000176200001440000002215613556660006016505 0ustar liggesusers--- title: "Extending roxygen2" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Extending roxygen2} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ``` ## Basics Roxygen is extensible with user-defined __roclets__. It means that you can take advantage of Roxygen's parser and extend it with your own `@tags`. There are two primary ways to extend roxygen2: * Add new tag that generates a new top-level section in `.Rd` files. * Add a new roclet that does anything you like. This vignette will introduce you to the key data structures in roxygen2, and then show you how to use these two extension points. This vignette is very rough, so you should expect to have to also read some roxygen2 source code to understand all the extension points. Hopefully it's useful enough to help you get started, and if you have problems, please [file an issue](https://github.com/r-lib/roxygen2/issues/new)! ```{r setup} library(roxygen2) ``` ## Key data structures Before we talk about extending roxygen2, we need to first discuss two important data structures that power roxygen: tags and blocks. ### Tags A tag (a list with S3 class `roxy_tag`) represents a single tag. It has the following fields: * `tag`: the name of the tag. * `raw`: the raw contents of the tag (i.e. everything from the end of this tag to the beginning of the next). * `val`: the parsed value, which we'll come back to shortly. * `file` and `line`: the location of the tag in the package. Used with `roxy_tag_warning()` to produce informative error messages. You _can_ construct tag objects by hand with `roxy_tag()`: ```{r} roxy_tag("name", "Hadley") str(roxy_tag("name", "Hadley")) ``` However, you should rarely need to do so, because you'll typically have them given to you in a block object, as you'll see shortly. ### Blocks A block (a list with S3 class `roxy_block`) represents a single roxygen block. It has the following fields: * `tags`: a list of `roxy_tags`. * `call`: the R code associated with the block (usually a function call). * `file` and `line`: the location of the R code. * `object`: the evaluated R object associated with the code. The easiest way to see the basic structure of a `roxy_block()` is to generate one by parsing a roxygen block with `parse_text()`: ```{r} text <- " #' This is a title #' #' This is the description. #' #' @param x,y A number #' @export f <- function(x, y) x + y " # parse_text() returns a list of blocks, so I extract the first block <- parse_text(text)[[1]] block ``` ## Adding a new `.Rd` tag The easiest way to extend roxygen2 is to create a new tag that adds output to `.Rd` files. This requires two steps: 1. Define a `roxy_tag_parse()` method that describes how to parse our new tag. 1. Define a `roxy_tag_rd()` method that describes how to convert the tag into `.Rd` commands. To illustrate the basic idea we'll create a new `@tip` tag that will create a bulleted list of tips about how to use a function. The idea is to take something like this: ```{r} #' @tip The mean of a logical vector is the proportion of `TRUE` values. #' @tip You can compute means of dates and date-times! ``` And generate Rd like this: ```latex \section{Tips and tricks}{ \itemize{ \item The mean of a logical vector is the proportion of \code{TRUE} values. \item You can compute means of dates and date-times! } } ``` The first step is to define a method for `roxy_tag_parse()` that describes how to turn the parse the tag text. The name of the class will be `roxy_tag_{tag}`, which in this case is `roxy_tag_tip`. This function takes a `roxy_tag` as input, and it's job is to set `x$val` to a convenient parsed value that will be used later by the roclet. Here we want to process the text using markdown so we can just use `tag_markdown()`: ```{r} roxy_tag_parse.roxy_tag_tip <- function(x) { tag_markdown(x) } ``` ```{r, include = FALSE} # Needed for vignette registerS3method("roxy_tag_parse", "roxy_tag_tip", roxy_tag_parse.roxy_tag_tip) ``` We check this works by using `parse_text()`: ```{r} text <- " #' Title #' #' @tip The mean of a logical vector is the proportion of `TRUE` values. #' @tip You can compute means of dates and date-times! #' @md f <- function(x, y) { # ... } " block <- parse_text(text)[[1]] block str(block$tags[[2]]) ``` (Here I explicit turn markdown parsing on using `@md`; it's usually turned on for a package using roxygen options). Next we define a method for `roxy_tag_rd()`, which must create an `rd_section()`. We're going to create a new section called `tip`. It will contain a character vector of tips: ```{r} roxy_tag_rd.roxy_tag_tip <- function(x, base_path, env) { rd_section("tip", x$val) } ``` ```{r, include = FALSE} # Needed for vignette registerS3method("roxy_tag_rd", "roxy_tag_tip", roxy_tag_rd.roxy_tag_tip) ``` This additional layer is needed because there can multiple tags of the same time in a single block, and multiple blocks can contribute to the same `.Rd` file. The job of the `rd_section` is to combine all the tags into a single top-level Rd section. Each tag generates an `rd_section` which is then combined with any previous section using `merge()`. The default `merge.rd_section()` just concatenates the values together (`rd_section(x$type, c(x$value, y$value))`); you can override this method if you need more sophisticated behaviour. We then need to define a `format()` method to converts this object into text for the `.Rd` file: ```{r} format.rd_section_tip <- function(x, ...) { paste0( "\\section{Tips and tricks}{\n", "\\itemize{\n", paste0(" \\item ", x$value, "\n", collapse = ""), "}\n", "}\n" ) } ``` ```{r, include = FALSE} # Needed for vignette registerS3method("format", "rd_section_tip", format.rd_section_tip) ``` We can now try this out with `roclet_text()`: ```{r} topic <- roc_proc_text(rd_roclet(), text)[[1]] topic$get_section("tip") ``` Note that there is no namespacing so if you're defining multiple new tags I recommend using your package name as common prefix. ## Creating a new roclet Creating a new roclet is usually a two part process. First, you define new tags that your roclet will work with. Second, you define a roclet that tells roxygen how to process an entire package. ### Custom tags In this example we will make a new `@memo` tag to enable printing the memos at the console when the roclet runs. We choose that the `@memo` has this syntax: ``` @memo [Headline] Description ``` As an example: ``` @memo [EFFICIENCY] Currently brute-force; find better algorithm. ``` As above, we first define a parse method: ```{r} roxy_tag_parse.roxy_tag_memo <- function(x) { if (!grepl("^\\[.*\\].*$", x$raw)) { roxy_tag_warning(x, "Invalid memo format") return() } parsed <- stringi::stri_match(str = x$raw, regex = "\\[(.*)\\](.*)")[1, ] x$val <- list( header = parsed[[2]], message = parsed[[3]] ) x } ``` ```{r, include = FALSE} # Needed for vignette registerS3method("roxy_tag_parse", "roxy_tag_memo", roxy_tag_parse.roxy_tag_memo) ``` Then check it works with `parse_text()`: ```{r} text <- " #' @memo [TBI] Remember to implement this! #' @memo [API] Check best API f <- function(x, y) { # ... } " block <- parse_text(text)[[1]] block str(block$tags[[1]]) ``` ### The roclet Next we create a constructor for the roclet, which uses `roclet()`. Our `memo` roclet doesn't have any options so this is very simple: ```{r} memo_roclet <- function() { roclet("memo") } ``` To give the roclet behaviour, you need to define method. There are two methods that almost every roclet will use: * `roclet_process()` is called with a list of blocks, and returns an object of your choosing. * `roclet_output()`: performs side-effects (usually writing to disk) using the result from `roclet_process()` For this roclet, we'll have `roclet_process()` collect all the memo tags into a named list: ```{r} roclet_process.roclet_memo <- function(x, blocks, env, base_path) { results <- list() for (block in blocks) { tags <- block_get_tags(block, "memo") for (tag in tags) { msg <- paste0("[", tag$file, ":", tag$line, "] ", tag$val$message) results[[tag$val$header]] <- c(results[[tag$val$header]], msg) } } results } ``` And then have `roclet_output()` just print them to the screen: ```{r} roclet_output.roclet_memo <- function(x, results, base_path, ...) { for (header in names(results)) { messages <- results[[header]] cat(paste0(header, ": ", "\n")) cat(paste0(" * ", messages, "\n", collapse = "")) } invisible(NULL) } ``` ```{r, include = FALSE} # Needed for vignette registerS3method("roclet_process", "roclet_memo", roclet_process.roclet_memo) registerS3method("roclet_output", "roclet_memo", roclet_output.roclet_memo) ``` Then you can test it works by using `roc_proc_text()`: ```{r} results <- roc_proc_text(memo_roclet(), " #' @memo [TBI] Remember to implement this! #' @memo [API] Check best API f <- function(x, y) { # ... } #' @memo [API] Consider passing z option g <- function(x, y) { # ... } ") roclet_output(memo_roclet(), results) ``` roxygen2/vignettes/rd.Rmd0000644000176200001440000006663214047223751015132 0ustar liggesusers--- title: "Rd (documentation) tags" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Rd (documentation) tags} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ``` ## Basics A roxygen __block__ is a sequence of lines starting with `#'` (optionally preceded by whitespace). Blocks gain additional structure through the use of __tags__ like `@tag details`. Tags must start at the beginning of a line, and the content of a tag extends to the start of the next tag (or the end of the block). Text within roxygen blocks can be formatted using markdown or `Rd` commands; see `vignette("rd-formatting")` for details. ## The description block Each documentation block starts with some text which defines the title, the description, and the details. Here's an example showing what the documentation for `sum()` might look like if it had been written with roxygen: ```{r} #' Sum of vector elements #' #' `sum` returns the sum of all the values present in its arguments. #' #' This is a generic function: methods can be defined for it directly #' or via the [Summary()] group generic. For this to work properly, #' the arguments `...` should be unnamed, and dispatch is on the #' first argument. sum <- function(..., na.rm = TRUE) {} ``` This introductory block is broken up as follows: * The first sentence is the __title__: that's what you see when you look at `help(package = mypackage)` and is shown at the top of each help file. It should generally fit on one line, be written in sentence case, and not end in a full stop. * The second paragraph is the __description__: this comes first in the documentation and should briefly describe what the function does. * The third and subsequent paragraphs go into the __details__: this is a (often long) section that comes after the argument description and should provide any other important details of how the function operates. The details are optional. You can also use explicit `@title`, `@description`, and `@details` tags. This is unnecessary unless you want to have a multi-paragraph description, bulleted list, or other more exotic structure. ```{r} #' Sum of vector elements #' #' @description #' `sum` returns the sum of all the values present in its arguments. #' #' @details #' This is a generic function: methods can be defined for it directly #' or via the [Summary()] group generic. For this to work properly, #' the arguments `...` should be unnamed, and dispatch is on the #' first argument. ``` ## Object specifics Further details of roxygen2 depend on what you're documenting. The following sections describe the most commonly used tags for functions, S3, S4, datasets, and packages. ### Functions Functions are the mostly commonly documented objects. Most functions use three tags: * `@param name description` describes the inputs to the function. The description should provide a succinct summary of the type of the parameter (e.g. a string, a numeric vector), and if not obvious from the name, what the parameter does. The description should start with a capital letter and end with a full stop. It can span multiple lines (or even paragraphs) if necessary. All parameters must be documented. You can document multiple arguments in one place by separating the names with commas (no spaces). For example, to document both `x` and `y`, you can say `@param x,y Numeric vectors`. * `@examples` provides executable R code showing how to use the function in practice. This is a very important part of the documentation because many people look at the examples before reading anything. Example code must work without errors as it is run automatically as part of `R CMD check`. However for the purpose of illustration, it's often useful to include code that causes an error. `\dontrun{}` allows you to include code in the example that is never used. There are two other special commands. `\dontshow{}` is run, but not shown in the help page: this can be useful for informal tests. `\donttest{}` is run in examples, but not run automatically in `R CMD check`. This is useful if you have examples that take a long time to run. The options are summarised below. Command | example | help | R CMD check | R CMD check --as-cran ------------ | --------- | ------ | ----------- | --------------------- `\dontrun{}` | | x | | `\dontshow{}`| x | | x | x `\donttest{}`| x | x | | x Note that `R CMD check --as-cran` is run for incoming CRAN checks but not for regular CRAN checks. For finer control you can use `@examplesIf ```r #' @examplesIf interactive() #' browseURL("https://roxygen2.r-lib.org") ``` will generate ``` \examples{ \dontshow{if (interactive() (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} gh_organizations(since = 42) \dontshow{\}) # examplesIf} } ``` This way the code evaluating whether the example can be run is not shown to users reading the help, but it still prevents R CMD check failures. Instead of including examples directly in the documentation, you can put them in separate files and use `@example path/relative/to/package/root` to insert them into the documentation. * `@return description` describes the output from the function. This is not always necessary, but is a good idea if you return different types of outputs depending on the input, or you're returning an S3, S4 or RC object. We could use these new tags to improve our documentation of `sum()` as follows: ```{r} #' Sum of vector elements #' #' `sum()` returns the sum of all the values present in its arguments. #' #' This is a generic function: methods can be defined for it directly #' or via the [Summary] group generic. For this to work properly, #' the arguments `...` should be unnamed, and dispatch is on the #' first argument. #' #' @param ... Numeric, complex, or logical vectors. #' @param na.rm A logical scalar. Should missing values (including `NaN`) #' be removed? #' @return If all inputs are integer and logical, then the output #' will be an integer. If integer overflow #' () occurs, the output #' will be NA with a warning. Otherwise it will be a length-one numeric or #' complex vector. #' #' Zero-length vectors have sum 0 by definition. See #' for more details. #' @examples #' sum(1:10) #' sum(1:5, 6:10) #' sum(F, F, F, T, T) #' #' sum(.Machine$integer.max, 1L) #' sum(.Machine$integer.max, 1) #' #' \dontrun{ #' sum("a") #' } sum <- function(..., na.rm = TRUE) {} ``` Indent the second and subsequent lines of a tag so that when scanning the documentation so it's easy to see where one tag ends and the next begins. Tags that always span multiple lines (like `@example`) should start on a new line and don't need to be indented. ### S3 * S3 __generics__ are regular functions, so document them as such. If necessary, include a `@section` that provides additional details for method implementors * S3 __classes__ have no formal definition, so document the [constructor](https://adv-r.hadley.nz/s3.html#s3-constructor). * It is your choice whether or not to document S3 __methods__. Generally, it's not necessary to document straightforward methods for common generics like `print()`. (You should, however, always `@export` S3 methods). If your method is more complicated, you should document it by setting `@rdname`. Typically you will document methods with their generic, so you'd document `foofy.data.frame` by setting `@rdname`. In base R, you can find documentation for more complex methods like `?predict.lm`, `?predict.glm`, and `?anova.glm`. Generally, roxygen2 will automatically figure out the generic that the method belongs to, and you should only need to use `@method` if there is ambiguity. For example, is `all.equal.data.frame()` the `equal.data.frame` method for `all()`, or the `data.frame` method for `all.equal()`?. If this happens to you, disambiguate with (e.g.) `@method all.equal data.frame`. ### S4 S4 __generics__ are also functions, so document them as such. Document __S4 classes__ by adding a roxygen block before `setClass()`. Use `@slot` to document the slots of the class. Here's a simple example: ```{r} #' An S4 class to represent a bank account #' #' @slot balance A length-one numeric vector Account <- setClass("Account", slots = list(balance = "numeric") ) ``` S4 __methods__ are a little more complicated. Unlike S3 methods, all S4 methods must be documented. You can document them in three places: * In the class. Most appropriate if the corresponding generic uses single dispatch and you created the class. * In the generic. Most appropriate if the generic uses multiple dispatch and you control it. * In its own file. Most appropriate if the method is complex. or the either two options don't apply. Use either `@rdname` or `@describeIn` to control where method documentation goes. See the next section for more details. ### R6 Starting from version 7.0.0 roxygen treats documentation for R6 classes specially: * R6 methods can be documented in-line, i.e. the method's documentation comments come right before the definition of the method. * Method documentation can use the `@description`, `@details`, `@param`, `@return` and `@examples` tags. These are used to create a subsection for the method, within a separate 'Methods' section. All roxygen comment lines of a method documentation must appear after a tag. * `@param` tags that appear before the class definition are automatically inherited by all methods, if needed. * R6 fields and active bindings can make use of the `@field` tag. Their documentation should also be in-line. * Roxygen2 checks that all public methods, public fields, active bindings and all method arguments are documented, and issues warnings otherwise. * To turn off the special handling of R6 classes and go back to the roxygen2 6.x.x behavior, use the `r6 = FALSE` option in `DESCRIPTION`, in the `Roxygen` entry: `Roxygen: list(r6 = FALSE)`. Roxygen2 automatically generates additional sections for an R6 class: * A section with information about the superclass(es) of the class, with links. In HTML this includes a list of all inherited methods, with links. * An 'Examples' section that contains all class and method examples. This section is run by `R CMD check`, so method examples must work without errors. An example from the R6 tutorial: ```{r} #' R6 Class Representing a Person #' #' @description #' A person has a name and a hair color. #' #' @details #' A person can also greet you. Person <- R6::R6Class("Person", public = list( #' @field name First or full name of the person. name = NULL, #' @field hair Hair color of the person. hair = NULL, #' @description #' Create a new person object. #' @param name Name. #' @param hair Hair color. #' @return A new `Person` object. initialize = function(name = NA, hair = NA) { self$name <- name self$hair <- hair self$greet() }, #' @description #' Change hair color. #' @param val New hair color. #' @examples #' P <- Person("Ann", "black") #' P$hair #' P$set_hair("red") #' P$hair set_hair = function(val) { self$hair <- val }, #' @description #' Say hi. greet = function() { cat(paste0("Hello, my name is ", self$name, ".\n")) } ) ) ``` ### Datasets Datasets are usually stored as `.rdata` files in `data/` and not as regular R objects in the package. This means you need to document them slightly differently: instead of documenting the data directly, you quote the dataset's name. ```{r} #' Prices of 50,000 round cut diamonds #' #' A dataset containing the prices and other attributes of almost 54,000 #' diamonds. #' #' @format A data frame with 53940 rows and 10 variables #' \describe{ #' \item{price}{price in US dollars (\$326--\$18,823)} #' \item{carat}{weight of the diamond (0.2--5.01)} #' \item{cut}{quality of the cut (Fair, Good, Very Good, Premium, Ideal)} #' \item{color}{diamond colour, from D (best) to J (worst)} #' \item{clarity}{a measurement of how clear the diamond is (I1 (worst), SI2, #' SI1, VS2, VS1, VVS2, VVS1, IF (best))} #' \item{x}{length in mm (0--10.74)} #' \item{y}{width in mm (0--58.9)} #' \item{z}{depth in mm (0--31.8)} #' \item{depth}{total depth percentage = z / mean(x, y) = 2 * z / (x + y) (43--79)} #' \item{table}{width of top of diamond relative to widest point (43--95)} #' } #' @source "diamonds" ``` Note the use of two additional tags that are particularly useful for documenting data: * `@format`, which gives an overview of the structure of the dataset. This should include a __definition list__ that describes each variable. There's currently no way to generate this with markdown, so this is one of the few places you'll need to Rd markup directly. * `@source` where you got the data form, often a URL. ### Packages As well as documenting every object inside the package, you can also document the package itself by documenting the special sentinel `"_PACKAGE"`. We recommend placing package documentation in `{pkgname}-package.R`, and have `@keywords internal`. Here's an example: ```{r, eval = FALSE} #' @details #' The only function you're likely to need from roxygen2 is [roxygenize()]. #' Otherwise refer to the vignettes to see how to format the documentation. #' @keywords internal "_PACKAGE" ``` Package documentation is a good place to put `@section Package options:` that documents options used by the package. Some notes: * Package documentation will automatically include information parsed from the `DESCRIPTION`, including title, description, list of authors, and useful URLs. * By default, aliases will be added so that both `?pkgname` and `package?pkgname` will find the package help. If there's an existing function called `pkgname`, use `@aliases {pkgname}-package` to override the default. * `usethis::use_package_doc()` will generate a basic template to get you started. * Use `@references` to point to published material about the package that users might find helpful. ## Sections You can add arbitrary sections with the `@section` tag. This is a useful way of breaking a long details section into multiple chunks with useful headings. Section titles should be in sentence case, must fit on one line, and must be followed by a colon. ```{r} #' @section Warning: #' Do not operate heavy machinery within 8 hours of using this function. ``` You can also create sections using the markdown syntax for headers. For example, the previously-defined section can be created with markdown headers like this: ```{r} #' @details # Warning #' Do not operate heavy machinery within 8 hours of using this function. ``` Note that '`#`' may only appear after the `@description` and `@details` tags. Since `@details` can appear multiple times in a block, you can always precede a '`#`' section with `@details`. To add a subsection, use level two or greater headings: ```{r} #' @details # Warning #' You must not call this function unless ... #' #' ## Exceptions #' Apart from the following special cases... ``` If you find yourself adding a lot of sections, you might consider using a vignette instead. ## Do repeat yourself There is a tension between the DRY (do not repeat yourself) principle of programming and the need for documentation to be self-contained. It's frustrating to have to navigate through multiple help files in order to pull together all the pieces you need. Roxygen2 provides several ways to avoid repeating yourself in code documentation, while assembling information from multiple places in one documentation file: * Cross-link documentation files with `@seealso` and `@family`. * Inherit documentation from another topic with `@inherit`, `@inheritParams`, and `@inheritSection`. * Document multiple functions in the same topic with `@describeIn` or `@rdname`. * Run arbitrary R code with the markdown markup for inline code, see section 'Dynamic R code' in `vignette("rd-formatting")`. * Run arbitrary R code with `@eval`. * Create reusable templates with `@template` and `@templateVar`. ### Cross-references There are two tags that make it easier for people to navigate around your documentation: `@seealso` and `@family`. `@seealso` allows you to point to other useful resources, either on the web `` or to other documentation with `[function_name()]`. If you have a family of related functions, you can use `@family {family}` to cross-reference each function to every other function within the family. A function can be a member of multiple families. For `sum()`, this might look like: ```{r} #' @family aggregations #' @seealso [prod()] for products, [cumsum()] for cumulative sums, and #' [colSums()]/[rowSums()] marginal sums over high-dimensional arrays. ``` By default `@family {family}`, will generate the see also text "Other {family}:", so the `@family` name should be plural (i.e., "model building helpers" not "model building helper"). You can override the default title by providing a `rd_family_title` list in `man/roxygen/meta.R`: ```{r, eval = FALSE} list( rd_family_title = list(aggregations = "Aggregation functions") ) ``` ### Inheriting documentation from other topics You can inherit documentation from other functions in a few ways: * `@inherit source_function` will inherit parameters, return, references, description, details, sections, and seealso from `source_function()`. * `@inherit source_function return details` will inherit selected components from `source_function()` * `@inheritParams source_function` inherits just the parameter documentation from `source_function()`. * `@inheritSection source_function Section title` will inherit the single `@section` called "Section title" from `source_function()`. All of these work recursively so you can inherit documentation from a function that has inherited it from elsewhere. You can also inherit documentation from functions provided by another package by using `pkg::source_function`. ### Documenting multiple functions in the same file 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` `@describeIn` is designed for the most common cases: * documenting methods in a generic * documenting methods in a class * documenting functions with the same (or similar arguments) It generates a new section, named either "Methods (by class)", "Methods (by generic)" or "Functions". The section contains a bulleted list describing each function, labelled so that you know what function or method it's talking about. Here's an example, documenting an imaginary new generic: ```{r} #' Foo bar generic #' #' @param x Object to foo. foobar <- function(x) UseMethod("x") #' @describeIn foobar Difference between the mean and the median foobar.numeric <- function(x) abs(mean(x) - median(x)) #' @describeIn foobar First and last values pasted together in a string. foobar.character <- function(x) paste0(x[1], "-", x[length(x)]) ``` #### `@rdname` `@rdname` is a more general purpose tool. It overrides the default file name generated by roxygen and merges documentation for multiple objects into one file. This gives you complete freedom to combine documentation however you see fit. There are two ways to use `@rdname`. You can add documentation to an existing function: ```{r} #' Basic arithmetic #' #' @param x,y numeric vectors. add <- function(x, y) x + y #' @rdname add times <- function(x, y) x * y ``` Or, you can create a dummy documentation file by documenting `NULL` and setting an informative `@name`. ```{r} #' Basic arithmetic #' #' @param x,y numeric vectors. #' @name arith NULL #' @rdname arith add <- function(x, y) x + y #' @rdname arith times <- function(x, y) x * y ``` ### 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. ```{r} #' @rdname arith #' @order 2 add <- function(x, y) x + y #' @rdname arith #' @order 1 times <- function(x, y) x * y ``` ### Evaluating arbitrary code Another technique is the `@eval` tag. It evaluates code and treatments the result as if it was a literal roxygen tags. This makes it possible to eliminate duplication by writing functions. The code will be evaluated in the package environment and should yield a character vector of roxygen comments (but without the leading `#'`). For example, this code + roxygen block: ```{r} my_params <- function() { c( "@param x An integer vector", "@param y A character vector" ) } #' A title #' #' @eval my_params() #' @export foo <- function(x, y) { } ``` Is equivalent to: ```{r} #' A title #' #' @param x An integer vector #' @param y A character vector #' @export foo <- function(x, y) { } ``` Note that `@eval` cannot be embedded into another roxygen tag. If you want to dynamically generate part of a roxygen tag, see section 'Dynamic R code' in `vignette("rd-formatting")`. A related function is `@evalRd`. It works in the same way as `@eval` (i.e. it's evaluated in the package environment) but rather than yielding roxygen comments that are processed as if they had been typed directly, it yields top-level Rd code that is inserted directly into the generated `.Rd` file. It is primarily useful if you want to generate Rd structure that is not currently supported by roxygen2. For example, this block: ```{r} my_note <- function(x) { paste0("\\note{", paste0(x, "\n", collapse =""), "}") } #' @evalRd my_note(c( #' "This is the first line", #' "This is the second line" #' )) NULL ``` Would generate this Rd: ```latex \note{ This is the first line This is the second line } ``` ### Roxygen templates Roxygen templates are R files that contain only roxygen comments and that live in the `man-roxygen` directory. Use `@template file-name` (without extension) to insert the contents of a template into the current documentation. You can make templates more flexible by using template variables defined with `@templateVar name value`. Template files are run with brew, so you can retrieve values (or execute any other arbitrary R code) with `<%= name %>`. Note that templates are parsed a little differently to regular blocks, so you'll need to explicitly set the title, description and details with `@title`, `@description` and `@details`. ## Including external `.Rmd`/`.md` files Starting from roxygen2 7.0.0, you can use `@includeRmd path/to/file.Rmd` to include an external `.Rmd` or `.md` document into a manual page (the path is relative from the source package root directory). You can include the same file in multiple documentation files, and for the first time, share content across documentation and vignettes. ### Sections `@includeRmd` supports headings in the external Rmd. The rules are as follows: * All text before the first level 1 heading (i.e. `#`), is added to the details section. If you prefer a different section, then write the name of the section after the path in the `@includeRmd` tag, in all lowercase. Example: `@includeRmd path description`. This currently does not work with user defined sections (created with `@section`). * Level 1 headings generate their own section (`\section{}`). * Other headings (level 2 and so on) create subsections (`\subsection{}`) within the section they appear in. All content in the Rmd file will go either in the details or in new top level sections. It is currently not possible to document function arguments, return values, etc. in external Rmd documents. ### Links 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. ### Caching and figures `@includeRmd` tries to set up knitr to support caching in the Rmd file. It sets the cache path to the default knitr cache path of the included Rmd file (i.e. `foo/bar/file_cache/` for `foo/bar/file.Rmd`), so if you do not change the cache path within the Rmd itself, then everything should work out of the box. You should add these cache paths to `.gitignore` and `.Rbuildignore`. `@includeRmd` also sets the knitr figure path of the (`fig.path`) to the default figure path of the included Rmd. Overriding this default is unlikely to work. ### Sharing text between vignettes and the manual `@includeRmd` helps avoiding repetition, as you can use the same `.Rmd` or `.md` document in the manual and also in the `README.md` file or in vignettes. One way to include an Rmd file in another one is to use child documents: ```` ```{r child = "common.Rmd"}`r ''` ``` ```` If the Rmd file has links to other help topics, then some care is needed, as those links while not work in Rmd files. A workaround is to specify external HTML links for them. These external locations will _not_ be used for `@includeRmd`, which always links them 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. ## Other tags ### Indexing Three other tags make it easier for the user to find documentation within R's help system: * Aliases form the index that `?` searches. Use `@aliases space separated aliases` to add additional aliases. * `@concept` add extra keywords that will be found with `help.search()` * Use `@keywords keyword1 keyword2 ...` to add standardised keywords. Keywords are optional, but if present, must be taken from the predefined list found `file.path(R.home("doc"), "KEYWORDS")`. Apart from `@keywords internal`, these tags are not very useful because most people find documentation using Google. `@keywords internal` is useful because it removes the function from the documentation index; it's useful for functions aimed primarily at other developers, not typical users of the package. ### Back references The original source location is added as a comment to the second line of each generated `.Rd` file in the following form: ``` % Please edit documentation in ... ``` `roxygen2` tries to capture all locations from which the documentation is assembled. For code that *generates* R code with Roxygen comments (e.g., the Rcpp package), the `@backref` tag is provided. This allows specifying the "true" source of the documentation, and will substitute the default list of source files. Use one tag per source file: ```{r} #' @backref src/file.cpp #' @backref src/file.h ``` roxygen2/vignettes/namespace.Rmd0000644000176200001440000001140713631761325016451 0ustar liggesusers--- title: "NAMESPACE tags" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{NAMESPACE tags} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ``` The package `NAMESPACE` is one of the most confusing parts of building a package. Roxygen2 aims to make it as easy as possible to build a package that is a well-behaved member of the R ecosystem. This is a little frustrating at first, but soon becomes second-nature. ## Exports For a function to be usable outside of your package, you must __export__ it. By default roxygen2 doesn't export anything from your package. If you want an object to be publicly available, you must explicitly tag it with `@export`. Use the following guidelines to decide what to export: * Functions: export functions that you want to make available. Exported functions must be documented, and you must be cautious when changing their interface. * Datasets: all datasets are publicly available. They exist outside of the package namespace and should not be exported. * S3 classes: if you want others to be able to create instances of the class `@export` the constructor function. * S3 generics: the generic is a function so `@export` if you want it to be usable outside the package * S3 methods: every S3 method _must_ be exported, even if the generic is not. Otherwise the S3 method table will not be generated correctly and internal generics will not find the correct method. If you are providing a method for a generic defined in another package, you must also import that generic. * S4 classes: if you want others to be able to extend your class, `@export` it. If you want others to create instances of your class, but not extend it, `@export` the constructor function, but not the class. ```R # Can extend and create #' @export setClass("A") # Can extend, but constructor not exported #' @export B <- setClass("B") # Can create, but not extend #' @export C C <- setClass("C") # Can create and extend #' @export D #' @exportClass D D <- setClass("D") ``` * S4 generics: `@export` if you want the generic to be publicly usable. * S4 methods: you only need to `@export` methods for generics that you did not define. * RC classes: the same principles apply as for S4 classes. `@export` will only export the class. ### Specialised exports Generally, roxygen2 can generate the correct namespace directive when `@export`ing a specific object. However, you may want to override the defaults and exercise greater control. In this case you can use the more specialised tags described below: * `@export foo` generates `export(foo)` * `@exportClass foo` generates `exportClasses(foo)` * `@exportMethod foo` generates `exportMethods(foo)` * `@exportPattern foo` generates `exportPattern(foo)` For even more specialised cases you can use `@rawNamespace code` which inserts `code` literally into the `NAMESPACE`. If you need to automate this, `@evalNamespace foo()` will evaluate the `foo()` in the package environment and insert the results into `NAMESPACE`. Because `evalNamespace()` is run in the package environment, it can only generate exports, not imports. ## Imports The `NAMESPACE` also controls which functions from other packages are made available to your package. Only unique directives are saved to the `NAMESPACE` file, so you can repeat them as needed to maintain a close link between the functions where they are needed and the namespace file. If you are using just a few functions from another package, the recommended option is to note the package name in the `Imports:` field of the `DESCRIPTION` file and call the function(s) explicitly using `::`, e.g., `pkg::fun()`. Alternatively, though no longer recommended due to its poorer readability, use `@importFrom`, e.g., `@importFrom pgk fun`, and call the function(s) without `::`. If you are using many functions from another package, use `@import package` to import them all and make available without using `::`. If you want to add a new method to an S3 generic, import it with `@importFrom pkg generic`. If you are using S4 you may also need: * `@importClassesFrom package classa classb ...` to import selected S4 classes. * `@importMethodsFrom package methoda methodb ...` to import selected S4 methods. To import compiled code from another package, use `@useDynLib` * `@useDynLib package` imports all compiled functions. * `@useDynLib package routinea routineb` imports selected compiled functions. * Any `@useDynLib` specification containing a comma, e.g. `@useDynLib mypackage, .registration = TRUE` will be inserted as is into the the NAMESPACE, e.g. `useDynLib(mypackage, .registration = TRUE)` roxygen2/R/0000755000176200001440000000000014115752044012233 5ustar liggesusersroxygen2/R/rd.R0000644000176200001440000001461514115750050012765 0ustar liggesusers#' @import stringr NULL #' Roclet: make Rd files. #' #' @template rd #' @family roclets #' @eval rd_roclet_description() #' @export #' @examples #' #' The length of a string (in characters) #' #' #' #' @param x String input character vector #' #' @return An integer vector the same length as `x`. #' #' `NA` strings have `NA` length. #' #' @seealso [nchar()] #' #' @export #' #' @examples #' #' str_length(letters) #' #' str_length(c("i", "like", "programming", NA)) #' str_length <- function(x) { #' } rd_roclet <- function() { roclet("rd") } rd_roclet_description <- function() { c( "@description", "Generally you will not call this function directly", "but will instead use roxygenise() specifying the rd roclet" ) } #' @export roclet_process.roclet_rd <- function(x, blocks, env, base_path) { # Convert each block into a topic, indexed by filename topics <- RoxyTopics$new() for (block in blocks) { rd <- block_to_rd(block, base_path, env) topics$add(rd) } topics_process_family(topics, env) topics_process_inherit(topics, env) topics$drop_invalid() topics_fix_params_order(topics) topics_add_default_description(topics) topics$topics } #' @export roclet_output.roclet_rd <- function(x, results, base_path, ..., is_first = FALSE) { man <- normalizePath(file.path(base_path, "man")) contents <- map_chr(results, format) paths <- file.path(man, names(results)) # Always check for roxygen2 header before overwriting NAMESPACE (#436), # even when running for the first time mapply(write_if_different, paths, contents, MoreArgs = list(check = TRUE)) if (!is_first) { # Automatically delete any files in man directory that were generated # by roxygen in the past, but weren't generated in this sweep. old_paths <- setdiff(dir(man, full.names = TRUE), paths) old_paths <- old_paths[!file.info(old_paths)$isdir] old_roxygen <- Filter(made_by_roxygen, old_paths) if (length(old_roxygen) > 0) { message(paste0("Deleting ", basename(old_roxygen), collapse = "\n")) unlink(old_roxygen) } } paths } #' @export roclet_clean.roclet_rd <- function(x, base_path) { rd <- dir(file.path(base_path, "man"), full.names = TRUE) rd <- rd[!file.info(rd)$isdir] unlink(purrr::keep(rd, made_by_roxygen)) } # Does this block get an Rd file? needs_doc <- function(block) { if (block_has_tags(block, "noRd")) { return(FALSE) } block_has_tags(block, c( "description", "param", "return", "title", "example", "examples", "name", "rdname", "details", "inherit", "describeIn") ) } # Tag processing functions ------------------------------------------------ block_to_rd <- function(block, base_path, env) { UseMethod("block_to_rd") } #' @export block_to_rd.default <- function(block, ...) { stop("Internal roxygen error, unknown block type") } #' @export block_to_rd.roxy_block <- function(block, base_path, env) { # Must start by processing templates block <- process_templates(block, base_path) if (!needs_doc(block)) { return() } name <- block_get_tag(block, "name")$val %||% block$object$topic if (is.null(name)) { roxy_tag_warning(block$tags[[1]], "Missing name") return() } rd <- RoxyTopic$new() topic_add_name_aliases(rd, block, name) for (tag in block$tags) { rd$add(roxy_tag_rd(tag, env = env, base_path = base_path)) } if (rd$has_section("description") && rd$has_section("reexport")) { roxy_tag_warning(block$tags[[1]], "Can't use description when re-exporting") return() } describe_rdname <- topic_add_describe_in(rd, block, env) filename <- describe_rdname %||% block_get_tag(block, "rdname")$val %||% nice_name(name) rd$filename <- paste0(filename, ".Rd") rd } #' @export block_to_rd.roxy_block_r6class <- function(block, base_path, env) { r6on <- roxy_meta_get("r6", TRUE) if (!isTRUE(r6on)) return(NextMethod()) # Must start by processing templates block <- process_templates(block, base_path) if (!needs_doc(block)) { return() } name <- block_get_tag(block, "name")$val %||% block$object$topic if (is.null(name)) { roxy_tag_warning(block$tags[[1]], "Missing name") return() } rd <- RoxyTopic$new() topic_add_name_aliases(rd, block, name) rd$add(roxy_tag_rd(block_get_tag(block, "name"), env = env, base_path = base_path)) rd$add(roxy_tag_rd(block_get_tag(block, "title"), env = env, base_path = base_path)) if (rd$has_section("description") && rd$has_section("reexport")) { roxy_tag_warning(block$tags[[1]], "Can't use description when re-exporting") return() } topic_add_r6_methods(rd, block, env) describe_rdname <- topic_add_describe_in(rd, block, env) filename <- describe_rdname %||% block_get_tag(block, "rdname")$val %||% nice_name(name) rd$filename <- paste0(filename, ".Rd") rd } # Special cases ----------------------------------------------------------- topics_add_default_description <- function(topics) { for (topic in topics$topics) { if (length(topic$get_section("description")) > 0) next # rexport manually generates a own description, so don't need to if (!topic$has_section("reexport") && !identical(topic$get_value("docType"), "package")) { topic$add(rd_section("description", topic$get_value("title"))) } } invisible() } # Tag-wise processing ----------------------------------------------------- #' Generate Rd output from a tag #' #' Provide a method for this generic if you want a tag to generate output #' in `.Rd` files. See `vignette("extending")` for more details. #' #' @param x The tag #' @param base_path Path to package root directory. #' @param env Environment in which to evaluate code (if needed) #' @return Methods must return a [rd_section]. #' @export #' @keywords internal roxy_tag_rd <- function(x, base_path, env) { UseMethod("roxy_tag_rd") } roxy_tag_rd.default <- function(x, base_path, env) { } # Special tags ------------------------------------------------------------ # These tags do not directly affect the output, and are no complicated enough # to require their own files. #' @export roxy_tag_rd.roxy_tag_.formals <- function(x, base_path, env) { rd_section("formals", x$val) } #' @export format.rd_section_formals <- function(x, ...) NULL #' @export roxy_tag_parse.roxy_tag_method <- function(x) tag_words(x, 2, 2) #' @export roxy_tag_parse.roxy_tag_noRd <- function(x) tag_toggle(x) #' @export roxy_tag_parse.roxy_tag_rdname <- function(x) tag_value(x) roxygen2/R/select-args.R0000644000176200001440000000310513523072405014564 0ustar liggesusersselect_args_text <- function(fun, select = "") { pieces <- strsplit(select, " +")[[1]] tryCatch( { parsed <- lapply(pieces, function(x) parse(text = x)[[1]]) }, error = function(e) { stop("Failed to parse: '", select, "'", call. = FALSE) } ) select_args(fun, parsed) } # Figure out which arguments that the user wants given a function and # unevaluated list select_args <- function(fun, select = list()) { stopifnot(is.function(fun)) stopifnot(is.list(select)) args <- names(formals(fun)) args <- args[args != "..."] if (length(select) == 0) { return(args) } # Construct environment that allow minimal select-style semantics arg_idx <- as.list(setNames(seq_along(args), args)) arg_env <- list2env(arg_idx, parent = emptyenv()) arg_env$`:` <- `:` arg_env$`-` <- `-` arg_env$`(` <- `(` indices <- lapply(select, eval, envir = arg_env) for (i in seq_along(select)) { select_check(indices[[i]], select[[i]]) } # If first is negative, start with all vars # If first is positive, start with no vars select <- rep(select_sign(indices[[1]]) < 0, length(args)) for (idx in indices) { select[abs(idx)] <- select_sign(idx) > 0 } args[select] } select_check <- function(x, call) { if (is.numeric(x) && (all(x > 0) || all(x < 0))) return() stop( "Arguments must evaluate to all positive or negative numbers.\n", "Problem: ", paste(deparse(call), collapse = ""), call. = FALSE ) } select_sign <- function(x) { if (all(x > 0)) { 1 } else if (all(x < 0)) { -1 } else { NA } } roxygen2/R/load.R0000644000176200001440000000544314047223751013305 0ustar liggesusers#' Load package code #' #' @description #' roxygen2 is a dynamic documentation system, which means it works with the #' objects inside your package, not just the source code used to create them. #' These functions offer various ways of loading your package to suit various #' constraints: #' #' * `load_pkgload()` uses `pkgload::load_all()` to simulate package loading #' as closely as we know how. It offers high fidelity handling of code that #' uses S4, but requires that the package be compiled. #' #' * `load_source()` simulates package loading by attaching packages listed in #' `Depends` and `Imports`, then sources all files in the `R/` directory. #' This was the default strategy used in roxygen2 6.0.0 and earlier; #' it's primary advantage is that it does not need compilation. #' #' * `load_installed()` uses the installed version of the package. Use this #' strategy if you have installed a development version of the package #' already. This is the highest fidelity strategy, but requires work #' outside of roxygen2. #' #' You can change the default strategy for your function with roxygen2 `load` #' option. Override the default off `pkgload` to use the `source` or #' `installed` strategies: #' #' ``` #' Roxygen: list(load = "source") #' ``` #' @name load #' @param path Path to source package NULL #' @rdname load #' @export load_pkgload <- function(path) { pkgload::load_all(path, helpers = FALSE, attach_testthat = FALSE)$env } #' @rdname load #' @export load_installed <- function(path) { package <- desc::desc_get_field("Package", file = path) asNamespace(package) } #' @rdname load #' @export load_source <- function(path) { # Create environment env <- new.env(parent = globalenv()) methods::setPackageName("roxygen_devtest", env) # Attach dependencies deps <- desc::desc_get_deps(path) pkgs <- deps$package[ deps$type %in% c("Depends", "Imports") & deps$package != "R" ] lapply(pkgs, require, character.only = TRUE) # Source files lapply(package_files(path), sys_source, envir = env) env } sys_source <- function(file, envir = baseenv()) { exprs <- parse(text = read_lines(file)) for (expr in exprs) { eval(expr, envir = envir) } invisible() } # Helpers ----------------------------------------------------------------- find_load_strategy <- function(x, option = roxy_meta_get("load", "pkgload")) { if (is.function(x)) { return(x) } if (is.null(x)) { x <- option if (!is.character(x) || length(x) != 1) { abort("roxygen2 `load` option must be a string") } } else { if (!is.character(x) || length(x) != 1) { abort("`load_code` must be a string or function") } } switch(x, pkgload = load_pkgload, source = load_source, installed = load_installed, abort("Unknown value of `load` option") ) } roxygen2/R/rd-r6.R0000644000176200001440000003044113631761325013316 0ustar liggesusers topic_add_r6_methods <- function(rd, block, env) { r6data <- block_get_tag_value(block, ".r6data") self <- r6data$self methods <- self[self$type == "method", ] methods <- methods[order(methods$file, methods$line), ] methods$tags <- replicate(nrow(methods), list(), simplify = FALSE) r6_tags <- c("description", "details", "param", "return", "examples") del <- integer() for (i in seq_along(block$tags)) { tag <- block$tags[[i]] # Not inline? if (is.na(tag$line) || tag$line < block$line) next # Not a method tag? if (! tag$tag %in% r6_tags) next del <- c(del, i) meth <- find_method_for_tag(methods, tag) if (is.na(meth)) { roxy_tag_warning(tag, "Cannot find matching R6 method") next } midx <- which(meth == methods$name) methods$tags[[midx]] <- c(methods$tags[[midx]], list(tag)) del <- c(del, i) } methods <- add_default_methods(methods) nodoc <- map_int(methods$tags, length) == 0 r6_warning(block, "undocumented R6 method[s]: %s", methods$name[nodoc]) block$tags[del] <- NULL # Now do the main tags first. We leave out the param tags, those are # for the methods for (tag in block$tags) { if (! tag$tag %in% c("param", "field")) { rd$add(roxy_tag_rd(tag, env = env, base_path = base_path)) } } # We need to add the whole thing as a big section. rd_lines <- c( r6_superclass(block, r6data, env), r6_fields(block, r6data), r6_active_bindings(block, r6data), r6_methods(block, r6data, methods) ) rd$add(rd_section("rawRd", paste(rd_lines, collapse = "\n"))) # Dump all method examples at the end of the examples block ex_lines <- r6_all_examples(block, methods) if (length(ex_lines) > 0) { ex_txt <- paste0(r6_all_examples(block, methods), collapse = "\n") rd$add(rd_section("examples", ex_txt), overwrite = FALSE) } } add_default_methods <- function(methods) { defaults <- list( clone = list( roxy_tag_parse(roxy_tag( "description", "The objects of this class are cloneable with this method." )), roxy_tag_parse(roxy_tag("param", "deep Whether to make a deep clone.")) ) ) for (mname in names(defaults)) { mline <- match(mname, methods$name) if (is.na(mline)) next if (length(methods$tags[[mline]]) > 0) next methods$tags[[mline]] <- defaults[[mname]] } methods } r6_superclass <- function(block, r6data, env) { super <- r6data$super cls <- unique(super$classes$classname) if (length(cls) == 0) return() lines <- character() push <- function(...) lines <<- c(lines, ...) title <- if (length(cls) > 1) "Super classes" else "Super class" push(paste0("\\section{", title, "}{")) pkgs <- super$classes$package[match(cls, super$classes$classname)] path <- sprintf("\\code{\\link[%s:%s]{%s::%s}}", pkgs, cls, pkgs, cls) me <- sprintf("\\code{%s}", block$object$value$classname) push(paste(c(rev(path), me), collapse = " -> ")) push("}") lines } r6_fields <- function(block, r6data) { self <- r6data$self fields <- self$name[self$type == "field"] active <- self$name[self$type == "active"] tags <- purrr::keep( block$tags, function(t) t$tag == "field" && ! t$val$name %in% active ) labels <- gsub(",", ", ", map_chr(tags, c("val", "name"))) docd <- str_trim(unlist(strsplit(labels, ","))) # Check for missing fields miss <- setdiff(fields, docd) r6_warning(block, "undocumented R6 field[s]: %s", miss) # Check for duplicate fields dup <- unique(docd[duplicated(docd)]) r6_warning(block, "R6 field[s] documented multiple times: %s", dup) # Check for extra fields xtra <- setdiff(docd, fields) r6_warning(block, "unknown R6 field[s]: %s", xtra) if (length(docd) == 0) return() # We keep the order of the documentation vals <- map_chr(tags, c("val", "description")) c("\\section{Public fields}{", "\\if{html}{\\out{
}}", "\\describe{", paste0("\\item{\\code{", labels, "}}{", vals, "}", collapse = "\n\n"), "}", "\\if{html}{\\out{
}}", "}" ) } r6_active_bindings <- function(block, r6data) { self <- r6data$self fields <- self$name[self$type == "field"] active <- self$name[self$type == "active"] tags <- purrr::keep( block$tags, function(t) t$tag == "field" && ! t$val$name %in% fields ) labels <- gsub(",", ", ", map_chr(tags, c("val", "name"))) docd <- str_trim(unlist(strsplit(labels, ","))) # Check for missing bindings miss <- setdiff(active, docd) r6_warning(block, "undocumented R6 active binding[s]: %s", miss) # Check for duplicate bindings dup <- unique(docd[duplicated(docd)]) r6_warning(block, "R6 active binding[s] documented multiple times: %s", dup) if (length(docd) == 0) return() # We keep the order of the documentation vals <- map_chr(tags, c("val", "description")) c("\\section{Active bindings}{", "\\if{html}{\\out{
}}", "\\describe{", paste0("\\item{\\code{", labels, "}}{", vals, "}", collapse = "\n\n"), "}", "\\if{html}{\\out{
}}", "}" ) } r6_methods <- function(block, r6data, methods) { # And then the methods, if any if (nrow(methods) == 0) return() lines <- character() push <- function(...) lines <<- c(lines, ...) push("\\section{Methods}{") push(r6_method_list(block, methods)) push(r6_inherited_method_list(block, r6data)) for (i in seq_len(nrow(methods))) { push(r6_method_begin(block, methods[i,])) push(r6_method_description(block, methods[i,])) push(r6_method_usage(block, methods[i,])) push(r6_method_params(block, methods[i,])) push(r6_method_details(block, methods[i,])) push(r6_method_return(block, methods[i,])) push(r6_method_examples(block, methods[i,])) push(r6_method_end(block, methods[i,])) } push("}") lines } find_method_for_tag <- function(methods, tag) { w <- which( basename(methods$file) == basename(tag$file) & methods$line > tag$line )[1] methods$name[w] } # vectorized r6_show_name <- function(names) { ifelse(names == "initialize", "new", names) } r6_method_list <- function(block, methods) { nms <- r6_show_name(methods$name) c("\\subsection{Public methods}{", "\\itemize{", sprintf( "\\item \\href{#method-%s}{\\code{%s$%s()}}", nms, block$object$alias, nms ), "}", "}" ) } r6_inherited_method_list <- function(block, r6data) { super <- r6data$super if (is.null(super)) return() # drop methods that were shadowed in a subclass super_meth <- super$members[super$members$type == "method", ] self <- r6data$self super_meth <- super_meth[! super_meth$name %in% self$name, ] super_meth <- super_meth[! duplicated(super_meth$name), ] super_meth <- super_meth[rev(seq_len(nrow(super_meth))), ] details <- paste0( "
Inherited methods" ) c("\\if{html}{", paste0("\\out{", details, "}"), "\\itemize{", sprintf( paste0( "\\item \\out{}", "\\href{../../%s/html/%s.html#method-%s}{\\code{%s::%s$%s()}}", "\\out{}" ), super_meth$package, super_meth$classname, super_meth$name, super_meth$package, super_meth$classname, super_meth$name, super_meth$package, super_meth$classname, super_meth$name ), "}", "\\out{
}", "}" ) } r6_method_begin <- function(block, method) { nm <- r6_show_name(method$name) c( "\\if{html}{\\out{
}}", paste0("\\if{html}{\\out{}}"), paste0("\\if{latex}{\\out{\\hypertarget{method-", nm, "}{}}}"), paste0("\\subsection{Method \\code{", nm, "()}}{") ) } r6_method_description <- function(block, method) { det <- purrr::keep(method$tags[[1]], function(t) t$tag == "description") # Add an empty line between @description tags, if there isn't one # there already txt <- map_chr(det, "val") c( sub("\n?\n?$", "\n\n", head(txt, -1)), utils::tail(txt, 1) ) } r6_method_usage <- function(block, method) { name <- paste0(block$object$alias, "$", r6_show_name(method$name)) fake <- paste(rep("X", nchar(name)), collapse = "") usage <- format(function_usage(fake, method$formals[[1]])) c( "\\subsection{Usage}{", paste0( "\\if{html}{\\out{
}}", "\\preformatted{", sub(paste0("^", fake), name, usage), "}", "\\if{html}{\\out{
}}" ), "}\n" ) } r6_method_details <- function(block, method) { det <- purrr::keep(method$tags[[1]], function(t) t$tag == "details") # Add an empty line between @details tags, if there isn't one # there already txt <- map_chr(det, "val") if (length(txt) == 0) return() c( "\\subsection{Details}{", sub("\n?\n?$", "\n\n", head(txt, -1)), utils::tail(txt, 1), "}\n" ) } r6_method_params <- function(block, method) { par <- purrr::keep(method$tags[[1]], function(t) t$tag == "param") nms <- gsub(",", ", ", map_chr(par, c("val", "name"))) # Each arg should appear exactly once mnames <- str_trim(unlist(strsplit(nms, ","))) dup <- unique(mnames[duplicated(mnames)]) for (m in dup) { roxy_warning( sprintf("argument `%s` documented multiple times for R6 method `%s`", m, method$name), file = block$file, line = method$line ) } # Now add the missing ones from the class fnames <- names(method$formals[[1]]) miss <- setdiff(fnames, mnames) is_in_cls <- map_lgl( block$tags, function(t) { !is.na(t$line) && t$line < block$line && t$tag == "param" && t$val$name %in% miss } ) par <- c(par, block$tags[is_in_cls]) # Check if anything is missing nms <- gsub(",", ", ", map_chr(par, c("val", "name"))) mnames <- str_trim(unlist(strsplit(nms, ","))) miss <- setdiff(fnames, mnames) for (m in miss) { roxy_warning( sprintf("argument `%s` undocumented for R6 method `%s()`", m, method$name), file = block$file, line = method$line ) } if (length(par) == 0) return() # Order them according to formals firstnames <- str_trim( map_chr(strsplit(map_chr(par, c("val", "name")), ","), 1) ) par <- par[order(match(firstnames, fnames))] val <- map_chr(par, c("val", "description")) nms <- gsub(",", ", ", map_chr(par, c("val", "name"))) # Ready to go c( "\\subsection{Arguments}{", "\\if{html}{\\out{
}}", "\\describe{", paste0("\\item{\\code{", nms, "}}{", val, "}", collapse = "\n\n"), "}", "\\if{html}{\\out{
}}", "}" ) } r6_method_return <- function(block, method) { ret <- purrr::keep(method$tags[[1]], function(t) t$tag == "return") if (length(ret) == 0) return() if (length(ret) > 1) { roxy_tag_warning(ret[[2]], "May only use one @return per R6 method") } ret <- ret[[1]] c( "\\subsection{Returns}{", ret$val, "}" ) } r6_method_examples <- function(block, method) { exa <- purrr::keep(method$tags[[1]], function(t) t$tag == "examples") if (length(exa) == 0) return() txt <- map_chr(exa, "val") c("\\subsection{Examples}{", paste0( "\\if{html}{\\out{
}}\n", "\\preformatted{", txt, "\n", "}\n", "\\if{html}{\\out{
}}\n", collapse = "\n" ), "}\n" ) } r6_method_end <- function(block, method) { c( "}" ) } r6_all_examples <- function(block, methods) { unlist(lapply( seq_len(nrow(methods)), function(i) { exa <- purrr::keep(methods$tags[[i]], function(t) t$tag == "examples") if (length(exa) == 0) return() name <- paste0(block$object$alias, "$", r6_show_name(methods$name[i])) c( "\n## ------------------------------------------------", paste0("## Method `", name, "`"), "## ------------------------------------------------\n", paste(map_chr(exa, "val"), collapse = "\n") ) })) } first_five <- function(x) { x <- encodeString(x, quote = "`") if (length(x) > 5) x <- c(x[1:5], "...") paste(x, collapse = ", ") } r6_warning <- function(block, template, bad) { if (length(bad) == 0) return() badlist <- first_five(bad) template <- gsub("[s]", if (length(bad) == 1) "" else "s", template, fixed = TRUE) roxy_warning(sprintf(template, badlist), file = block$file, line = block$line) } roxygen2/R/utils.R0000644000176200001440000001015413631761131013516 0ustar liggesusersinternal_f <- function(p, f) { stopifnot(is.character(p), length(p) == 1) stopifnot(is.character(f), length(f) == 1) get(f, envir = asNamespace(p)) } "%||%" <- function(a, b) { if (length(a) > 0) a else b } subs <- matrix(ncol = 2, byrow = T, c( # Common special function names '[<-', 'subset', '[', 'sub', '<-', 'set', # Infix verbs '!', 'not', '&', 'and', '|', 'or', '*', 'times', '+', 'plus', '^', 'pow', # Others '"', 'quote', '#', 'hash', '$', 'cash', '%', 'grapes', "'", 'single-quote', '(', 'open-paren', ')', 'close-paren', ':', 'colon', ';', 'semi-colon', '<', 'less-than', '==', 'equals', '=', 'equals', '>', 'greater-than', '?', 'help', '@', 'at', ']', 'close-brace', '\\', 'backslash', '/', 'slash', '`', 'tick', '{', 'open-curly', '}', 'close', '~', 'twiddle' )) subs[, 2] <- paste0("-", subs[, 2], "-") nice_name <- function(x) { x <- stringi::stri_replace_all_fixed(x, subs[, 1], subs[, 2], vectorize_all = FALSE) # Clean up any remaining x <- str_replace_all(x, "[^A-Za-z0-9_.-]+", "-") x <- str_replace_all(x, "-+", "-") x <- str_replace_all(x, "^-|-$", "") x <- str_replace_all(x, "^\\.", "dot-") x } write_if_different <- function(path, contents, check = TRUE) { if (!file.exists(dirname(path))) { dir.create(dirname(path), showWarnings = FALSE) } if (check && !made_by_roxygen(path)) { warning("The existing '", basename(path), "' file was not generated by roxygen2, and will not be overwritten.", call. = FALSE, immediate. = TRUE) return(FALSE) } line_ending <- detect_line_ending(path) contents <- paste0(paste0(contents, collapse = line_ending), line_ending) contents <- enc2utf8(gsub("\r?\n", line_ending, contents)) if (same_contents(path, contents)) return(FALSE) name <- basename(path) if (!str_detect(name, "^[a-zA-Z][a-zA-Z0-9_.-]*$")) { cat("Skipping invalid path: ", name, "\n") FALSE } else { cat(sprintf('Writing %s\n', name)) writeBin(charToRaw(contents), path) TRUE } } same_contents <- function(path, contents) { if (length(contents) != 1) { stop("Internal roxygen error: `contents` must be character(1)") } if (!file.exists(path)) return(FALSE) text_hash <- digest::digest(contents, serialize = FALSE) path <- normalizePath(path, mustWork = TRUE) file_hash <- digest::digest(file = path) identical(text_hash, file_hash) } compact <- function(x) { x[!map_lgl(x, is.null)] } # Parse DESCRIPTION into convenient format read.description <- function(file) { dcf <- desc::desc(file = file) fields <- dcf$fields() purrr::map(purrr::set_names(fields), ~ dcf$get_field(.x)) } invert <- function(x) { if (length(x) == 0) return() stacked <- utils::stack(x) tapply(as.character(stacked$ind), stacked$values, list) } has_colons <- function(x) { grepl("::", x, fixed = TRUE) } # Collapse the values associated with duplicated keys collapse <- function(key, value, fun, ...) { stopifnot(is.character(key)) stopifnot(length(key) == length(value)) dedup <- tapply(value, key, fun, ..., simplify = FALSE) # tapply orders alphabetically, so reorder to match original order dedup <- dedup[unique(key)] list( key = names(dedup), value = unname(dedup) ) } cat_line <- function(...) { cat(paste0(..., "\n", collapse = "")) } tag_aliases <- function(f) { paste0("@aliases ", paste0("@", names(f()), collapse = " ")) } pkg_env <- function() { env <- new.env(parent = globalenv()) env$.packageName <- "roxygen2" env } uuid <- function(nchar = 8) { paste( sample(c(letters, LETTERS, 0:9), nchar, replace = TRUE), collapse = "" ) } # quoting ----------------------------------------------------------------- auto_backtick <- function(x) { needs_backtick <- !has_quotes(x) & !is_syntactic(x) x[needs_backtick] <- encodeString(x[needs_backtick], quote = "`") x } auto_quote <- function(x) { needs_quotes <- !has_quotes(x) & !is_syntactic(x) x[needs_quotes] <- encodeString(x[needs_quotes], quote = '"') x } is_syntactic <- function(x) make.names(x) == x has_quotes <- function(x) str_detect(x, "^(`|'|\").*\\1$") roxygen2/R/parse.R0000644000176200001440000000515714115750053013476 0ustar liggesusers#' Parse a package, file, or inline code #' #' `parse_package()`, `parse_file()`, and `parse_text()` allow you to use #' roxygen's parsing code to parse the roxygen blocks from a package, file, or #' character vector of code. `env_package()` and `env_file()` provide #' defaults that generate a temporary environment making it possible to #' associate each block with the corresponding live object. #' #' @param path,file,text Either specify a `path` to the root directory of #' a package, an R `file`, or a character vector `text`. #' @param env An environment environment containing the result of evaluating #' the input code. The defaults will do this for you in a test environment: #' for real code you'll need to generate the environment yourself. #' #' You can also set to `NULL` if you only want to get the tokenized code #' blocks only. This suppresses evaluation of `@eval` tags, and will not #' find the code object associated with each block. #' @return A list of roxy_block objects #' @export #' @keywords internal parse_package <- function(path = ".", env = env_package(path)) { files <- package_files(path) list_of_blocks <- lapply(files, tokenize_file) blocks <- purrr::flatten(list_of_blocks) if (!is.null(env)) { blocks <- lapply(blocks, block_set_env, env = env) } blocks <- order_blocks(blocks) blocks } #' @export #' @rdname parse_package parse_file <- function(file, env = env_file(file), srcref_path = NULL) { blocks <- tokenize_file(file, srcref_path = srcref_path) if (!is.null(env)) { blocks <- lapply(blocks, block_set_env, env = env) } blocks <- order_blocks(blocks) blocks } #' @export #' @rdname parse_package parse_text <- function(text, env = env_file(file)) { file <- tempfile() write_lines(text, file) on.exit(unlink(file)) blocks <- parse_file(file, env = env, srcref_path = "") blocks } #' @export #' @rdname parse_package env_file <- function(file) { env <- new.env(parent = parent.env(globalenv())) methods::setPackageName("roxygen_devtest", env) sys.source(file, envir = env) env } #' @export #' @rdname parse_package env_package <- function(path) { load_pkgload(path) } # helpers ----------------------------------------------------------------- order_blocks <- function(blocks) { block_order <- function(x) { if (block_has_tags(x, "order")) { ord <- block_get_tag_value(x, "order") as.double(ord) } else { Inf } } ord <- vapply(blocks, block_order, double(1)) blocks[order(ord)] } #' @export roxy_tag_parse.roxy_tag_order <- function(x) { tag_value(x) } roxygen2/R/zzz.R0000644000176200001440000000011213540202201013167 0ustar liggesusers.onLoad <- function(...) { as_character_rd <<- make_as_character_rd() } roxygen2/R/tag.R0000644000176200001440000000416713545454521013146 0ustar liggesusers#' `roxy_tag` S3 constructor #' #' `roxy_tag()` is the constructor for tag objects. #' `roxy_tag_warning()` generates a warning that gives the location of the tag. #' #' @section Methods: #' Define a method for `roxy_tag_parse` to support new tags. See [tag_parsers] #' for more details. #' #' @keywords internal #' @export #' @param tag Tag name. Arguments starting with `.` are reserved for internal #' usage. #' @param raw Raw tag value, a string. #' @param val Parsed tag value, typically a character vector, but sometimes #' a list. Usually filled in by `tag_parsers` #' @param file,line Location of the tag roxy_tag <- function(tag, raw, val = NULL, file = NA_character_, line = NA_integer_) { structure( list( file = file, line = line, raw = raw, tag = tag, val = val ), class = c(paste0("roxy_tag_", tag), "roxy_tag") ) } #' @rdname roxy_tag #' @param x A tag #' @export roxy_tag_parse <- function(x) { UseMethod("roxy_tag_parse") } #' @export roxy_tag_parse.default <- function(x) { roxy_tag_warning(x, "unknown tag") } is.roxy_tag <- function(x) inherits(x, "roxy_tag") #' @export format.roxy_tag <- function(x, ..., file = NULL) { if (identical(x$file, file)) { file <- "line" } else if (is.na(x$file)) { file <- "????" } else { file <- basename(x$file) } line <- if (is.na(x$line)) "???" else format(x$line, width = 3) loc <- paste0("[", file, ":", line, "]") if (!is.null(x$raw)) { lines <- strsplit(x$raw, "\n")[[1]] ellipsis <- FALSE if (length(lines) > 1) { raw <- lines[[1]] ellipsis <- TRUE } else { raw <- x$raw } if (nchar(raw) > 50) { raw <- substr(raw, 1, 47) ellipsis <- TRUE } raw <- paste0(raw, if (ellipsis) "...") } else { raw <- "" } parsed <- if (is.null(x$val)) "{unparsed}" else "{parsed}" paste0(loc, " @", x$tag, " '", raw, "' ", parsed) } #' @export print.roxy_tag <- function(x, ...) { cat_line(format(x, ...)) } #' @export #' @rdname roxy_tag roxy_tag_warning <- function(x, ...) { roxy_warning(file = x$file, line = x$line, "@", x$tag, " ", ...) } roxygen2/R/util-locale.R0000644000176200001440000000050413675432130014570 0ustar liggesusersset_collate <- function(locale) { cur <- Sys.getlocale(category = "LC_COLLATE") Sys.setlocale(category = "LC_COLLATE", locale = locale) cur } with_collate <- function(locale, code) { old <- set_collate(locale) on.exit(set_collate(old)) force(code) } sort_c <- function(x, ...) with_collate("C", sort(x, ...)) roxygen2/R/roclet.R0000644000176200001440000000670214115747053013657 0ustar liggesusers#' Build a new roclet. #' #' To create a new roclet, you will need to create a constructor function #' that wraps `roclet`, and then implement the methods described below. #' #' @section Methods: #' #' * `roclet_preprocess()` is called after blocks have been parsed but before #' code has been evaluated. This should only be needed if your roclet affects #' how code will evaluated. Should return a roclet. #' #' * `roclet_process()` called after blocks have been evaluated; i.e. the #' `@eval` tag has been processed, and the object associated with each block #' has been determined. #' #' * `roclet_output()` is given the output from `roclet_process()` and should #' produce files on disk. #' #' * `roclet_clean()` called when `roxygenise(clean = TRUE)`. Should remove #' any files created by the roclet. #' #' ### Deprecated methods #' #' `roclet_tags()` is no longer used; instead provide a [roxy_tag_parse()] #' method for each tag. #' #' @param x A `roclet` object. #' @param blocks A list of [roxy_block] objects. #' @param results Value returned from your `roclet_process()` method. #' @param base_path Path to root of source package. #' @param env Package environment. #' @keywords internal #' @name roclet NULL #' @export #' @rdname roclet roclet <- function(subclass, ...) { structure(list(...), class = c(paste0("roclet_", subclass), "roclet")) } #' @export #' @rdname roclet roclet_preprocess <- function(x, blocks, base_path) { UseMethod("roclet_preprocess") } #' @export roclet_preprocess.default <- function(x, blocks, base_path) { x } #' @export #' @rdname roclet roclet_process <- function(x, blocks, env, base_path) { UseMethod("roclet_process") } #' @export #' @rdname roclet roclet_output <- function(x, results, base_path, ...) { UseMethod("roclet_output", x) } #' @export #' @rdname roclet roclet_clean <- function(x, base_path) { UseMethod("roclet_clean") } #' @export #' @rdname roclet roclet_tags <- function(x) { UseMethod("roclet_tags") } #' Create a roclet from a string. #' #' This provides a flexible way of specifying a roclet in a string. #' #' @param x Arbitrary R code evaluated in roxygen2 package. #' @export #' @examples #' # rd, namespace, and vignette work for backward compatibility #' roclet_find("rd") #' #' # But generally you should specify the name of a function that #' # returns a roclet #' roclet_find("rd_roclet") #' #' # If it lives in another package, you'll need to use :: #' roclet_find("roxygen2::rd_roclet") #' #' # If it takes parameters (which no roclet does currently), you'll need #' # to call the function #' roclet_find("roxygen2::rd_roclet()") roclet_find <- function(x) { env <- new.env(parent = getNamespace("roxygen2")) env$rd <- rd_roclet env$namespace <- namespace_roclet env$vignette <- vignette_roclet expr <- parse(text = x) res <- eval(expr, env) if (is.function(res)) { res <- res() } if (!is.roclet(res)) { stop("Must return a roclet", call. = FALSE) } res } is.roclet <- function(x) inherits(x, "roclet") #' Process roclet on string and capture results. #' #' Useful for testing. #' #' @param roclet Name of roclet to use for processing. #' @param input Source string #' @export #' @keywords internal roc_proc_text <- function(roclet, input) { stopifnot(is.roclet(roclet)) file <- tempfile() write_lines(input, file) on.exit(unlink(file)) env <- env_file(file) blocks <- parse_text(input, env = env) roclet_process(roclet, blocks, env = env, base_path = ".") } roxygen2/R/object-defaults.R0000644000176200001440000000473713544733102015443 0ustar liggesusersobject_defaults <- function(x) UseMethod("object_defaults") #' @export object_defaults.default <- function(x) list() #' @exportS3Method object_defaults "function" object_defaults.function <- function(x) { list( roxy_tag("usage", NULL, object_usage(x)), # Used in process_inherit_params() roxy_tag(".formals", NULL, names(formals(x$value))) ) } #' @export object_defaults.s3generic <- object_defaults.function #' @export object_defaults.s3method <- object_defaults.function #' @export object_defaults.s4generic <- object_defaults.function #' @export object_defaults.s4method <- object_defaults.function #' @export object_defaults.data <- function(x) { str_out <- rd(object_format(x$value)) list( roxy_tag("docType", NULL, "data"), roxy_tag("format", NULL, str_out), roxy_tag("keywords", NULL, "datasets"), roxy_tag("usage", NULL, object_usage(x)) ) } #' @export object_defaults.package <- function(x) { desc <- x$value$desc description <- as.character(desc$Description) logo_path <- file.path(x$value$path, "man", "figures", "logo.png") if (file.exists(logo_path)) { fig <- "\\if{html}{\\figure{logo.png}{options: align='right' alt='logo' width='120'}}" description <- paste0(fig, "\n\n", description) } list( roxy_tag("docType", NULL, "package"), roxy_tag("name", NULL, package_suffix(desc$Package)), # "NULL" prevents addition of default aliases, see also #202 roxy_tag("aliases", NULL, paste("NULL", desc$Package, package_suffix(desc$Package))), roxy_tag("title", NULL, paste0(desc$Package, ": ", desc$Title)), roxy_tag("description", NULL, description), roxy_tag("seealso", NULL, package_seealso(desc)), roxy_tag("author", NULL, package_authors(desc)) ) } #' @export object_defaults.import <- function(x) { list( roxy_tag("docType", NULL, "import"), roxy_tag("name", NULL, "reexports"), roxy_tag("keywords", NULL, "internal"), roxy_tag("title", NULL, "Objects exported from other packages"), roxy_tag(".reexport", NULL, list(pkg = x$value$pkg, fun = x$value$fun)) ) } #' @export object_defaults.s4class <- function(x) { list( roxy_tag("docType", NULL, "class") ) } #' @export object_defaults.rcclass <- function(x) { list( roxy_tag("docType", NULL, "class"), if (!is.null(x$methods)) roxy_tag(".methods", NULL, x$methods) ) } # Helpers ----------------------------------------------------------------- package_suffix <- function(name) { paste0(name, "-package") } roxygen2/R/rd-family.R0000644000176200001440000000334113560327270014245 0ustar liggesusers#' @export roxy_tag_parse.roxy_tag_family <- function(x) tag_markdown(x) #' @export roxy_tag_rd.roxy_tag_family <- function(x, base_path, env) { rd_section(x$tag, x$val) } #' @export format.rd_section_family <- function(x, ...) { NULL } # ------------------------------------------------------------------------- topics_process_family_prefix <- function(family) { default <- paste0("Other ", family, ": ") # check for meta (use default prefix when unset) meta <- roxy_meta_get("rd_family_title") if (is.null(meta)) return(default) # validate meta structure valid <- is.character(meta) || is.list(meta) if (!valid) { message <- "rd_family_title is set, but is not a named list / vector" abort(message) } # extract element prefix <- meta[[family]] if (is.null(prefix)) return(default) prefix } topics_process_family <- function(topics, env) { family_index <- invert(topics$simple_values("family")) aliases <- topics$simple_values("alias") for (topic_name in names(topics$topics)) { topic <- topics$get(topic_name) families <- topic$get_value("family") for (family in families) { related <- family_index[[family]] topic$add(rd_section("concept", family)) others <- setdiff(related, topic_name) if (length(others) < 1) next by_file <- map_chr(aliases[others], function(x) { obj <- find_object(x[1], env) suffix <- if (is.function(obj$value)) "()" else "" paste0("\\code{\\link{", escape(x[1]), "}", suffix, "}") }) links <- paste(sort_c(by_file), collapse = ",\n") seealso <- topics_process_family_prefix(family) topic$add(rd_section("seealso", paste0(seealso, "\n", links))) } } invisible() } roxygen2/R/tokenize.R0000644000176200001440000000275514115747135014224 0ustar liggesusers# Returns list of roxy_blocks tokenize_file <- function(file, srcref_path = NULL) { lines <- read_lines(file) parsed <- parse( text = lines, keep.source = TRUE, srcfile = srcfilecopy(srcref_path %||% file, lines, isFile = TRUE) ) if (length(parsed) == 0) return(list()) refs <- utils::getSrcref(parsed) comment_refs <- comments(refs) tokens <- lapply(comment_refs, tokenise_ref) has_tokens <- !purrr::map_lgl(tokens, purrr::is_empty) blocks <- purrr::pmap( list( call = as.list(parsed)[has_tokens], srcref = refs[has_tokens], tokens = tokens[has_tokens] ), block_create ) purrr::compact(blocks) } tokenise_ref <- function(x) { tokenise_block( as.character(x), file = attr(x, "srcfile")$filename, offset = x[[1]] ) } # For each src ref, find the comment block preceding it comments <- function(refs) { srcfile <- attr(refs[[1]], "srcfile") # first_line, first_byte, last_line, last_byte com <- vector("list", length(refs)) for (i in seq_along(refs)) { # Comments begin after last line of last block, and this block is included # so that it can be parsed for additional comments if (i == 1) { first_byte <- 1 first_line <- 1 } else { first_byte <- refs[[i - 1]][4] + 1 first_line <- refs[[i - 1]][3] } last_line <- refs[[i]][3] last_byte <- refs[[i]][4] lloc <- c(first_line, first_byte, last_line, last_byte) com[[i]] <- srcref(srcfile, lloc) } com } roxygen2/R/markdown-link.R0000644000176200001440000001447213675431774015161 0ustar liggesusers#' Add link reference definitions for functions to a markdown text. #' #' We find the `[text][ref]` and the `[ref]` forms. There must be no #' spaces between the closing and opening bracket in the `[text][ref]` #' form. #' #' Starting from R 4.0.2-ish, explicit cross-package links to topics are not #' allowed, so for each such linked topic, we look up the linked file. #' #' These are the link references we add: #' ``` #' MARKDOWN LINK TEXT CODE RD #' -------- --------- ---- -- #' [fun()] fun() T \\link[=fun]{fun()} #' [obj] obj F \\link{obj} #' [pkg::fun()] pkg::fun() T \\link[pkg:file]{pkg::fun()} #' [pkg::obj] pkg::obj F \\link[pkg:file]{pkg::obj} #' [text][fun()] text F \\link[=fun]{text} #' [text][obj] text F \\link[=obj]{text} #' [text][pkg::fun()] text F \\link[pkg:file]{text} #' [text][pkg::obj] text F \\link[pkg:file]{text} #' [s4-class] s4 F \\linkS4class{s4} #' [pkg::s4-class] pkg::s4 F \\link[pkg:file]{pkg::s4} #' ``` #' #' The reference links will always look like `R:ref` for `[ref]` and #' `[text][ref]`. These are explicitly tested in `test-rd-markdown-links.R`. #' #' We add in a special `R:` marker to the URL. This way we don't #' pick up other links, that were specified via `` or #' `[text](link)`. In the parsed XML tree these look the same as #' our `[link]` and `[text][link]` links. #' #' In the link references, we need to URL encode the reference, #' otherwise commonmark does not use it (see issue #518). #' #' @param text Input markdown text. #' @return The input text and all dummy reference link definitions #' appended. #' #' @noRd #' @importFrom utils URLencode URLdecode get_md_linkrefs <- function(text) { refs <- str_match_all( text, regex( comments = TRUE, " (?<=[^\\]\\\\]|^) # must not be preceded by ] or \ \\[([^\\]\\[]+)\\] # match anything inside of [] (?:\\[([^\\]\\[]+)\\])? # match optional second pair of [] (?=[^\\[{]|$) # must not be followed by [ or { " ) )[[1]] if (length(refs) == 0) { return(character()) } ## For the [fun] form the link text is the same as the destination. # Need to check both NA and "" for different versions of stringr refs[, 3] <- ifelse(is.na(refs[,3]) | refs[,3] == "", refs[, 2], refs[,3]) refs3encoded <- map_chr(refs[,3], URLencode) paste0("[", refs[, 3], "]: ", "R:", refs3encoded) } add_linkrefs_to_md <- function(text) { ref_lines <- get_md_linkrefs(text) if (length(ref_lines) == 0) return(text) ref_text <- paste0(ref_lines, collapse = "\n") paste0(text, "\n\n", ref_text, "\n") } #' Parse a MarkDown link, to see if we should create an Rd link #' #' See the table above. #' #' @param destination string constant, the "url" of the link #' @param contents An XML node, containing the contents of the link. #' #' @noRd #' @importFrom xml2 xml_name parse_link <- function(destination, contents, state) { ## Not a [] or [][] type link, remove prefix if it is if (! grepl("^R:", destination)) return(NULL) destination <- sub("^R:", "", URLdecode(destination)) ## if contents is a `code tag`, then we need to move this outside is_code <- FALSE if (length(contents) == 1 && xml_name(contents) == "code") { is_code <- TRUE contents <- xml_contents(contents) destination <- sub("`$", "", sub("^`", "", destination)) } ## If the supplied link text is the same as the reference text, ## then we assume that the link text was automatically generated and ## it was not specified explicitly. In this case `()` links are ## turned to `\\code{}`. ## We also assume link text if we see a non-text XML tag in contents. has_link_text <- paste(xml_text(contents), collapse = "") != destination || any(xml_name(contents) != "text") ## if (is_code) then we'll need \\code ## `pkg` is package or NA ## `fun` is fun() or obj (fun is with parens) ## `is_fun` is TRUE for fun(), FALSE for obj ## `obj` is fun or obj (fun is without parens) ## `s4` is TRUE if we link to an S4 class (i.e. have -class suffix) ## `noclass` is fun with -class removed ## `file` is the file name of the linked topic. thispkg <- roxy_meta_get("current_package") %||% "" is_code <- is_code || (grepl("[(][)]$", destination) && ! has_link_text) pkg <- str_match(destination, "^(.*)::")[1,2] pkg <- gsub("%", "\\\\%", pkg) if (!is.na(pkg) && pkg == thispkg) pkg <- NA_character_ fun <- utils::tail(strsplit(destination, "::", fixed = TRUE)[[1]], 1) fun <- gsub("%", "\\\\%", fun) is_fun <- grepl("[(][)]$", fun) obj <- sub("[(][)]$", "", fun) s4 <- str_detect(destination, "-class$") noclass <- str_match(fun, "^(.*)-class$")[1,2] file <- find_topic_filename(pkg, obj, state$tag) ## To understand this, look at the RD column of the table above if (!has_link_text) { paste0( if (is_code) "\\code{", if (s4 && is.na(pkg)) "\\linkS4class" else "\\link", if (is_fun || ! is.na(pkg)) "[", if (is_fun && is.na(pkg)) "=", if (! is.na(pkg)) paste0(pkg, ":"), if (is_fun || ! is.na(pkg)) paste0(if (is.na(pkg)) obj else file, "]"), "{", if (!is.na(pkg)) paste0(pkg, "::"), if (s4) noclass else fun, "}", if (is_code) "}" else "" ) } else { contents <- mdxml_link_text(contents, state) list( paste0( if (is_code) "\\code{", "\\link[", if (is.na(pkg)) "=" else paste0(pkg, ":"), if (is.na(pkg)) obj else file, "]{" ), contents, "}", if (is_code) "}" else "" ) } } #' Dummy page to test roxygen's markdown formatting #' #' Links are very tricky, so I'll put in some links here: #' Link to a function: [roxygenize()]. #' Link to an object: [roxygenize] (we just treat it like an object here. #' #' Link to another package, function: [devtools::document()]. #' Link to another package, non-function: [devtools::document]. #' #' Link with link text: [this great function][roxygenize()], #' [`roxygenize`][roxygenize()], or [that great function][roxygenize]. #' #' In another package: [and this one][devtools::document]. #' #' This is a table: #' #' | __foo__ | __bar__ | #' | :-- | --: | #' | 1 | 2 | #' | 100 | 200 | #' #' @name markdown-test #' @keywords internal NULL roxygen2/R/topo-sort.R0000644000176200001440000000252013540202201014305 0ustar liggesusersTopoSort <- R6::R6Class("TopoSort", public = list( vertices = list(), add = function(name) { if (is.null(self$vertices[[name]])) { self$vertices[[name]] <- Vertex$new(name) } invisible(self$vertices[[name]]) }, add_ancestor = function(predecessor_name, ancestor_name) { predecessor <- self$add(predecessor_name) ancestor <- self$add(ancestor_name) predecessor$add_ancestor(ancestor) }, sort = function() { sorted <- list() visit <- function(predecessor) { predecessor$discovered <- TRUE for (ancestor in predecessor$ancestors) { if (!ancestor$discovered) { visit(ancestor) } } sorted <<- append(sorted, predecessor) } for (vertex in self$vertices) { if (!vertex$discovered) { visit(vertex) } } map_chr(sorted, "name") } )) Vertex <- R6::R6Class("Vertex", public = list( name = NA_character_, discovered = FALSE, ancestors = list(), initialize = function(name) { self$name <- name }, has_ancestor = function(ancestor) { for (vertex in self$ancestors) { if (identical(ancestor, vertex)) { return(TRUE) } } FALSE }, add_ancestor = function(ancestor) { if (!self$has_ancestor(ancestor)) { self$ancestors <- append(ancestor, self$ancestors) } } )) roxygen2/R/rd-name-alias.R0000644000176200001440000000170313544473137015001 0ustar liggesusers#' @export roxy_tag_parse.roxy_tag_aliases <- function(x) tag_value(x) #' @export format.rd_section_alias <- function(x, ...) { x$value <- str_replace_all(x$value, fixed("%"), "\\%") format_rd(x, ..., sort = FALSE) } #' @export roxy_tag_parse.roxy_tag_name <- function(x) tag_value(x) #' @export format.rd_section_name <- function(x, ...) { x$value <- str_replace_all(x$value, fixed("%"), "\\%") format_first(x, ...) } topic_add_name_aliases <- function(topic, block, name) { tags <- block_get_tags(block, "aliases") if (length(tags) == 0) { aliases <- character() } else { vals <- map_chr(tags, "val") aliases <- unlist(str_split(vals, "\\s+")) } if (any(aliases == "NULL")) { # Don't add default aliases aliases <- setdiff(aliases, "NULL") } else { aliases <- c(name, block$object$alias, aliases) } aliases <- unique(aliases) topic$add(rd_section("name", name)) topic$add(rd_section("alias", aliases)) } roxygen2/R/markdown-state.R0000644000176200001440000000167013544713471015330 0ustar liggesusers#' @export roxy_tag_parse.roxy_tag_md <- function(x) tag_toggle(x) #' @export roxy_tag_parse.roxy_tag_noMd <- function(x) tag_toggle(x) ## Hacky global switch - this uses the fact that blocks are parsed ## one after the another, and that we set markdown on/off before each ## block markdown_env <- new.env(parent = emptyenv()) markdown_on <- function(value = NULL) { if (!is.null(value)) { assign("markdown-support", isTRUE(value), envir = markdown_env) } return(isTRUE(markdown_env$`markdown-support`)) } markdown_activate <- function(tags) { ## markdown on/off based on global flag and presence of @md & @nomd names <- purrr::map_chr(tags, "tag") has_md <- "md" %in% names has_nomd <- "noMd" %in% names if (has_md && has_nomd) { roxy_tag_warning(tags[[1]], "Both @md and @noMd, no markdown parsing") } md <- roxy_meta_get("markdown", FALSE) if (has_md) md <- TRUE if (has_nomd) md <- FALSE markdown_on(md) } roxygen2/R/topics.R0000644000176200001440000000433513544473137013674 0ustar liggesusers# Manage a list of topics, indexed by file name. # Adding a topic with an existing file name merges it with the existing topic RoxyTopics <- R6::R6Class("RoxyTopics", public = list( topics = list(), add = function(topic) { if (is.null(topic)) return() stopifnot(inherits(topic, "RoxyTopic")) filename <- topic$filename if (filename %in% names(self$topics)) { self$topics[[filename]]$add(topic) } else { self$topics[[filename]] <- topic } invisible() }, # Drop any topics that don't have a title drop_invalid = function() { for (topic in names(self$topics)) { if (!self$topics[[topic]]$is_valid()) { warning(topic, " is missing name/title. Skipping", call. = FALSE) self$topics[[topic]] <- NULL } } invisible() }, get = function(filename) { self$topics[[filename]] }, # Given a topic name, find its file name. find_filename = function(name) { for (i in seq_along(self$topics)) { if (name %in% self$topics[[i]]$get_value("name")) { return(names(self$topics)[[i]]) } } NA_character_ }, # Topologically sort the topics. # # @param deps A function. Is passed RoxyTopic, and should return a character # vector of topic names topo_order = function(dependencies) { topo <- TopoSort$new() for (i in seq_along(self$topics)) { name <- names(self$topics)[[i]] topo$add(name) dep_topics <- dependencies(self$topics[[i]]) for (dep_topic in dep_topics) { dep_rd <- self$find_filename(dep_topic) if (!is.na(dep_rd)) topo$add_ancestor(name, dep_rd) } } topo$sort() }, # Call fun in topological order defined by dep. topo_apply = function(dep, fun, ...) { topics_topo <- self$topo_order(dep) for (topic_name in topics_topo) { topic <- self$get(topic_name) fun(topic, self, ...) } invisible() }, apply = function(fun, ...) { for (topic in self$topics) { fun(topic, self, ...) } invisible() }, # Extract values for simple fields simple_values = function(field) { fields <- lapply(self$topics, function(rd) rd$get_section(field)) lapply(compact(fields), "[[", "value") } )) roxygen2/R/object-from-call.R0000644000176200001440000002037113631761325015505 0ustar liggesusersobject_from_call <- function(call, env, block, file) { if (is.character(call)) { if (identical(call, "_PACKAGE")) { parser_package(call, env, block, file) } else { parser_data(call, env, file) } } else if (is.call(call)) { call <- call_standardise(call, env) name <- deparse(call[[1]]) switch(name, "=" = , "<-" = , "<<-" = parser_assignment(call, env, block), "delayedAssign" = parser_delayedAssign(call, env, block), "::" = parser_import(call, env, block), "methods::setClass" = , "setClass" = parser_setClass(call, env, block), "methods::setClassUnion" = , "setClassUnion" = parser_setClassUnion(call, env, block), "methods::setRefClass" = , "setRefClass" = parser_setRefClass(call, env, block), "methods::setGeneric" = , "setGeneric" = parser_setGeneric(call, env, block), "methods::setMethod" = , "setMethod" = parser_setMethod(call, env, block), "methods::setReplaceMethod" = , "setReplaceMethod" = parser_setReplaceMethod(call, env, block), "R.methodsS3::setMethodS3" = , "setMethodS3" = parser_setMethodS3(call, env, block), "R.oo::setConstructorS3" = , "setConstructorS3" = parser_setConstructorS3(call, env, block), NULL ) } else { NULL } } object_from_name <- function(name, env, block) { value <- get(name, env) if (inherits(value, "R6ClassGenerator")) { type <- "r6class" } else if (methods::is(value, "refObjectGenerator")) { value <- methods::getClass(as.character(value@className), where = env) type <- "rcclass" } else if (methods::is(value, "classGeneratorFunction")) { value <- methods::getClass(as.character(value@className), where = env) type <- "s4class" } else if (methods::is(value, "MethodDefinition")) { # S4 methods need munging to get real function def value@.Data <- extract_method_fun(value@.Data) type <- "s4method" } else if (methods::is(value, "standardGeneric")) { type <- "s4generic" } else if (is.function(value)) { # Potential S3 methods/generics need metadata added method <- block_get_tag_value(block, "method") value <- add_s3_metadata(value, name, env, method) if (inherits(value, "s3generic")) { type <- "s3generic" } else if (inherits(value, "s3method")) { type <- "s3method" } else { type <- "function" } } else { type <- "data" } object(value, name, type) } # Parsers for individual calls -------------------------------------------- parser_data <- function(call, env, block) { if (isNamespace(env)) { value <- getExportedValue(call, ns = asNamespace(env)) } else { value <- get(call, envir = env) } object(value, call, type = "data") } parser_package <- function(call, env, block, file) { pkg_path <- dirname(dirname(file)) desc <- read.description(file.path(pkg_path, "DESCRIPTION")) value <- list( desc = desc, path = pkg_path ) object(value, call, type = "package") } parser_assignment <- function(call, env, block) { name <- as.character(call[[2]]) # If it's a compound assignment like x[[2]] <- ignore it if (length(name) > 1) { return() } # If it doesn't exist (any more), don't document it. if (!exists(name, env)) { return() } object_from_name(name, env, block) } parser_delayedAssign <- function(call, env, block) { name <- as.character(call$x) object_from_name(name, env, block) } parser_setClass <- function(call, env, block) { name <- as.character(call$Class) value <- methods::getClass(name, where = env) object(value, NULL, "s4class") } parser_setClassUnion <- function(call, env, block) { name <- as.character(call$name) value <- methods::getClass(name, where = env) object(value, NULL, "s4class") } parser_setRefClass <- function(call, env, block) { name <- as.character(call$Class) value <- methods::getClass(name, where = env) object(value, NULL, "rcclass") } parser_setGeneric <- function(call, env, block) { name <- as.character(call$name) value <- methods::getGeneric(name, where = env) object(value, NULL, "s4generic") } parser_setMethod <- function(call, env, block) { name <- as.character(call$f) value <- methods::getMethod(name, eval(call$signature), where = env) value@.Data <- extract_method_fun(value@.Data) object(value, NULL, "s4method") } parser_setReplaceMethod <- function(call, env, block) { name <- paste0(as.character(call$f), "<-") value <- methods::getMethod(name, eval(call[[3]]), where = env) value@.Data <- extract_method_fun(value@.Data) object(value, NULL, "s4method") } parser_import <- function(call, env, block) { pkg <- as.character(call[[2]]) fun <- as.character(call[[3]]) object(list(pkg = pkg, fun = fun), alias = fun, type = "import") } parser_setMethodS3 <- function(call, env, block) { # R.methodsS3::setMethodS3(name, class, ...) method <- as.character(call[[2]]) class <- as.character(call[[3]]) name <- paste(method, class, sep = ".") method <- block_get_tag_value(block, "method") value <- add_s3_metadata(get(name, env), name, env, method) object(value, name, "s3method") } parser_setConstructorS3 <- function(call, env, block) { # R.oo::setConstructorS3(name, ...) name <- as.character(call[[2]]) object(get(name, env), name, "function") } # helpers ----------------------------------------------------------------- # @param override Either NULL to use default, or a character vector of length 2 add_s3_metadata <- function(val, name, env, override = NULL) { if (!is.null(override)) { return(s3_method(val, override)) } if (is_s3_generic(name, env)) { class(val) <- c("s3generic", "function") return(val) } method <- find_generic(name, env) if (is.null(method)) { val } else { s3_method(val, method) } } # When a generic has ... and a method adds new arguments, the S4 method # wraps the definition inside another function which has the same arguments # as the generic. This function figures out if that's the case, and extracts # the original function if so. # # It's based on expression processing based on the structure of the # constructed method which looks like: # # function (x, ...) { # .local <- function (x, ..., y = 7) {} # .local(x, ...) # } extract_method_fun <- function(fun) { method_body <- body(fun) if (!is_call(method_body, "{")) return(fun) if (length(method_body) < 2) return(fun) first_line <- method_body[[2]] if (!is_call(first_line, name = "<-", n = 2)) return(fun) if (!identical(first_line[[2]], quote(`.local`))) return(fun) local_fun <- eval(first_line[[3]]) if (!is.function(local_fun)) return(fun) local_fun } #' Constructors for S3 object to represent R objects. #' #' These objects are usually created by the parsers, but it is also #' useful to generate them by hand for testing. #' #' @param value The object itself. #' @param alias Alias for object being documented, in case you create a #' generator function with different name. #' @export #' @keywords internal object <- function(value, alias, type) { structure( list( alias = alias, value = value, methods = if (type == "rcclass") rc_methods(value), topic = object_topic(value, alias, type) ), class = c(type, "object") ) } #' @export format.object <- function(x, ...) { c( paste0("<", class(x)[1], "> ", x$name), paste0(" $topic ", x$topic), if (!is.null(x$alias)) paste0(" $alias ", x$alias) ) } #' @export print.object <- function(x, ...) { cat_line(format(x, ...)) } object_topic <- function(value, alias, type) { switch(type, s4method = paste0(value@generic, ",", paste0(value@defined, collapse = ","), "-method"), s4class = paste0(value@className, "-class"), s4generic = value@generic, rcclass = paste0(value@className, "-class"), r6class = alias, rcmethod = value@name, s3generic = alias, s3method = alias, import = alias, `function` = alias, package = alias, data = alias, stop("Unsupported type '", type, "'", call. = FALSE) ) } call_to_object <- function(code, env = pkg_env(), file = NULL) { code <- enexpr(code) eval(code, envir = env) if (is_call(code, "{")) { call <- code[[length(code)]] } else { call <- code } object_from_call(call, env, block = NULL, file = file) } roxygen2/R/rd-find-link-files.R0000644000176200001440000000545613675431774015764 0ustar liggesusers #' Find the Rd file of a topic #' #' @param pkg Package to search in, or `NA` if no package was specified. #' If the same as the dev package, then we treat it as `NA`. #' @param topic Topic to search for. This is the escaped, so it is `"\%\%"` and #' not `"%%"`. #' @param tag The roxy tag object that contains the link. We use this for #' better warnings, that include the file name and line number (of the tag). #' @return String. File name to link to. #' #' @details #' If `pkg` is `NA` or the package being documented, we'll just leave the #' topic alone. #' #' If `pkg` is not `NA` and not the package being documented (the _dev_ #' package), then we need to be able to find the Rd file. If we can't, that's #' a warning and the link is left untouched. This typically happens when the #' linked package is not installed or cannot be loaded. #' #' @noRd find_topic_filename <- function(pkg, topic, tag = NULL) { if (is.na(pkg) || identical(roxy_meta_get("current_package"), pkg)) { topic } else { try_find_topic_in_package(pkg, topic, tag = tag) } } #' Find a help topic in a package #' #' This is used by both `find_topic_filename()` and #' `format.rd_section_reexport()` that creates the re-exports page. The error #' messages are different for the two, so errors are not handled here. #' #' @param pkg Package name. This cannot be `NA`. #' @inheritParams find_topic_filename #' @return File name if the topic was found, `NA` if the package could be #' searched, but the topic was not found. Errors if the package cannot be #' searched. (Because it is not installed or cannot be loaded, etc.) #' #' @noRd find_topic_in_package <- function(pkg, topic) { # This is needed because we have the escaped text here, and parse_Rd will # un-escape it properly. on.exit(close(con), add = TRUE) con <- textConnection(topic) raw_topic <- str_trim(tools::parse_Rd(con)[[1]][1]) basename(utils::help((raw_topic), (pkg))[1]) } try_find_topic_in_package <- function(pkg, topic, where = "", tag = NULL) { path <- tryCatch( find_topic_in_package(pkg, topic), error = function(err) { msg <- paste0( "Link to unavailable package", where, ": ", pkg, "::", topic, ". ", err$message ) if (is.null(tag)) { roxy_warning(msg) } else { roxy_tag_warning(tag, msg) } topic } ) if (is.na(path)) { msg <- paste0("Link to unknown topic", where, ": ", pkg, "::", topic) if (is.null(tag)) { roxy_warning(msg) } else { roxy_tag_warning(tag, msg) } topic } else { path } } resolve_qualified_link <- function(topic) { if (has_colons(topic)) { target <- str_split_fixed(topic, "::", n = 2) file <- find_topic_in_package(target[1], target[2]) paste0(target[1], ":", file) } else { paste0("=", topic) } } roxygen2/R/rd-usage.R0000644000176200001440000001042714115750050014064 0ustar liggesusers#' @export roxy_tag_parse.roxy_tag_usage <- function(x) { x <- tag_value(x) x$val <- rd(x$val) x } #' @export roxy_tag_rd.roxy_tag_usage <- function(x, base_path, env) { if (identical(x$val, rd("NULL"))) { usage <- NULL } else { usage <- x$val } rd_section("usage", usage) } #' @export format.rd_section_usage <- function(x, ...) { rd_macro(x$type, build_rd(x$value, collapse = "\n\n"), space = TRUE) } # object_usage ------------------------------------------------------------ object_usage <- function(x) { UseMethod("object_usage") } object_usage.default <- function(x) { NULL } object_usage.data <- function(x) { rd(x$alias) } object_usage.function <- function(x) { function_usage(x$alias, formals(x$value), identity) } object_usage.s3generic <- object_usage.function object_usage.s3method <- function(x) { method <- attr(x$value, "s3method") s3method <- function(name) { paste0("\\method{", name, "}{", auto_backtick(method[2]), "}") } function_usage(method[1], formals(x$value), s3method) } object_usage.s4generic <- function(x) { function_usage(x$value@generic, formals(x$value), identity) } object_usage.s4method <- function(x) { s4method <- function(name) { classes <- auto_backtick(as.character(x$value@defined)) paste0("\\S4method{", name, "}{", paste0(classes, collapse = ","), "}") } function_usage(x$value@generic, formals(x$value), s4method) } # Function usage ---------------------------------------------------------- # Usage: # replacement, infix, regular # function, s3 method, s4 method, data function_usage <- function(name, formals, format_name = identity) { if (is_replacement_fun(name) && !is_infix_fun(name)) { name <- str_replace(name, fixed("<-"), "") if (identical(format_name, identity)) { name <- auto_backtick(name) } name <- gsub("%", "\\%", name, fixed = TRUE) formals$value <- NULL wrap_usage(name, format_name, formals, suffix = " <- value") } else if (is_infix_fun(name) && identical(format_name, identity)) { # If infix, and regular function, munge format arg_names <- names(formals) build_rd(arg_names[1], " ", format_name(name), " ", arg_names[2]) } else { if (identical(format_name, identity)) { name <- auto_backtick(name) } name <- gsub("%", "\\%", name, fixed = TRUE) wrap_usage(name, format_name, formals) } } is_replacement_fun <- function(name) { str_detect(name, fixed("<-")) } is_infix_fun <- function(name) { str_detect(name, "^%.*%$") } usage_args <- function(args) { is.missing.arg <- function(arg) { is.symbol(arg) && deparse(arg) == "" } arg_to_text <- function(arg) { if (is.missing.arg(arg)) return("") text <- enc2utf8(deparse(arg, backtick = TRUE, width.cutoff = 500L)) text <- paste0(text, collapse = "\n") Encoding(text) <- "UTF-8" text } map_chr(args, arg_to_text) } args_string <- function(x) { sep <- ifelse(x != "", "\u{A0}=\u{A0}", "") arg_names <- escape(auto_backtick(names(x))) paste0(arg_names, sep, escape(x)) } args_call <- function(call, args) { paste0(call, "(", paste0(args, collapse = ", "), ")") } #' @param name Function name #' @param format_name Single argument that returns formatted function name #' @param formals List of function formals #' @param suffix Optional suffix, used for replacement functions #' @noRd wrap_usage <- function(name, format_name, formals, suffix = NULL, width = 80L) { args <- args_string(usage_args(formals)) # Do we need any wrapping? bare <- args_call(name, args) if (nchar(bare, type = "width") < width) { out <- args_call(format_name(name), args) } else if (roxy_meta_get("old_usage", FALSE)) { x <- args_call(format_name(name), args) out <- wrapUsage(x, width = as.integer(width), indent = 2) } else { args <- paste0(" ", args) args <- map_chr(args, wrapUsage, width = 90, indent = 4) out <- paste0(format_name(name), "(\n", paste0(args, collapse = ",\n"), "\n)") } out <- gsub("\u{A0}", " ", out, useBytes = TRUE) Encoding(out) <- "UTF-8" rd(paste0(out, suffix)) } # helpers ----------------------------------------------------------------- # used for testing call_to_usage <- function(code, env = pkg_env()) { obj <- call_to_object(!!enexpr(code), env) gsub("\u{A0}", " ", as.character(object_usage(obj))) } roxygen2/R/safety.R0000644000176200001440000000412013540202201013630 0ustar liggesusersfirst_time <- function(path) { description <- file.path(path, "DESCRIPTION") if (!file.exists(description)) { stop( "`package.dir` must include a DESCRIPTION file:\n", " * \"", path, "\" does not.\n", "Did you call `roxygenize()` in a directory ", "that is not the package root?", call. = FALSE ) } generated <- dir(file.path(path, "man"), full.names = TRUE) generated <- generated[!file.info(generated)$isdir] namespace <- file.path(path, "NAMESPACE") if (file.exists(namespace)) { generated <- c(generated, namespace) } roxy <- map_lgl(generated, made_by_roxygen) all(!roxy) } made_by_roxygen <- function(path) { if (!file.exists(path)) return(TRUE) first <- read_lines(path, n = 1) check_made_by(first) } check_made_by <- function(first) { if (length(first) == 0L) return(FALSE) grepl("^. Generated by roxygen2", first) } made_by <- function(comment) { # This text is used by IDE to display a special warning. DO NOT CHANGE # without consulting the IDE team paste0(comment, " Generated by roxygen2: do not edit by hand\n") } update_roxygen_version <- function(base_path) { desc_path <- file.path(base_path, "DESCRIPTION") cur <- as.character(utils::packageVersion("roxygen2")) prev <- stringr::str_trim(desc::desc_get("RoxygenNote", file = desc_path)[[1]]) if (!is.na(cur) && !is.na(prev) && package_version(cur) < package_version(prev)) { warning("Version of roxygen2 last used with this package is ", prev, ". ", " You only have version ", cur, call. = FALSE, immediate. = TRUE) } else if (!identical(cur, prev)) { message("Updating roxygen version in ", desc_path) upgrade_7_0_0(cur) desc::desc_set(RoxygenNote = cur, file = desc_path) } } upgrade_7_0_0 <- function(cur_version) { if (numeric_version(cur_version) > "6.1.99") { return() } rule <- paste0(paste(rep("-", options('width')), collapse = "")) inform(c( rule, "Changes in roxygen2 7.0.0:", "* `%` is now escaped automatically in Markdown mode.", "Please carefully check .Rd files for changes", rule )) } roxygen2/R/rd-params.R0000644000176200001440000000442713544473137014263 0ustar liggesusers#' @export roxy_tag_parse.roxy_tag_param <- function(x) { tag_name_description(x) } #' @export roxy_tag_rd.roxy_tag_param <- function(x, base_path, env) { value <- setNames(x$val$description, x$val$name) rd_section(x$tag, value) } #' @export merge.rd_section_param <- function(x, y, ...) { stopifnot(identical(class(x), class(y))) # When parameters appear in both x and y, keep values from y # This happens for example when inherit_dot_params adds a "..." param after # inherit_params has done the same. to_add <- setdiff(names(x$value), names(y$value)) rd_section(x$type, c(x$value[to_add], y$value)) } #' @export format.rd_section_param <- function(x, ...) { names <- names(x$value) # add space to multiple arguments so they can wrap names <- gsub(",", ", ", names) items <- paste0("\\item{", names, "}{", x$value, "}", collapse = "\n\n") rd_macro("arguments", items, space = TRUE) } # Other helpers ----------------------------------------------------------- # Postprocessing to reset ordering of parameter documentation topics_fix_params_order <- function(topics) { for (topic in topics$topics) { # Compute correct ordering of parameter documentation # Check what's needed... needed <- topic$get_value("formals") # (Workaround for dupes that can occur but perhaps shouldn't, # cf. https://github.com/r-lib/roxygen2/commit/83d125dce50a072534988787d49ffe206d19b232#commitcomment-6742169) needed <- unique(needed) # ...and what's documented (here we look only at the first parameter # in a multi-parameter documentation) documented <- get_documented_params(topic, only_first = TRUE) # We operate on indexes to make sure that no documentation is lost during # the reordering documented_indexes <- seq_along(documented) # We compute the indexes in the current documentation in the required order # and append everything that's missing in the order found required_order <- match(needed, documented) required_order <- required_order[!is.na(required_order)] required_order <- c(required_order, setdiff(documented_indexes, required_order)) # Overwrite all param fields to fix order param <- topic$get_value("param")[required_order] topic$add(rd_section("param", param), overwrite = TRUE) } invisible() } roxygen2/R/rd-include-rmd.R0000644000176200001440000000375714115751164015202 0ustar liggesusers#' @export roxy_tag_parse.roxy_tag_includeRmd <- function(x) { if (!is_installed("rmarkdown")) { roxy_tag_warning(x, "Needs the rmarkdown package") return() } tag_two_part(x, "path", "section", required = FALSE, markdown = FALSE) } #' @export roxy_tag_rd.roxy_tag_includeRmd <- function(x, base_path, env) { rmd <- x$val$path section <- x$val$section if (section == "") section <- "details" stopifnot(is.character(rmd), length(rmd) == 1, !is.na(rmd)) rmd_path <- tempfile(fileext = ".Rmd") md_path <- tempfile(fileext = ".md") on.exit(unlink(c(rmd_path, md_path), recursive = TRUE), add = TRUE) wd <- getwd() setwd(base_path) on.exit(setwd(wd), add = TRUE) # This will create an absolute path rmd <- normalizePath(rmd) cache_path <- paste0(sub("\\.Rmd$", "", rmd), "_cache/") fig_path <- file.path(dirname(rmd), "figure/") linkrefs <- rmd_linkrefs_from_file(rmd) opts <- c( root.dir = dirname(rmd), cache.path = cache_path, fig.path = fig_path, child = rmd ) optss <- paste0(names(opts), "=", encodeString(opts, quote = '"')) txt <- sprintf( "```{r %s}\n```\n\n%s\n", paste(optss, collapse = ","), linkrefs ) cat(txt, file = rmd_path) rmarkdown::render( rmd_path, output_format = rmarkdown::github_document(), output_file = md_path, quiet = TRUE, envir = new_environment(parent = global_env()) ) value <- rmd_eval_rd(md_path, x) rd_section_markdown(section, value) } # Helpers ----------------------------------------------------------------- rmd_linkrefs_from_file <- function(path) { lines <- read_lines(path) txt <- paste(lines, collapse = "\n") paste(get_md_linkrefs(txt), collapse = "\n") } rmd_eval_rd <- function(path, tag) { mdtxt <- paste(read_lines(path), collapse = "\n") mdesc <- add_linkrefs_to_md(mdtxt) mdxml <- md_to_mdxml(mdesc) state <- new.env(parent = emptyenv()) state$tag <- tag state$has_sections <- TRUE rd <- mdxml_children_to_rd_top(mdxml, state = state) rd } roxygen2/R/options.R0000644000176200001440000000701113675431642014060 0ustar liggesusers#' Load roxygen2 options #' #' @description #' Options can be stored in the `Roxygen` field of the `DESCRIPTION`, or #' in `man/roxygen/meta.R`. In either case, the code is parsed and evaluated #' in a child of the base environment. Call `roxy_meta_get()` to access #' current option values from within tag and roclet methods. #' #' Options in `man/roxygen/meta.R` override those present in `DESCRIPTION`. #' #' @section Possible options: #' #' * `roclets` ``: giving names of roclets to run. See #' [roclet_find()] for details. #' #' * `packages` ``: packages to load that implement new tags. #' #' * `load` ``: how to load R code. See [load] for details. #' #' * `old_usage` ``: use old style usage formatting? #' #' * `markdown` ``: translate markdown syntax to Rd? #' #' * `r6` ``: document R6 classes? #' #' * `current_package` `` (read only): name of package being documented. #' #' * `rd_family_title` ``: overrides for `@family` titles. See the #' _rd_ vignette for details: `vignette("rd", package = "roxygen2")` #' #' @section How to set: #' Either set in `DESCRIPTION`: #' #' ``` #' Roxygen: list(markdown = TRUE, load = "installed") #' ``` #' #' Or if longer, you can put in `/man/roxygen/meta.R`: #' #' ``` #' list( #' markdown = TRUE, #' load = "installed" #' ) #' ``` #' #' @param base_path Path to package. #' @export #' @keywords internal load_options <- function(base_path = ".") { desc <- load_options_description(base_path) meta <- load_options_meta(base_path) opts <- utils::modifyList(desc, meta) defaults <- list( roclets = c("collate", "namespace", "rd"), packages = character(), load = "pkgload", old_usage = FALSE, markdown = FALSE, r6 = TRUE, current_package = NA_character_, rd_family_title = list() ) unknown_opts <- setdiff(names(opts), names(defaults)) if (length(unknown_opts) > 0) { warn(paste0( "Unknown Roxygen options ", paste(unknown_opts, collapse = ", "), ".\n", "Supported options: ", paste(names(defaults), collapse = ", ") )) } utils::modifyList(defaults, opts) } load_options_description <- function(base_path = ".") { desc_path <- file.path(base_path, "DESCRIPTION") dcf <- read.dcf(desc_path, fields = c("Roxygen", "Package")) desc_opts <- dcf[[1, 1]] if (is.na(desc_opts)) { opts <- list() } else { opts <- eval(parse(text = desc_opts), child_env(baseenv())) } opts$current_package <- dcf[[1, 2]] opts } load_options_meta <- function(base_path = ".", path = "man/roxygen/meta.R") { # Only look for .R for consistency with style advice meta_path <- file.path(base_path, path) if (!file.exists(meta_path)) { return(list()) } value <- tryCatch( source(meta_path, local = child_env(baseenv()))$value, error = function(err) { warn("Failed to source `man/roxygen/meta.R`") list() } ) if (!is.list(value)) { warn("`man/roxygen/meta.R` must yield a named list") return(list()) } value } # Global binding management ----------------------------------------------- roxy_meta <- new_environment() #' @export #' @rdname load_options roxy_meta_get <- function(key = NULL, default = NULL) { env_get(roxy_meta, key, default = default) } roxy_meta_set <- function(key, value = NULL) { env_poke(roxy_meta, key, value) } roxy_meta_clear <- function() { env_unbind(roxy_meta, env_names(roxy_meta)) } roxy_meta_load <- function(base_path = getwd()) { roxy_meta_clear() env_bind(roxy_meta, !!!load_options(base_path)) } roxygen2/R/field.R0000644000176200001440000000433113544473137013452 0ustar liggesusers#' Construct an `rd_section` object #' #' An `rd_section` represents an Rd command that can appear at the top-level #' of an Rd document, like `\name{}`, `\title{}`, `\description{}`, or #' `\section{}`. #' #' @section Methods: #' If provide your own `rd_section` type, you'll also need to define a #' `format.rd_section_{type}` method that returns formatted Rd output. You #' may also need to provide a `merge.rd_section_{type}` method if two #' sections can not be combined with `rd_section(x$type, c(x$value, y$value))`. #' See `vignette("extending")` for more details. #' #' @param type Section type. Stored in `type` field, and in class #' `rd_section_{type}`. To avoid namespace clashes between different #' extensions, this should include the package name. #' @param value Section data. Only used by `format()` and `merge()` methods. #' @export #' @keywords internal rd_section <- function(type, value) { if (is.null(value) || identical(value, "NULL")) { # NULL is special sentinel value that suppresses output of that field return() } structure( list( type = type, value = value ), class = c(paste0("rd_section_", type), "rd_section") ) } #' @export print.rd_section <- function(x, ...) { cat(format(x), "\n") } #' @export format.rd_section <- function(x, ...) { abort(paste0("`format.", class(x)[[1]], "` not found")) } #' @export merge.rd_section <- function(x, y, ...) { stopifnot(identical(class(x), class(y))) rd_section(x$type, c(x$value, y$value)) } format_rd <- function(x, ..., sort = TRUE) { # One rd macro for each value x$value <- unique(x$value) if (sort) { x$value <- sort_c(x$value) } map_chr(x$value, rd_macro, field = x$type) } format_first <- function(x, ...) { # Only use the first value rd_macro(x$type, x$value[1]) } format_collapse <- function(x, ..., indent = 0, exdent = 0) { # Collapse all into a single string value <- paste0(x$value, collapse = "\n\n") rd_macro(x$type, value, space = TRUE) } rd_section_description <- function(name, dt, dd) { if (length(dt) == 0) return("") items <- paste0("\\item{\\code{", dt, "}}{", dd, "}", collapse = "\n\n") paste0("\\section{", name, "}{\n\n", "\\describe{\n", items, "\n}}\n" ) } roxygen2/R/rd-s4.R0000644000176200001440000000127113544473137013320 0ustar liggesusers#' @export roxy_tag_parse.roxy_tag_field <- function(x) tag_name_description(x) #' @export roxy_tag_rd.roxy_tag_field <- function(x, base_path, env) { value <- setNames(x$val$description, x$val$name) rd_section(x$tag, value) } #' @export format.rd_section_field <- function(x, ...) { rd_section_description("Fields", names(x$value), x$value) } #' @export roxy_tag_parse.roxy_tag_slot <- function(x) tag_name_description(x) #' @export roxy_tag_rd.roxy_tag_slot <- function(x, base_path, env) { value <- setNames(x$val$description, x$val$name) rd_section(x$tag, value) } #' @export format.rd_section_slot <- function(x, ...) { rd_section_description("Slots", names(x$value), x$value) } roxygen2/R/namespace.R0000644000176200001440000001722113631761325014321 0ustar liggesusers#' Roclet: make `NAMESPACE` #' #' @description #' This roclet automates the production of a `NAMESPACE` file, which controls #' the functions imported and exported by your package, as described in #' [Writing R extensions](https://cran.r-project.org/doc/manuals/r-release/R-exts.html). #' #' The `NAMESPACE` is generated in two passes: the first generates only #' import directives (because this can be computed without evaluating package #' code), and the second generates everything (after the package has been #' loaded). #' #' See `vignette("namespace")` for details. #' #' @family roclets #' @export #' @examples #' # The most common namespace tag is @@export, which declares that a function #' # is part of the external interface of your package #' #' @export #' foofy <- function(x, y, z) { #' } #' #' # You'll also often find global imports living in a file called #' # R/{package}-package.R. #' #' @@importFrom magrittr %>% #' #' @@import rlang #' NULL namespace_roclet <- function() { roclet("namespace") } #' @export roclet_preprocess.roclet_namespace <- function(x, blocks, base_path) { lines <- blocks_to_ns(blocks, emptyenv(), import_only = TRUE) NAMESPACE <- file.path(base_path, "NAMESPACE") if (length(lines) == 0 && !made_by_roxygen(NAMESPACE)) { return(x) } results <- c(made_by("#"), lines) write_if_different(NAMESPACE, results, check = TRUE) invisible(x) } #' @export roclet_process.roclet_namespace <- function(x, blocks, env, base_path) { blocks_to_ns(blocks, env) } #' @export roclet_output.roclet_namespace <- function(x, results, base_path, ...) { NAMESPACE <- file.path(base_path, "NAMESPACE") results <- c(made_by("#"), results) # Always check for roxygen2 header before overwriting NAMESPACE (#436), # even when running for the first time write_if_different(NAMESPACE, results, check = TRUE) NAMESPACE } #' @export roclet_clean.roclet_namespace <- function(x, base_path) { NAMESPACE <- file.path(base_path, "NAMESPACE") if (made_by_roxygen(NAMESPACE)) { unlink(NAMESPACE) } } # NAMESPACE generation ---------------------------------------------------- blocks_to_ns <- function(blocks, env, import_only = FALSE) { lines <- map(blocks, block_to_ns, env = env, import_only = import_only) lines <- unlist(lines) %||% character() sort_c(unique(lines)) } block_to_ns <- function(block, env, import_only = FALSE) { map(block$tags, roxy_tag_ns, block = block, env = env, import_only = import_only) } # Namespace tag methods --------------------------------------------------- roxy_tag_ns <- function(x, block, env, import_only = FALSE) { UseMethod("roxy_tag_ns") } #' @export roxy_tag_ns.default <- function(x, block, env, import_only = FALSE) { } #' @export roxy_tag_parse.roxy_tag_evalNamespace <- function(x) { tag_code(x) } #' @export roxy_tag_ns.roxy_tag_evalNamespace <- function(x, block, env, import_only = FALSE) { if (import_only) { return() } roxy_tag_eval(x, env) } #' @export roxy_tag_parse.roxy_tag_export <- function(x) { tag_words_line(x) } #' @export roxy_tag_ns.roxy_tag_export <- function(x, block, env, import_only = FALSE) { if (import_only) { return() } if (identical(x$val, "")) { # FIXME: check for empty exports (i.e. no name) default_export(block$object, block) } else { export(x$val) } } #' @export roxy_tag_parse.roxy_tag_exportClass <- function(x) { tag_words(x, 1) } #' @export roxy_tag_ns.roxy_tag_exportClass <- function(x, block, env, import_only = FALSE) { if (import_only) { return() } export_class(x$val) } #' @export roxy_tag_parse.roxy_tag_exportMethod <- function(x) { tag_words(x, min = 1) } #' @export roxy_tag_ns.roxy_tag_exportMethod <- function(x, block, env, import_only = FALSE) { if (import_only) { return() } export_s4_method(x$val) } #' @export roxy_tag_parse.roxy_tag_exportPattern <- function(x) { tag_words(x, min = 1) } #' @export roxy_tag_ns.roxy_tag_exportPattern <- function(x, block, env, import_only = FALSE) { if (import_only) { return() } one_per_line("exportPattern", x$val) } #' @export roxy_tag_parse.roxy_tag_exportS3Method <- function(x) { tag_words(x, min = 0, max = 2) } #' @export roxy_tag_ns.roxy_tag_exportS3Method <- function(x, block, env, import_only = FALSE) { if (import_only) { return() } obj <- block$object if (length(x$val) < 2 && !inherits(obj, "s3method")) { roxy_tag_warning(x, "`@exportS3Method` and `@exportS3Method generic` must be used with an S3 method" ) return() } if (identical(x$val, "")) { method <- attr(obj$value, "s3method") } else if (length(x$val) == 1) { method <- c(x$val, attr(obj$value, "s3method")[[2]]) } else { method <- x$val } export_s3_method(method) } #' @export roxy_tag_parse.roxy_tag_import <- function(x) { tag_words(x, min = 1) } #' @export roxy_tag_ns.roxy_tag_import <- function(x, block, env, import_only = FALSE) { one_per_line("import", x$val) } #' @export roxy_tag_parse.roxy_tag_importClassesFrom <- function(x) { tag_words(x, min = 2) } #' @export roxy_tag_ns.roxy_tag_importClassesFrom <- function(x, block, env, import_only = FALSE) { repeat_first("importClassesFrom", x$val) } #' @export roxy_tag_parse.roxy_tag_importFrom <- function(x) { tag_words(x, min = 2) } #' @export roxy_tag_ns.roxy_tag_importFrom <- function(x, block, env, import_only = FALSE) { repeat_first("importFrom", x$val) } #' @export roxy_tag_parse.roxy_tag_importMethodsFrom <- function(x) { tag_words(x, min = 2) } #' @export roxy_tag_ns.roxy_tag_importMethodsFrom <- function(x, block, env, import_only = FALSE) { repeat_first("importMethodsFrom", x$val) } #' @export roxy_tag_parse.roxy_tag_rawNamespace <- function(x) { tag_code(x) } #' @export roxy_tag_ns.roxy_tag_rawNamespace <- function(x, block, env, import_only = FALSE) { x$val } #' @export roxy_tag_parse.roxy_tag_useDynLib <- function(x) { tag_words(x, min = 1) } #' @export roxy_tag_ns.roxy_tag_useDynLib <- function(x, block, env, import_only = FALSE) { if (length(x$val) == 1) { return(paste0("useDynLib(", auto_quote(x$val), ")")) } if (any(grepl(",", x$val))) { # If there's a comma in list, don't quote output. This makes it possible # for roxygen2 to support other NAMESPACE forms not otherwise mapped args <- paste0(x$val, collapse = " ") paste0("useDynLib(", args, ")") } else { repeat_first("useDynLib", x$val) } } # Default export methods -------------------------------------------------- default_export <- function(x, block) UseMethod("default_export") #' @export default_export.s4class <- function(x, block) export_class(x$value@className) #' @export default_export.s4generic <- function(x, block) export(x$value@generic) #' @export default_export.s4method <- function(x, block) export_s4_method(x$value@generic) #' @export default_export.s3method <- function(x, block) export_s3_method(auto_quote(attr(x$value, "s3method"))) #' @export default_export.rcclass <- function(x, block) export_class(x$value@className) #' @export default_export.default <- function(x, block) export(x$alias) #' @export default_export.NULL <- function(x, block) export(block_get_tag_value(block, "name")) # Helpers ----------------------------------------------------------------- export <- function(x) one_per_line("export", x) export_class <- function(x) one_per_line("exportClasses", x) export_s4_method <- function(x) one_per_line("exportMethods", x) export_s3_method <- function(x) { args <- paste0(x, collapse = ",") paste0("S3method(", args, ")") } one_per_line <- function(name, x) { paste0(name, "(", auto_quote(x), ")") } repeat_first <- function(name, x) { paste0(name, "(", auto_quote(x[1]), ",", auto_quote(x[-1]), ")") } roxygen2/R/roxygen.R0000644000176200001440000000111114047223751014045 0ustar liggesusers#' @details #' See `vignette("roxygen2", package = "roxygen2")` for an overview #' of the package, `vignette("rd", package = "roxygen2")` for generating #' documentation, and `vignette("namespace", package = "roxygen2")` for #' generating the namespace specification. #' #' If you have existing Rd files, check out the `Rd2roxygen` package #' for a convenient way of converting Rd files to roxygen comments. #' #' @useDynLib roxygen2, .registration=TRUE #' @keywords internal #' @importFrom R6 R6Class #' @importFrom purrr map map_int map_chr map_lgl map2 #' @import rlang "_PACKAGE" roxygen2/R/rd-section.R0000644000176200001440000000223613631762137014436 0ustar liggesusers#' @export roxy_tag_parse.roxy_tag_section <- function(x) { tag_markdown(x) } #' @export roxy_tag_rd.roxy_tag_section <- function(x, base_path, env) { pieces <- str_split(x$val, ":", n = 2)[[1]] title <- str_split(pieces[1], "\n")[[1]] if (length(title) > 1) { roxy_tag_warning(x, paste0( "Section title spans multiple lines.\n", "Did you forget a colon (:) at the end of the title?" )) return() } rd_section_section(pieces[1], pieces[2]) } rd_section_section <- function(title, content) { stopifnot(is.character(title), is.character(content)) stopifnot(length(title) == length(content)) rd_section("section", list(title = title, content = content)) } #' @export format.rd_section_section <- function(x, ...) { paste0( "\\section{", x$value$title, "}{\n", x$value$content, "\n}\n", collapse = "\n" ) } #' @export merge.rd_section_section <- function(x, y, ...) { stopifnot(identical(class(x), class(y))) dedup <- collapse( c(x$value$title, y$value$title), c(x$value$content, y$value$content), paste, collapse = "\n\n" ) rd_section("section", list(title = dedup$key, content = unlist(dedup$value))) } roxygen2/R/object-package.R0000644000176200001440000002220313631767006015222 0ustar liggesuserspackage_seealso <- function(desc) { if (!is.null(desc$URL)) { links <- paste0("\\url{", strsplit(desc$URL, ",\\s+")[[1]], "}") } else { links <- character() } if (!is.null(desc$BugReports)) { links <- c(links, paste0("Report bugs at \\url{", desc$BugReports, "}")) } itemize("Useful links:", links) } package_authors <- function(desc) { authors <- tryCatch(eval(parse(text = desc$`Authors@R` %||% "")), error = function(e) { warning(e) NULL } ) if (is.null(authors)) return() desc <- map_chr(unclass(authors), author_desc) type <- map_chr(unclass(authors), author_type) by_type <- split(desc, type) paste( c( paste0("\\strong{Maintainer}: ", by_type$cre[[1]], "\n"), itemize("Authors:", by_type$aut), itemize("Other contributors:", by_type$other) ), collapse = "\n" ) } author_desc <- function(x) { if (inherits(x, "person")) { stop("person class must be stripped", call. = FALSE) } desc <- paste0(x$given, collapse = " ") if (!is.null(x$family)) { desc <- paste0(desc, " ", paste0(x$family, collapse = " ")) } if (!is.null(x$email)) { desc <- paste0(desc, " \\email{", x$email, "}") } if (!is.null(x$comment)) { if (has_name(x$comment, "ORCID")) { orcid <- x$comment[["ORCID"]] if (grepl("https?://", orcid)) { desc <- paste0(desc, " (\\href{", orcid, "}{ORCID})") } else { desc <- paste0(desc, " (\\href{https://orcid.org/", orcid, "}{ORCID})") } x$comment <- x$comment[!names(x$comment) %in% "ORCID"] } if (length(x$comment) > 0) { desc <- paste0(desc, " (", x$comment, ")") } } extra_roles <- setdiff(x$role, c("cre", "aut")) if (length(extra_roles) > 0) { desc <- paste0( desc, " [", paste0(role_lookup[extra_roles], collapse = ", "), "]" ) } desc } author_type <- function(x) { if ("cre" %in% x$role) { "cre" } else if ("aut" %in% x$role) { "aut" } else { "other" } } role_lookup <- c( "abr" = "abridger", "act" = "actor", "adp" = "adapter", "rcp" = "addressee", "anl" = "analyst", "anm" = "animator", "ann" = "annotator", "apl" = "appellant", "ape" = "appellee", "app" = "applicant", "arc" = "architect", "arr" = "arranger", "acp" = "art copyist", "adi" = "art director", "art" = "artist", "ard" = "artistic director", "asg" = "assignee", "asn" = "associated name", "att" = "attributed name", "auc" = "auctioneer", "aut" = "author", "aqt" = "author in quotations or text abstracts", "aft" = "author of afterword, colophon, etc.", "aud" = "author of dialog", "aui" = "author of introduction, etc.", "ato" = "autographer", "ant" = "bibliographic antecedent", "bnd" = "binder", "bdd" = "binding designer", "blw" = "blurb writer", "bkd" = "book designer", "bkp" = "book producer", "bjd" = "bookjacket designer", "bpd" = "bookplate designer", "bsl" = "bookseller", "brl" = "braille embosser", "brd" = "broadcaster", "cll" = "calligrapher", "ctg" = "cartographer", "cas" = "caster", "cns" = "censor", "chr" = "choreographer", "cng" = "cinematographer", "cli" = "client", "cor" = "collection registrar", "col" = "collector", "clt" = "collotyper", "clr" = "colorist", "cmm" = "commentator", "cwt" = "commentator for written text", "com" = "compiler", "cpl" = "complainant", "cpt" = "complainant-appellant", "cpe" = "complainant-appellee", "cmp" = "composer", "cmt" = "compositor", "ccp" = "conceptor", "cnd" = "conductor", "con" = "conservator", "csl" = "consultant", "csp" = "consultant to a project", "cos" = "contestant", "cot" = "contestant-appellant", "coe" = "contestant-appellee", "cts" = "contestee", "ctt" = "contestee-appellant", "cte" = "contestee-appellee", "ctr" = "contractor", "ctb" = "contributor", "cpc" = "copyright claimant", "cph" = "copyright holder", "crr" = "corrector", "crp" = "correspondent", "cst" = "costume designer", "cou" = "court governed", "crt" = "court reporter", "cov" = "cover designer", "cre" = "creator", "cur" = "curator", "dnc" = "dancer", "dtc" = "data contributor", "dtm" = "data manager", "dte" = "dedicatee", "dto" = "dedicator", "dfd" = "defendant", "dft" = "defendant-appellant", "dfe" = "defendant-appellee", "dgg" = "degree granting institution", "dgs" = "degree supervisor", "dln" = "delineator", "dpc" = "depicted", "dpt" = "depositor", "dsr" = "designer", "drt" = "director", "dis" = "dissertant", "dbp" = "distribution place", "dst" = "distributor", "dnr" = "donor", "drm" = "draftsman", "dub" = "dubious author", "edt" = "editor", "edc" = "editor of compilation", "edm" = "editor of moving image work", "elg" = "electrician", "elt" = "electrotyper", "enj" = "enacting jurisdiction", "eng" = "engineer", "egr" = "engraver", "etr" = "etcher", "evp" = "event place", "exp" = "expert", "fac" = "facsimilist", "fld" = "field director", "fmd" = "film director", "fds" = "film distributor", "flm" = "film editor", "fmp" = "film producer", "fmk" = "filmmaker", "fpy" = "first party", "frg" = "forger", "fmo" = "former owner", "fnd" = "funder", "gis" = "geographic information specialist", "hnr" = "honoree", "hst" = "host", "his" = "host institution", "ilu" = "illuminator", "ill" = "illustrator", "ins" = "inscriber", "itr" = "instrumentalist", "ive" = "interviewee", "ivr" = "interviewer", "inv" = "inventor", "isb" = "issuing body", "jud" = "judge", "jug" = "jurisdiction governed", "lbr" = "laboratory", "ldr" = "laboratory director", "lsa" = "landscape architect", "led" = "lead", "len" = "lender", "lil" = "libelant", "lit" = "libelant-appellant", "lie" = "libelant-appellee", "lel" = "libelee", "let" = "libelee-appellant", "lee" = "libelee-appellee", "lbt" = "librettist", "lse" = "licensee", "lso" = "licensor", "lgd" = "lighting designer", "ltg" = "lithographer", "lyr" = "lyricist", "mfp" = "manufacture place", "mfr" = "manufacturer", "mrb" = "marbler", "mrk" = "markup editor", "med" = "medium", "mdc" = "metadata contact", "mte" = "metal-engraver", "mtk" = "minute taker", "mod" = "moderator", "mon" = "monitor", "mcp" = "music copyist", "msd" = "musical director", "mus" = "musician", "nrt" = "narrator", "osp" = "onscreen presenter", "opn" = "opponent", "orm" = "organizer", "org" = "originator", "oth" = "other", "own" = "owner", "pan" = "panelist", "ppm" = "papermaker", "pta" = "patent applicant", "pth" = "patent holder", "pat" = "patron", "prf" = "performer", "pma" = "permitting agency", "pht" = "photographer", "ptf" = "plaintiff", "ptt" = "plaintiff-appellant", "pte" = "plaintiff-appellee", "plt" = "platemaker", "pra" = "praeses", "pre" = "presenter", "prt" = "printer", "pop" = "printer of plates", "prm" = "printmaker", "prc" = "process contact", "pro" = "producer", "prn" = "production company", "prs" = "production designer", "pmn" = "production manager", "prd" = "production personnel", "prp" = "production place", "prg" = "programmer", "pdr" = "project director", "pfr" = "proofreader", "prv" = "provider", "pup" = "publication place", "pbl" = "publisher", "pbd" = "publishing director", "ppt" = "puppeteer", "rdd" = "radio director", "rpc" = "radio producer", "rce" = "recording engineer", "rcd" = "recordist", "red" = "redaktor", "ren" = "renderer", "rpt" = "reporter", "rps" = "repository", "rth" = "research team head", "rtm" = "research team member", "res" = "researcher", "rsp" = "respondent", "rst" = "respondent-appellant", "rse" = "respondent-appellee", "rpy" = "responsible party", "rsg" = "restager", "rsr" = "restorationist", "rev" = "reviewer", "rbr" = "rubricator", "sce" = "scenarist", "sad" = "scientific advisor", "aus" = "screenwriter", "scr" = "scribe", "scl" = "sculptor", "spy" = "second party", "sec" = "secretary", "sll" = "seller", "std" = "set designer", "stg" = "setting", "sgn" = "signer", "sng" = "singer", "sds" = "sound designer", "spk" = "speaker", "spn" = "sponsor", "sgd" = "stage director", "stm" = "stage manager", "stn" = "standards body", "str" = "stereotyper", "stl" = "storyteller", "sht" = "supporting host", "srv" = "surveyor", "tch" = "teacher", "tcd" = "technical director", "tld" = "television director", "tlp" = "television producer", "ths" = "thesis advisor", "trc" = "transcriber", "trl" = "translator", "tyd" = "type designer", "tyg" = "typographer", "uvp" = "university place", "vdg" = "videographer", "vac" = "voice actor", "wit" = "witness", "wde" = "wood engraver", "wdc" = "woodcutter", "wam" = "writer of accompanying material", "wac" = "writer of added commentary", "wal" = "writer of added lyrics", "wat" = "writer of added text", "win" = "writer of introduction", "wpr" = "writer of preface", "wst" = "writer of supplementary textual content" ) itemize <- function(header, x) { if (length(x) == 0) return() paste0( header, "\n", "\\itemize{\n", paste0(" \\item ", x, "\n", collapse = ""), "}\n" ) } roxygen2/R/package_files.R0000644000176200001440000000204313540202201015114 0ustar liggesuserspackage_files <- function(path) { all <- normalizePath(r_files(path)) collate <- desc::desc_get_collate(file = file.path(path, "DESCRIPTION")) collate <- normalizePath(file.path(path, "R", collate)) rfiles <- c(collate, setdiff(all, collate)) ignore_files(rfiles, path) } r_files <- function(path) { sort_c(dir(file.path(path, "R"), "\\.[Rr]$", full.names = TRUE)) } ignore_files <- function(rfiles, path) { rbuildignore <- file.path(path, ".Rbuildignore") if (!file.exists(rbuildignore)) return(rfiles) # Strip leading directory and slashes rfiles_relative <- sub(normalizePath(path, winslash = "/"), "", normalizePath(rfiles, winslash = "/"), fixed = TRUE) rfiles_relative <- sub("^[/]*", "", rfiles_relative) # Remove any files that match any perl-compatible regexp patterns <- read_lines(rbuildignore) patterns <- patterns[patterns != ""] if (length(patterns) == 0L) { return(rfiles) } matches <- lapply(patterns, grepl, rfiles_relative, perl = TRUE) matches <- Reduce("|", matches) rfiles[!matches] } roxygen2/R/roxygenize.R0000644000176200001440000000702213632213671014563 0ustar liggesusers#' Process a package with the Rd, namespace and collate roclets. #' #' This is the workhorse function that uses roclets, the built-in document #' transformation functions, to build all documentation for a package. See #' the documentation for the individual roclets, [rd_roclet()], #' [namespace_roclet()], and for [update_collate()], #' for more details. #' #' Note that roxygen2 is a dynamic documentation system: it works by #' inspecting loaded objects in the package. This means that you must #' be able to load the package in order to document it: see [load] for #' details. #' #' @param package.dir Location of package top level directory. Default is #' working directory. #' @param roclets Character vector of roclet names to use with package. #' The default, `NULL`, uses the roxygen `roclets` option, #' which defaults to `c("collate", "namespace", "rd")`. #' @param load_code A function used to load all the R code in the package #' directory. The default, `NULL`, uses the strategy defined by #' the `load` roxygen option, which defaults to [load_pkgload()]. #' See [load] for more details. #' @param clean If `TRUE`, roxygen will delete all files previously #' created by roxygen before running each roclet. #' @return `NULL` #' @export #' @importFrom stats setNames roxygenize <- function(package.dir = ".", roclets = NULL, load_code = NULL, clean = FALSE) { base_path <- normalizePath(package.dir, mustWork = TRUE) is_first <- roxygen_setup(base_path) encoding <- desc::desc_get("Encoding", file = base_path)[[1]] if (!identical(encoding, "UTF-8")) { warning("roxygen2 requires Encoding: UTF-8", call. = FALSE) } roxy_meta_load(base_path) # Load required packages for method registration packages <- roxy_meta_get("packages") lapply(packages, loadNamespace) roclets <- roclets %||% roxy_meta_get("roclets") # Special case collate: it doesn't need to execute code, and must be run # first to ensure that code can be executed if ("collate" %in% roclets) { update_collate(base_path) roclets <- setdiff(roclets, "collate") } if (length(roclets) == 0) return(invisible()) roclets <- lapply(roclets, roclet_find) # Now load code load_code <- find_load_strategy(load_code) env <- load_code(base_path) roxy_meta_set("env", env) on.exit(roxy_meta_set("env", NULL), add = TRUE) # Tokenise each file blocks <- parse_package(base_path, env = NULL) if (clean) { purrr::walk(roclets, roclet_clean, base_path = base_path) } roclets <- lapply(roclets, roclet_preprocess, blocks = blocks, base_path = base_path ) blocks <- lapply(blocks, block_set_env, env = env) results <- lapply(roclets, roclet_process, blocks = blocks, env = env, base_path = base_path ) out <- purrr::map2( roclets, results, roclet_output, base_path = base_path, is_first = is_first ) invisible(out) } #' @rdname roxygenize #' @export roxygenise <- roxygenize roxygen_setup <- function(base_path) { is_first <- first_time(base_path) if (is_first) { message("First time using roxygen2. Upgrading automatically...") } man_path <- file.path(base_path, "man") dir.create(man_path, recursive = TRUE, showWarnings = FALSE) update_roxygen_version(base_path) is_first } roxy_warning <- function(..., file = NA, line = NA) { message <- paste0( if (!is.na(file)) paste0("[", file, ":", line, "] "), ..., collapse = " " ) warning(message, call. = FALSE, immediate. = TRUE) NULL } roxygen2/R/utils-io.R0000644000176200001440000000131213634747606014135 0ustar liggesusersreadLines <- function(...) stop("Use read_lines!") writeLines <- function(...) stop("Use write_lines!") read_lines <- function(path, n = -1L) { base::readLines(path, n = n, encoding = "UTF-8", warn = FALSE) } write_lines <- function(text, path, line_ending = detect_line_ending(path)) { # we need to convert any embedded newlines as well text <- gsub("\r?\n", line_ending, text) path <- file(path, open = "wb") base::writeLines(enc2utf8(text), path, sep = line_ending, useBytes = TRUE) close(path) } detect_line_ending <- function(path) { tryCatch({ samp <- suppressWarnings(readChar(path, nchars = 500)) if (isTRUE(grepl("\r\n", samp))) "\r\n" else "\n" }, error = function(e) "\n") } roxygen2/R/object-r6.R0000644000176200001440000001051313675432065014161 0ustar liggesusers#' @export object_defaults.r6class <- function(x) { r6on <- roxy_meta_get("r6", TRUE) if (isTRUE(r6on)) { list( roxy_tag("docType", NULL, NULL), roxy_tag(".r6data", NULL, extract_r6_data(x$value)) ) } else { NextMethod() } } extract_r6_data <- function(x) { list( self = extract_r6_self_data(x), super = drop_clone_maybe(x, extract_r6_super_data(x)) ) } drop_clone_maybe <- function(x, data) { if (! "clone" %in% names(x$public_methods)) { cline <- which(data$members$name == "clone" & data$members$type == "method") if (length(cline)) data$members <- data$members[-cline, ] } data } extract_r6_self_data <- function(x) { rbind( extract_r6_methods(x), extract_r6_fields(x), extract_r6_bindings(x) ) } default_r6_methods <- function() { "clone" } extract_r6_methods <- function(x) { method_nms <- setdiff(names(x$public_methods), default_r6_methods()) method_loc <- map_int( x$public_methods[method_nms], function(m) { ref <- utils::getSrcref(m) if (is.null(ref)) { name <- x$classname %||% NA stop( "R6 class ", if (!is.na(name)) paste0("(", name, ") "), "without source references. ", "If you use the `installed` load method in `DESCRIPTION`, then ", "try re-installing the package with option '--with-keep.source'. ", "E.g. `install.packages(..., INSTALL_OPTS = \"--with-keep.source\")`." ) } utils::getSrcLocation(ref) } ) method_fnm <- map_chr( x$public_methods[method_nms], function(m) { utils::getSrcFilename(utils::getSrcref(m)) } ) method_formals <- map(x$public_methods[method_nms], formals) methods <- data.frame( stringsAsFactors = FALSE, type = if (length(method_loc)) "method" else character(), name = unname(method_nms), file = unname(method_fnm), line = unname(method_loc), formals = I(unname(method_formals)) ) add_default_method_data(x, methods) } add_default_method_data <- function(obj, methods) { pubm <- obj$public_methods defaults <- list( clone = list( formals = if ("clone" %in% names(pubm)) I(list(formals(pubm$clone))) ) ) for (mname in names(defaults)) { if (mname %in% methods$name) next if (! mname %in% names(obj$public_methods)) next rec <- data.frame( stringsAsFactors = FALSE, type = defaults[[mname]]$type %||% "method", name = defaults[[mname]]$name %||% mname, file = defaults[[mname]]$file %||% NA_character_, line = defaults[[mname]]$line %||% NA_integer_, formals = defaults[[mname]]$formals %||% NULL ) methods <- rbind(methods, rec) } methods } extract_r6_fields <- function(x) { field_nms <- names(x$public_fields) data.frame( stringsAsFactors = FALSE, type = rep("field", length(field_nms)), name = as.character(field_nms), file = rep(NA, length(field_nms)), line = rep(NA, length(field_nms)), formals = I(replicate(length(field_nms), NULL)) ) } extract_r6_bindings <- function(x) { bind_nms <- names(x$active) data.frame( stringsAsFactors = FALSE, type = if (length(bind_nms)) "active" else character(), name = as.character(bind_nms), file = rep(NA, length(bind_nms)), line = rep(NA, length(bind_nms)), formals = I(replicate(length(bind_nms), NULL)) ) } extract_r6_super_data <- function(x) { if (is.null(x$inherit)) return() super <- x$get_inherit() super_data <- extract_r6_super_data(super) method_nms <- names(super$public_methods) field_nms <- names(super$public_fields) active_nms <- names(super$active) classname <- super$classname %||% NA_character_ pkg <- environmentName(topenv(super$parent_env)) cls <- rbind( data.frame( stringsAsFactors = FALSE, package = pkg, classname = classname ), super_data$classes ) types <- rep( c("method", "field", "active"), c(length(method_nms), length(field_nms), length(active_nms)) ) rsort <- function(x) sort_c(x, decreasing = TRUE) names <-c(rsort(method_nms), rsort(field_nms), rsort(active_nms)) mth <- rbind( data.frame( stringsAsFactors = FALSE, package = rep(pkg, length(names)), classname = rep(classname , length(names)), type = types, name = names ), super_data$members ) list(classes = cls, members = mth) } roxygen2/R/block.R0000644000176200001440000001645514115750053013461 0ustar liggesusers#' Blocks #' #' @description #' A `roxy_block` represents a single roxygen2 block. #' #' The `block_*` functions provide a few helpers for common operations: #' * `block_has_tag(blocks, tags)`: does `block` contain any of these `tags`? #' * `block_get_tags(block, tags)`: get all instances of `tags` #' * `block_get_tag(block, tag)`: get single tag. Returns `NULL` if 0, #' throws warning if more than 1. #' * `block_get_tag_value(block, tag)`: gets `val` field from single tag. #' #' @param tags A list of [roxy_tag]s. #' @param file,line Location of the `call` (i.e. the line after the last #' line of the block). #' @param call Expression associated with block. #' @param object Optionally, the object associated with the block, found #' by inspecting/evaluating `call`. #' @param block A `roxy_block` to manipulate. #' @param tag,tags Either a single tag name, or a character vector of tag names. #' @export #' @keywords internal #' @examples #' # The easiest way to see the structure of a roxy_block is to create one #' # using parse_text: #' text <- " #' #' This is a title #' #' #' #' @param x,y A number #' #' @export #' f <- function(x, y) x + y #' " #' #' # parse_text() returns a list of blocks, so I extract the first #' block <- parse_text(text)[[1]] #' block roxy_block <- function(tags, file, line, call, object = NULL) { stopifnot(is.list(tags)) stopifnot(is.character(file), length(file) == 1) stopifnot(is.integer(line), length(line) == 1) structure( list( tags = tags, file = file, line = line, call = call, object = object ), class = "roxy_block" ) } is_roxy_block <- function(x) inherits(x, "roxy_block") #' @export print.roxy_block <- function(x, ...) { call <- deparse(x$call, nlines = 2) if (length(call) == 2) { call <- paste0(call[[1]], " ...") } obj <- format(x$object) cat_line(" [", basename(x$file), ":", x$line, "]") cat_line(" $tag") cat_line(" ", map_chr(x$tags, format, file = x$file)) cat_line(" $call ", call) cat_line(" $object ", obj[[1]]) cat_line(" ", obj[-1]) } block_create <- function(tokens, call, srcref) { pkgenv <- roxy_meta_get("env") # This should only happen in our test cases if (is.null(pkgenv)) pkgenv <- baseenv() evalenv <- new.env(parent = pkgenv) roxy_meta_set("evalenv", evalenv) on.exit(roxy_meta_set("evalenv", NULL), add = TRUE) tags <- parse_tags(tokens) if (length(tags) == 0) return() roxy_block(tags, file = attr(srcref, "srcfile")$filename, line = as.vector(srcref)[[1]], call = call ) } block_set_env <- function(block, env) { block <- block_evaluate(block, env) block <- block_find_object(block, env) block } block_evaluate <- function(block, env) { tags <- block_get_tags(block, "eval") if (length(tags) == 0) { return(block) } # Evaluate results <- lapply(tags, roxy_tag_eval, env = env) results <- lapply(results, function(x) { if (is.null(x)) { character() } else { paste0("#' ", x) } }) # Tokenise and parse tokens <- lapply(results, tokenise_block, file = block$file, offset = block$line ) tags <- lapply(tokens, parse_tags) # Interpolate results back into original locations block_replace_tags(block, "eval", tags) } block_find_object <- function(block, env) { stopifnot(is_roxy_block(block)) object <- object_from_call( call = block$call, env = env, block = block, file = block$file ) block$object <- object class(block) <- unique(c( paste0("roxy_block_", class(object)), class(block) )) # Add in defaults generated from the object defaults <- object_defaults(object) defaults <- c(defaults, list(roxy_tag("backref", block$file, block$file))) default_tags <- map_chr(defaults, "tag") defaults <- defaults[!default_tags %in% block_tags(block)] block$tags <- c(block$tags, defaults) block } # block accessors --------------------------------------------------------- block_tags <- function(block) { map_chr(block$tags, "tag") } #' @export #' @rdname roxy_block block_has_tags <- function(block, tags) { any(block_tags(block) %in% tags) } #' @export #' @rdname roxy_block block_get_tags <- function(block, tags) { block$tags[block_tags(block) %in% tags] } #' @export #' @rdname roxy_block block_get_tag <- function(block, tag) { matches <- which(block_tags(block) %in% tag) n <- length(matches) if (n == 0) { NULL } else if (n == 1) { block$tags[[matches]] } else { roxy_tag_warning(block$tags[[matches[[2]]]], "May only use one @", tag, " per block") block$tags[[matches[[1]]]] } } #' @export #' @rdname roxy_block block_get_tag_value <- function(block, tag) { block_get_tag(block, tag)$val } block_replace_tags <- function(block, tags, values) { indx <- which(block_tags(block) %in% tags) stopifnot(length(indx) == length(values)) tags <- lapply(block$tags, list) tags[indx] <- values block$tags <- compact(unlist(tags, recursive = FALSE)) block } # parsing ----------------------------------------------------------------- parse_tags <- function(tokens) { markdown_activate(tokens) tokens <- parse_description(tokens) out <- vector("list", length(tokens)) for (i in seq_along(tokens)) { out[[i]] <- roxy_tag_parse(tokens[[i]]) } compact(out) } #' @export roxy_tag_parse.roxy_tag_eval <- function(x) { tag_code(x) } #' @export roxy_tag_parse.roxy_tag_include <- function(x) { tag_value(x) } parse_description <- function(tags) { if (length(tags) == 0) { return(tags) } tag_names <- vapply(tags, `[[`, "tag", FUN.VALUE = character(1)) if (tag_names[1] != "") { return(tags) } intro <- tags[[1]] intro$val <- str_trim(intro$raw) if (intro$val == "") { return(tags[-1]) } tags <- tags[-1] tag_names <- tag_names[-1] paragraphs <- str_split(intro$val, fixed('\n\n'))[[1]] lines <- str_count(paragraphs, "\n") + rep(2, length(paragraphs)) offsets <- c(0, cumsum(lines)) # 1st paragraph = title (unless has @title) if ("title" %in% tag_names) { title <- NULL } else if (length(paragraphs) > 0) { title <- roxy_tag("title", paragraphs[1], NULL, intro$file, intro$line + offsets[[1]]) paragraphs <- paragraphs[-1] offsets <- offsets[-1] } else { title <- roxy_tag("title", "", NULL, intro$file, intro$line) } # 2nd paragraph = description (unless has @description) if ("description" %in% tag_names || length(paragraphs) == 0) { description <- NULL } else if (length(paragraphs) > 0) { description <- roxy_tag("description", paragraphs[1], NULL, intro$file, intro$line + offsets[[1]]) paragraphs <- paragraphs[-1] offsets <- offsets[-1] } # Every thing else = details, combined with @details if (length(paragraphs) > 0) { details_para <- paste(paragraphs, collapse = "\n\n") # Find explicit @details tags didx <- which(tag_names == "details") if (length(didx) > 0) { explicit_details <- map_chr(tags[didx], "raw") tags <- tags[-didx] details_para <- paste(c(details_para, explicit_details), collapse = "\n\n") } details <- roxy_tag("details", details_para, NULL, intro$file, intro$line + offsets[[1]]) } else { details <- NULL } c(compact(list(title, description, details)), tags) } roxygen2/R/rd-raw.R0000644000176200001440000000154313544473137013565 0ustar liggesusers#' @export roxy_tag_parse.roxy_tag_evalRd <- function(x) tag_code(x) #' @export roxy_tag_rd.roxy_tag_evalRd <- function(x, base_path, env) { rd_section("rawRd", roxy_tag_eval(x, env)) } #' @export roxy_tag_parse.roxy_tag_rawRd <- function(x) tag_value(x) #' @export roxy_tag_rd.roxy_tag_rawRd <- function(x, base_path, env) { rd_section(x$tag, x$val) } #' @export format.rd_section_rawRd <- function(x, ...) { paste(x$value, collapse = "\n") } roxy_tag_eval <- function(tag, env) { tryCatch({ expr <- parse(text = tag$val) out <- eval(expr, envir = env) if (!is.character(out)) { roxy_tag_warning(tag, "did not evaluate to a string") } else if (anyNA(out)) { roxy_tag_warning(tag, "result contained NA") } else { out } }, error = function(e) { roxy_tag_warning(tag, "failed with error:\n", e$message) }) } roxygen2/R/rd-inherit.R0000644000176200001440000002653014115750050014424 0ustar liggesusers# Tags -------------------------------------------------------------------- #' @export roxy_tag_parse.roxy_tag_inherit <- function(x) tag_inherit(x) #' @export roxy_tag_rd.roxy_tag_inherit <- function(x, base_path, env) { rd_section_inherit(x$val$source, list(x$val$fields)) } #' @export roxy_tag_parse.roxy_tag_inheritParams <- function(x) tag_value(x) #' @export roxy_tag_rd.roxy_tag_inheritParams <- function(x, base_path, env) { rd_section_inherit(x$val, list("params")) } #' @export roxy_tag_parse.roxy_tag_inheritDotParams <- function(x) { tag_two_part(x, "source", "args", required = FALSE, markdown = FALSE) } #' @export roxy_tag_rd.roxy_tag_inheritDotParams <- function(x, base_path, env) { rd_section_inherit_dot_params(x$val$source, x$val$args) } #' @export roxy_tag_parse.roxy_tag_inheritSection <- function(x) tag_name_description(x) #' @export roxy_tag_rd.roxy_tag_inheritSection <- function(x, base_path, env) { rd_section_inherit_section(x$val$name, x$val$description) } # Fields ------------------------------------------------------------------ # For each unique source, list which fields it inherits from rd_section_inherit <- function(source, fields) { stopifnot(is.character(source), is.list(fields)) stopifnot(!anyDuplicated(source)) stopifnot(length(source) == length(fields)) rd_section("inherit", list(source = source, fields = fields)) } #' @export merge.rd_section_inherit <- function(x, y, ...) { stopifnot(identical(class(x), class(y))) dedup <- collapse( c(x$value$source, y$value$source), c(x$value$fields, y$value$fields), function(x) Reduce(union, x) ) rd_section("inherit", list(source = dedup$key, fields = dedup$value)) } #' @export format.rd_section_inherit <- function(x, ...) NULL rd_section_inherit_section <- function(source, title) { stopifnot(is.character(source), is.character(title)) stopifnot(length(source) == length(title)) rd_section("inherit_section", list(source = source, title = title)) } #' @export format.rd_section_inherit_section <- function(x, ...) NULL #' @export merge.rd_section_inherit_section <- function(x, y, ...) { stopifnot(identical(class(x), class(y))) rd_section_inherit_section(c(x$value$source, y$value$source), c(x$value$title, y$value$title)) } rd_section_inherit_dot_params <- function(source, args) { stopifnot(is.character(source), is.character(args)) stopifnot(length(source) == length(args)) rd_section("inherit_dot_params", list(source = source, args = args)) } #' @export format.rd_section_inherit_dot_params <- function(x, ...) NULL #' @export merge.rd_section_inherit_dot_params <- function(x, y, ...) { stopifnot(identical(class(x), class(y))) rd_section_inherit_dot_params(c(x$value$source, y$value$source), c(x$value$args, y$value$args)) } # Process inheritance ----------------------------------------------------- topics_process_inherit <- function(topics, env) { inherits <- function(type) { function(x) x$inherits_from(type) } topics$topo_apply(inherits("return"), inherit_field, roxy_name = "return", rd_name = "value") topics$topo_apply(inherits("title"), inherit_field, "title") topics$topo_apply(inherits("description"), inherit_field, "description") topics$topo_apply(inherits("details"), inherit_field, "details") topics$topo_apply(inherits("seealso"), inherit_field, "seealso") topics$topo_apply(inherits("references"), inherit_field, "references") topics$topo_apply(inherits("examples"), inherit_field, "examples") topics$topo_apply(inherits("author"), inherit_field, "author") topics$topo_apply(inherits("source"), inherit_field, "source") # First inherit individual sections, then all sections. topics$topo_apply(function(x) x$inherits_section_from(), inherit_section) topics$topo_apply(inherits("sections"), inherit_sections) topics$topo_apply(inherits("params"), inherit_params) # Can't inherit ... into ... so can do in any order topics$apply(inherit_dot_params, env = env) invisible() } # Inherit parameters ----------------------------------------------------------- inherit_params <- function(topic, topics) { inheritors <- topic$inherits_from("params") if (length(inheritors) == 0) { return() } documented <- get_documented_params(topic) needed <- topic$get_value("formals") missing <- setdiff(needed, documented) if (length(missing) == 0) { warn(paste0( "Topic '", topic$get_name(), "': ", "no parameters to inherit with @inheritParams" )) return() } for (inheritor in inheritors) { inherited <- find_params(inheritor, topics) matches <- map_chr(missing, match_param, names(inherited)) new_match <- !is.na(matches) if (!any(new_match)) { # Can't warn here because @inherit inherits parameters next } topic$add( rd_section( "param", setNames(inherited[matches[new_match]], missing[new_match]) ) ) missing <- missing[!new_match] } } inherit_dot_params <- function(topic, topics, env) { inheritors <- topic$get_value("inherit_dot_params") if (is.null(inheritors)) return() # Need to find formals for each source funs <- lapply(inheritors$source, function(x) eval(parse(text = x), envir = env)) args <- map2(funs, inheritors$args, select_args_text) # Then pull out the ones we need docs <- lapply(inheritors$source, find_params, topics = topics) arg_matches <- function(args, docs) { doc_args <- str_split(names(docs), ", ?") match <- map_lgl(doc_args, function(x) x %in% args) docs[match] } docs_selected <- unlist(map2(args, docs, arg_matches)) # Only document params under "..." that aren't otherwise documented documented <- get_documented_params(topic) non_documented_params <- setdiff(names(docs_selected), documented) docs_selected <- docs_selected[non_documented_params] # Build the Rd # (1) Link to function(s) that was inherited from src <- inheritors$source dest <- map_chr(src, resolve_qualified_link) from <- paste0("\\code{\\link[", dest, "]{", src, "}}", collapse = ", ") # (2) Show each inherited argument arg_names <- paste0("\\code{", names(docs_selected), "}") args <- paste0(" \\item{", arg_names, "}{", docs_selected, "}", collapse = "\n") rd <- paste0( "\n", " Arguments passed on to ", from, "\n", " \\describe{\n", args, "\n", " }" ) topic$add(rd_section("param", c("..." = rd))) } get_documented_params <- function(topic, only_first = FALSE) { documented <- names(topic$get_value("param")) if (length(documented) > 0) { documented <- strsplit(documented, ",") if (only_first) documented <- map_chr(documented, 1) else documented <- unlist(documented) } documented[documented == "\\dots"] <- "..." documented } find_params <- function(name, topics) { topic <- get_rd(name, topics) if (is.null(topic)) { return() } params <- topic_params(topic) if (is.null(params)) return() param_names <- str_trim(names(params)) param_names[param_names == "\\dots"] <- "..." # Split up compound names on , (swallowing spaces) duplicating their contents individual_names <- strsplit(param_names, ",\\s*") reps <- map_int(individual_names, length) setNames(rep.int(params, reps), unlist(individual_names)) } topic_params <- function(x) UseMethod("topic_params") topic_params.Rd <- function(x) { arguments <- get_tags(x, "\\arguments") if (length(arguments) != 1) { return(list()) } items <- get_tags(arguments[[1]], "\\item") values <- map_chr(items, function(x) rd2text(x[[2]])) params <- map_chr(items, function(x) rd2text(x[[1]])) setNames(values, params) } topic_params.RoxyTopic <- function(x) { x$get_value("param") } # Inherit sections -------------------------------------------------------- inherit_sections <- function(topic, topics) { current_secs <- topic$get_value("section")$title for (inheritor in topic$inherits_from("sections")) { inheritor <- get_rd(inheritor, topics) if (is.null(inheritor)) { return() } sections <- find_sections(inheritor) needed <- !(sections$title %in% current_secs) if (!any(needed)) next topic$add( rd_section_section(sections$title[needed], sections$content[needed]) ) } } inherit_section <- function(topic, topics) { sections <- topic$get_value("inherit_section") sources <- sections$source titles <- sections$title for (i in seq_along(sources)) { inheritor <- get_rd(sources[[i]], topics) if (is.null(inheritor)) { return() } new_section <- find_sections(inheritor) selected <- new_section$title %in% titles[[i]] if (sum(selected) != 1) { warning( "Can't find section '", titles[[i]], "' in ?", sources[[i]], call. = FALSE ) } topic$add( rd_section_section(new_section$title[selected], new_section$content[selected]) ) } } find_sections <- function(topic) { if (inherits(topic, "Rd")) { tag <- get_tags(topic, "\\section") titles <- map_chr(map(tag, 1), rd2text) contents <- map_chr(map(tag, 2), rd2text) list(title = titles, content = contents) } else { topic$get_value("section") } } # Inherit from single field ---------------------------------------------------- inherit_field <- function(topic, topics, rd_name, roxy_name = rd_name) { # Already has the field, so don't need to inherit if (topic$has_section(rd_name)) return() # Otherwise, try each try function listed in inherits for (inherit_from in topic$inherits_from(roxy_name)) { inherit_topic <- get_rd(inherit_from, topics) if (is.null(inherit_topic)) { next } inheritee <- find_field(inherit_topic, rd_name) if (is.null(inheritee)) next topic$add(rd_section(rd_name, inheritee)) return() } } find_field <- function(topic, field_name) { if (inherits(topic, "Rd")) { tag <- get_tags(topic, paste0("\\", field_name)) if (length(tag) == 0) return() value <- tag[[1]] attr(value, "Rd_tag") <- NULL str_trim(rd2text(value)) } else { topic$get_value(field_name) } } # Find info in Rd or topic ------------------------------------------------ get_rd <- function(name, topics) { if (has_colons(name)) { # External package parsed <- parse_expr(name) pkg <- as.character(parsed[[2]]) fun <- as.character(parsed[[3]]) tweak_links(get_rd_from_help(pkg, fun), package = pkg) } else { # Current package rd_name <- topics$find_filename(name) if (identical(rd_name, NA_character_)) { warn(paste0("Can't find help topic '", name, "' in current package")) } topics$get(rd_name) } } get_rd_from_help <- function(package, alias) { if (!is_installed(package)) { warn(paste0("Can't find package '", package, "'")) return() } help <- eval(expr(help(!!alias, !!package))) if (length(help) == 0) { warn(paste0("Can't find help topic '", alias, "' in '", package, "' package")) return() } internal_f("utils", ".getHelpFile")(help) } # helpers ----------------------------------------------------------------- # Returns matching parameter name in haystack match_param <- function(needle, haystack) { if (needle %in% haystack) { return(needle) } if (substr(needle, 1, 1) == ".") { if (needle %in% paste0(".", haystack)) { return(substr(needle, 2, nchar(needle))) } } else { if (paste0(".", needle) %in% haystack) { return(paste0(".", needle)) } } NA } roxygen2/R/rd-markdown.R0000644000176200001440000000660013631761325014611 0ustar liggesusers# Without sections -------------------------------------------------------- #' @export roxy_tag_parse.roxy_tag_author <- function(x) tag_markdown(x) #' @export roxy_tag_rd.roxy_tag_author <- function(x, base_path, env) { rd_section(x$tag, x$val) } #' @export format.rd_section_author <- function(x, ...) { format_collapse(x, ...) } #' @export roxy_tag_parse.roxy_tag_format <- function(x) tag_markdown(x) #' @export roxy_tag_rd.roxy_tag_format <- function(x, base_path, env) { rd_section(x$tag, x$val) } #' @export format.rd_section_format <- function(x, ...) { format_collapse(x, ...) } #' @export roxy_tag_parse.roxy_tag_note <- function(x) tag_markdown(x) #' @export roxy_tag_rd.roxy_tag_note <- function(x, base_path, env) { rd_section(x$tag, x$val) } #' @export format.rd_section_note <- function(x, ...) { format_collapse(x, ...) } #' @export roxy_tag_parse.roxy_tag_references <- function(x) tag_markdown(x) #' @export roxy_tag_rd.roxy_tag_references <- function(x, base_path, env) { rd_section(x$tag, x$val) } #' @export format.rd_section_references <- function(x, ...) { format_collapse(x, ...) } #' @export roxy_tag_parse.roxy_tag_return <- function(x) tag_markdown(x) #' @export roxy_tag_parse.roxy_tag_returns <- roxy_tag_parse.roxy_tag_return #' @export roxy_tag_rd.roxy_tag_return <- function(x, base_path, env) { rd_section("value", x$val) } #' @export roxy_tag_rd.roxy_tag_returns <- roxy_tag_rd.roxy_tag_return #' @export format.rd_section_value <- function(x, ...) { format_collapse(x, ...) } #' @export roxy_tag_parse.roxy_tag_seealso <- function(x) tag_markdown(x) #' @export roxy_tag_rd.roxy_tag_seealso <- function(x, base_path, env) { rd_section(x$tag, x$val) } #' @export format.rd_section_seealso <- function(x, ...) { format_collapse(x, ...) } #' @export roxy_tag_parse.roxy_tag_source <- function(x) tag_markdown(x) #' @export roxy_tag_rd.roxy_tag_source <- function(x, base_path, env) { rd_section(x$tag, x$val) } #' @export format.rd_section_source <- function(x, ...) { format_collapse(x, ...) } #' @export roxy_tag_parse.roxy_tag_title <- function(x) tag_markdown(x) #' @export roxy_tag_rd.roxy_tag_title <- function(x, base_path, env) { rd_section(x$tag, x$val) } #' @export format.rd_section_title <- function(x, ...) { format_first(x, ...) } # With sections ----------------------------------------------------------- #' @export roxy_tag_parse.roxy_tag_description <- function(x) { tag_markdown_with_sections(x) } #' @export roxy_tag_rd.roxy_tag_description <- function(x, base_path, env) { rd_section_markdown(x$tag, x$val) } #' @export format.rd_section_description <- function(x, ...) { format_collapse(x, ...) } #' @export roxy_tag_parse.roxy_tag_details <- function(x) { tag_markdown_with_sections(x) } #' @export roxy_tag_rd.roxy_tag_details <- function(x, base_path, env) { rd_section_markdown(x$tag, x$val) } #' @export format.rd_section_details <- function(x, ...) { format_collapse(x, ...) } rd_section_markdown <- function(name, value) { # Any additional components are sections if (length(value) > 1) { titles <- names(value) value <- unname(value) name <- c(name, rep("section", length(value) - 1)) value <- c( list(value[[1]]), map2(titles[-1], value[-1], ~ list(title = .x, content = .y)) ) if (value[[1]] == "") { name <- name[-1] value <- value[-1] } } map2(name, value, rd_section) } roxygen2/R/cpp11.R0000644000176200001440000000125014047226732013304 0ustar liggesusers# Generated by cpp11: do not edit by hand escapeExamples <- function(x) { .Call(`_roxygen2_escapeExamples`, x) } findEndOfTag <- function(string, is_code) { .Call(`_roxygen2_findEndOfTag`, string, is_code) } rdComplete <- function(string, is_code) { .Call(`_roxygen2_rdComplete`, string, is_code) } leadingSpaces <- function(lines) { .Call(`_roxygen2_leadingSpaces`, lines) } tokenise_block <- function(lines, file, offset) { .Call(`_roxygen2_tokenise_block`, lines, file, offset) } find_includes <- function(path) { .Call(`_roxygen2_find_includes`, path) } wrapUsage <- function(string, width, indent) { .Call(`_roxygen2_wrapUsage`, string, width, indent) } roxygen2/R/rd-examples.R0000644000176200001440000000511314036301727014577 0ustar liggesusers#' @export roxy_tag_parse.roxy_tag_examples <- function(x) { tag_examples(x) } #' @export roxy_tag_parse.roxy_tag_examplesIf <- function(x) { lines <- unlist(strsplit(x$raw, "\r?\n")) condition <- lines[1] tryCatch( suppressWarnings(parse(text = condition)), error = function(err) { roxy_tag_warning(x, "failed to parse condition of @examplesIf") } ) dontshow <- paste0( "\\dontshow{if (", condition, ") (if (getRversion() >= \"3.4\") withAutoprint else force)(\\{ # examplesIf}" ) x$raw <- paste( c(dontshow, lines[-1], "\\dontshow{\\}) # examplesIf}"), collapse = "\n" ) x <- tag_examples(x) } #' @export roxy_tag_parse.roxy_tag_example <- function(x) { x <- tag_value(x) nl <- str_count(x$val, "\n") if (any(nl) > 0) { roxy_tag_warning(x, "spans multiple lines. Do you want @examples?") return() } x } #' @export roxy_tag_rd.roxy_tag_examples <- function(x, base_path, env) { rd_section("examples", x$val) } #' @export roxy_tag_rd.roxy_tag_examplesIf <- function(x, base_path, env) { rd_section("examples", x$val) } #' @export roxy_tag_rd.roxy_tag_example <- function(x, base_path, env) { path <- file.path(base_path, x$val) if (!file.exists(path)) { roxy_tag_warning(x, "'", path, "' doesn't exist") return() } code <- read_lines(path) rd_section("examples", escape_examples(code)) } #' @export format.rd_section_examples <- function(x, ...) { value <- paste0(x$value, collapse = "\n") rd_macro(x$type, value, space = TRUE) } #' Escape examples #' #' This documentation topic is used primarily for testing and to record #' our understanding of the `\example{}` escaping rules. #' See for the details provided #' by R core. #' #' @keywords internal #' @examples #' # In examples we automatically escape Rd comments (%): #' 100 %% 30 #' # even if they are in strings #' "50%" #' #' # and \\ and \v inside of strings and symbols #' "\v" # vertical tab #' "\\" #' # but not comments: \l \v #' #' # other string escapes are left as is #' "\"" #' "\n" #' #' # Otherwise, backslashes and parentheses are left as is. This #' # means that you need to escape unbalanced parentheses, which typically only #' # occur in \dontshow{}: #' \dontshow{if (FALSE) \{ } #' print("Hello") #' \dontshow{ \} } #' #' # You also need to escape backslashes in infix operators and comments #' # (this is generally rare) #' `%\\%` <- function(x, y) x + y #' 10 %\\% 20 #' # \\\\ (renders as two backslashes) escape_examples <- function(x) { x <- paste0(x, collapse = "\n") rd(escapeExamples(x)) } roxygen2/R/tag-parser.R0000644000176200001440000001320314115747515014431 0ustar liggesusers#' Parse tags #' #' These functions parse the `raw` tag value, convert a string into a richer R #' object and storing it in `val`, or provide an informative warning and #' returning `NULL`. #' #' @section New tag: #' To create a new `@mytag` define `roxy_tag_parse.roxy_tag_mytag()`. It should #' either call one of the functions here, or directly set `x$val`. #' #' @param x A [roxy_tag] object to parse #' @returns A [roxy_tag] object with the `val` field set to the parsed value. #' @name tag_parsers #' @keywords internal NULL #' @export #' @rdname tag_parsers tag_value <- function(x) { if (x$raw == "") { roxy_tag_warning(x, "requires a value") } else if (!rdComplete(x$raw, is_code = FALSE)) { roxy_tag_warning(x, "mismatched braces or quotes") } else { x$val <- str_trim(x$raw) x } } #' @export #' @rdname tag_parsers tag_inherit <- function(x) { if (x$raw == "") { roxy_tag_warning(x, "requires a value") } else if (!rdComplete(x$raw, is_code = FALSE)) { roxy_tag_warning(x, "mismatched braces or quotes") } else { pieces <- str_split(str_trim(x$raw), "\\s+")[[1]] fields <- pieces[-1] # Also recorded in `rd.Rmd` all <- c("params", "return", "title", "description", "details", "seealso", "sections", "references", "examples", "author", "source") if (length(fields) == 0) { fields <- all } else { unknown <- setdiff(fields, all) if (length(unknown) > 0) { types <- paste0(unknown, collapse = ", ") roxy_tag_warning(x, "Unknown inherit type: ", types) fields <- intersect(fields, all) } } x$val <- list( source = pieces[1], fields = fields ) x } } #' @export #' @rdname tag_parsers tag_name <- function(x) { if (x$raw == "") { roxy_tag_warning(x, "requires a name") } else if (!rdComplete(x$raw, is_code = FALSE)) { roxy_tag_warning(x, "mismatched braces or quotes") } else if (str_count(x$raw, "\\s+") > 1) { roxy_tag_warning(x, "should have only a single argument") } else { x$val <- str_trim(x$raw) x } } #' @export #' @rdname tag_parsers #' @param first,second Name of first and second parts of two part tags #' @param required Is the second part required (TRUE) or can it be blank #' (FALSE)? #' @param markdown Should the second part be parsed as markdown? tag_two_part <- function(x, first, second, required = TRUE, markdown = TRUE) { if (str_trim(x$raw) == "") { roxy_tag_warning(x, "requires a value") } else if (required && !str_detect(x$raw, "[[:space:]]+")) { roxy_tag_warning(x, "requires ", first, " and ", second) } else if (!rdComplete(x$raw, is_code = FALSE)) { roxy_tag_warning(x, "mismatched braces or quotes") } else { pieces <- str_split_fixed(str_trim(x$raw), "[[:space:]]+", 2) pieces[is.na(pieces)] <- "" if (markdown) { pieces[,2] <- markdown_if_active(pieces[,2], x) } x$val <- list( pieces[, 1], trim_docstring(pieces[,2]) ) names(x$val) <- c(first, second) x } } #' @export #' @rdname tag_parsers tag_name_description <- function(x) { tag_two_part(x, "name", "description") } #' @export #' @rdname tag_parsers #' @param min,max Minimum and maximum number of words tag_words <- function(x, min = 0, max = Inf) { if (!rdComplete(x$raw, is_code = FALSE)) { return(roxy_tag_warning(x, "mismatched braces or quotes")) } words <- str_split(str_trim(x$raw), "\\s+")[[1]] if (length(words) < min) { roxy_tag_warning(x, " needs at least ", min, " words") } else if (length(words) > max) { roxy_tag_warning(x, " can have at most ", max, " words") } x$val <- words x } #' @export #' @rdname tag_parsers tag_words_line <- function(x) { x$val <- str_trim(x$raw) if (str_detect(x$val, "\n")) { roxy_tag_warning(x, "may only span a single line") } else if (!rdComplete(x$val, is_code = FALSE)) { roxy_tag_warning(x, "mismatched braces or quotes") } else { x$val <- str_split(x$val, "\\s+")[[1]] x } } #' @export #' @rdname tag_parsers tag_toggle <- function(x) { x$val <- str_trim(x$raw) if (x$val != "") { roxy_tag_warning(x, "has no parameters") } else { x } } #' @export #' @rdname tag_parsers tag_code <- function(x) { if (x$raw == "") { roxy_tag_warning(x, "requires a value") } else { tryCatch({ parse(text = x$raw) }, error = function(e) { roxy_tag_warning(x, "code failed to parse.\n", e$message) }) x$val <- x$raw x } } # Examples need special parsing because escaping rules are different #' @export #' @rdname tag_parsers tag_examples <- function(x) { if (x$raw == "") { return(roxy_tag_warning(x, "requires a value")) } x$val <- escape_examples(gsub("^\n", "", x$raw)) if (!rdComplete(x$val, is_code = TRUE)) { roxy_tag_warning(x, "mismatched braces or quotes") } else { x } } #' @export #' @rdname tag_parsers tag_markdown <- function(x) { x$val <- markdown_if_active(x$raw, x) x } #' @export #' @rdname tag_parsers tag_markdown_with_sections <- function(x) { if (x$raw == "") { return(roxy_tag_warning(x, "requires a value")) } x$val <- markdown_if_active(x$raw, x, sections = TRUE) for (i in seq_along(x$val)) { if (!rdComplete(x$val[i], is_code = FALSE)) { roxy_tag_warning(x, "mismatched braces or quotes") x$val[i] <- "" } else { x$val[i] <- str_trim(x$val[i]) } } x } markdown_if_active <- function(text, tag, sections = FALSE) { if (markdown_on()) { markdown(text, tag, sections) } else { if (!rdComplete(text, is_code = FALSE)) { roxy_tag_warning(tag, "mismatched braces or quotes") "" } else { str_trim(text) } } } roxygen2/R/rd-backref.R0000644000176200001440000000113213544473137014363 0ustar liggesusers#' @export roxy_tag_parse.roxy_tag_backref <- function(x) { tag_value(x) } #' @export roxy_tag_rd.roxy_tag_backref <- function(x, base_path, env) { rd_section("backref", x$val) } #' @export format.rd_section_backref <- function(x, ...) { filename <- unique(x$value) filename <- file.path(basename(dirname(filename)), basename(filename), fsep = "/") lines <- stringi::stri_wrap( paste0("Please edit documentation in ", paste(filename, collapse = ", ")), initial = "% ", prefix = "% ", width = 80, whitespace_only = TRUE ) paste0(paste0(lines, collapse = "\n")) } roxygen2/R/rd-template.R0000644000176200001440000000277013544713502014603 0ustar liggesusers#' @export roxy_tag_parse.roxy_tag_template <- function(x) { tag_value(x) } #' @export roxy_tag_parse.roxy_tag_templateVar <- function(x) { tag_name_description(x) } process_templates <- function(block, base_path) { tags <- block_get_tags(block, "template") if (length(tags) == 0) return(block) templates <- map_chr(tags, "val") paths <- map_chr(templates, template_find, base_path = base_path) var_tags <- block_get_tags(block, "templateVar") vars <- set_names( map(var_tags, c("val", "description")), map_chr(var_tags, c("val", "name")) ) vars <- lapply(vars, utils::type.convert, as.is = TRUE) results <- lapply(paths, template_eval, vars = list2env(vars)) tokens <- lapply(results, tokenise_block, file = "TEMPLATE", offset = 0L) tags <- lapply(tokens, parse_tags) # Insert templates back in the location where they came from block_replace_tags(block, "template", tags) } # Helpers ----------------------------------------------------------------- template_find <- function(base_path, template_name) { file_name <- paste0(template_name, ".", c("R", "r")) path <- c( file.path(base_path, "man-roxygen", file_name), file.path(base_path, "man", "roxygen", "templates", file_name) ) path_exists <- file.exists(path) if (!any(path_exists)) { stop("Can't find template '", template_name, "'", call. = FALSE) } path[path_exists][[1]] } template_eval <- function(template_path, vars) { utils::capture.output(brew::brew(template_path, envir = vars)) } roxygen2/R/rd-simple.R0000644000176200001440000000204513544473137014263 0ustar liggesusers#' @export roxy_tag_parse.roxy_tag_concept <- function(x) tag_value(x) #' @export roxy_tag_rd.roxy_tag_concept <- function(x, base_path, env) { rd_section(x$tag, x$val) } #' @export format.rd_section_concept <- function(x, ...) { format_rd(x, ...) } #' @export roxy_tag_parse.roxy_tag_docType <- function(x) tag_name(x) #' @export roxy_tag_rd.roxy_tag_docType <- function(x, base_path, env) { rd_section("docType", x$val) } #' @export format.rd_section_docType <- function(x, ...) { format_first(x, ...) } #' @export roxy_tag_parse.roxy_tag_encoding <- function(x) tag_value(x) #' @export roxy_tag_rd.roxy_tag_encoding <- function(x, base_path, env) { rd_section(x$tag, x$val) } #' @export format.rd_section_encoding <- function(x, ...) { format_first(x, ...) } #' @export roxy_tag_parse.roxy_tag_keywords <- function(x) tag_value(x) #' @export roxy_tag_rd.roxy_tag_keywords <- function(x, base_path, env) { rd_section("keyword", str_split(x$val, "\\s+")[[1]]) } #' @export format.rd_section_keyword <- function(x, ...) { format_rd(x, ...) } roxygen2/R/topic.R0000644000176200001440000001123113631761325013476 0ustar liggesusers #' A `RoxyTopic` is an ordered collection of unique rd_sections #' #' @description #' A `RoxyTopic` object corresponds to a generated `.Rd` file. #' #' @param type Section type, a character scalar. #' @param overwrite Whether to overwrite an existing section. If `FALSE` #' then the two sections will be merged. #' #' @keywords internal RoxyTopic <- R6::R6Class("RoxyTopic", public = list( #' @field sections Named list of sections. Each item must be an #' [rd_section()] object. sections = list(), #' @field filename Path to the `.Rd` file to generate. filename = "", #' @description Format the `.Rd` file. It considers the sections in #' particular order, even though Rd tools will reorder them again. #' #' @param ... Passed to the `format()` methods of the [rd_section()] #' objects, the sections. #' @return Character string. format = function(...) { # This has to happen here to get a better order when combining topics order <- c("backref", "docType", "encoding", "name", "alias", "title", "format", "source", "usage", "param", "value", "description", "details", "minidesc", "field", "slot", "rcmethods", "note", "section", "examples", "references", "seealso", "author", "concept", "keyword", "rawRd") sections <- move_names_to_front(self$sections, order) formatted <- lapply(sections, format, ...) paste0( made_by("%"), paste0(unlist(formatted), collapse = "\n") ) }, #' @description Check if an `.Rd` file is valid #' @return Logical flag, `TRUE` for valid `.Rd` files is_valid = function() { # Needs both title and name sections to generate valid Rd all(self$has_section(c("title", "name"))) }, #' @description Check if an `.Rd` file has a certain section. #' @return Logical flag. has_section = function(type) { type %in% names(self$sections) }, #' @description Query a section. #' @return The [rd_section] object representing the section, or `NULL` #' if the topic has no such section. get_section = function(type) { self$sections[[type]] }, #' @description Query the value of a section. This is the value of #' the [rd_section] object. #' @return Value. get_value = function(type) { self$get_section(type)$value }, #' @description Get the Rd code of a section. #' @return Character vector, one element per line. get_rd = function(type) { format(self$get_section(type)) }, #' @description Get the value of the `name` section. This is the name #' of the Rd topic. #' @return Character scalar. get_name = function() { self$get_value("name") }, #' @description Query the topics this topic inherits `type` from. #' @return A character vector of topic names. inherits_from = function(type) { if (!self$has_section("inherit")) { return(character()) } inherit <- self$get_value("inherit") inherits_field <- map_lgl(inherit$fields, function(x) type %in% x) sources <- inherit$source[inherits_field] if ("NULL" %in% sources) return(character()) sources }, #' @description Query the topics this topic inherits sections from. #' @return A character vector of topic names. inherits_section_from = function() { if (!self$has_section("inherit_section")) { return(character()) } self$get_value("inherit_section")$source }, #' @description Add one or more sections to the topic. #' @param x Section(s) to add. It may be #' another `RoxyTopic` object, all of its sections will be added; #' or an [rd_section] object; #' or a list of [rd_section] objects to add. add = function(x, overwrite = FALSE) { if (inherits(x, "RoxyTopic")) { self$add(x$sections, overwrite = overwrite) } else if (inherits(x, "rd_section")) { self$add_section(x, overwrite = overwrite) } else if (is.list(x)) { for (section in x) { self$add_section(section, overwrite = overwrite) } } else if (is.null(x)) { # skip } else { stop("Don't know how to add object of type ", class(x)[1]) } invisible() }, #' @description Add a section. #' @details #' Ensures that each type of name (as given by its name), only appears #' once in `self$sections`. This method if for internal use only. #' @param section [rd_section] object to add. add_section = function(section, overwrite = FALSE) { if (is.null(section)) return() type <- section$type if (self$has_section(type) && !overwrite) { section <- merge(self$get_section(type), section) } self$sections[[type]] <- section invisible() } )) move_names_to_front <- function(x, to_front) { nms <- names(x) x[union(intersect(to_front, nms), nms)] } roxygen2/R/object-s3.R0000644000176200001440000000457213540202201014141 0ustar liggesusers#' Determine if a function is an S3 generic or S3 method. #' #' @description #' `is_s3_generic` compares name to `.knownS3Generics` and #' `.S3PrimitiveGenerics`, then looks at the function body to see if it #' calls [UseMethod()]. #' #' `is_s3_method` builds names of all possible generics for that function #' and then checks if any of them actually is a generic. #' #' @param name Name of function. #' @param env Base environment in which to look for function definition. #' @export is_s3_generic <- function(name, env = parent.frame()) { if (name == "") return(FALSE) if (!exists(name, envir = env)) return(FALSE) f <- get(name, envir = env) if (!is.function(f)) return(FALSE) if (inherits(f, "groupGenericFunction")) return(TRUE) ns_name <- tryCatch(getNamespaceName(environment(f)), error = function(e) "") if (identical(unname(.knownS3Generics[name]), ns_name)) return(TRUE) if (is.primitive(f)) { known_generics <- c(names(.knownS3Generics), internal_f("tools", ".get_internal_S3_generics")()) return(name %in% known_generics) } calls_use_method(body(f)) } calls_use_method <- function(x) { # Base cases if (missing(x)) return(FALSE) if (!is.call(x)) return(FALSE) if (identical(x[[1]], quote(UseMethod))) return(TRUE) if (length(x) == 1) return(FALSE) # Recursive case: arguments to call for (arg in as.list(x[-1])) { if (calls_use_method(arg)) return(TRUE) } FALSE } #' @rdname is_s3_generic #' @export is_s3_method <- function(name, env = parent.frame()) { !is.null(find_generic(name, env)) } is.s3method <- function(x) inherits(x, "s3method") is.s3generic <- function(x) inherits(x, "s3generic") is.s3 <- function(x) inherits(x, c("s3method", "s3generic")) find_generic <- function(name, env = parent.frame()) { pieces <- str_split(name, fixed("."))[[1]] n <- length(pieces) # No . in name, so can't be method if (n == 1) return(NULL) for(i in seq_len(n - 1)) { generic <- paste0(pieces[seq_len(i)], collapse = ".") class <- paste0(pieces[(i + 1):n], collapse = ".") if (is_s3_generic(generic, env)) return(c(generic, class)) } NULL } s3_method <- function(f, method) { stopifnot(is.function(f)) stopifnot(length(method) == 2, is.character(method)) class(f) <- c("s3method", "function") attr(f, "s3method") <- method f } s3_method_info <- function(x) { stopifnot(is.s3(x)) attr(x, "s3method") } roxygen2/R/collate.R0000644000176200001440000000513613540253530014003 0ustar liggesusers#' Update Collate field in DESCRIPTION #' #' @description #' By default, R loads files in alphabetical order. Unfortunately not every #' alphabet puts letters in the same order, so you can't rely on alphabetic #' ordering if you need one file loaded before another. (This usually doesn't #' matter but is important for S4, where you need to make sure that classes are #' loaded before subclasses and generics are defined before methods.). #' You can override the default alphabetical ordering with `@include before.R`, #' which specify that `before.R` must be loaded before the current file. #' #' Generally, you will not need to run this function yourself; it should be #' run automatically by any package that needs to load your R files in #' collation order. #' #' @section Collate: #' This is not a roclet because roclets need the values of objects in a package, #' and those values can not be generated unless you've sourced the files, #' and you can't source the files unless you know the correct order. #' #' If there are no `@include` tags, roxygen2 will leave collate as is. #' This makes it easier to use roxygen2 with an existing collate directive, #' but if you remove all your `@include` tags, you'll need to also #' manually delete the collate field. #' #' @param base_path Path to package directory. #' @examples #' #' If `example-a.R', `example-b.R' and `example-c.R' live in R/ #' #' and we're in `example-a.R`, then the following @@include statement #' #' ensures that example-b and example-c are sourced before example-a. #' #' @@include example-b.R example-c.R #' NULL #' @export #' @aliases @@include update_collate <- function(base_path) { new <- generate_collate(file.path(base_path, "R")) if (is.null(new)) return() desc_path <- file.path(base_path, "DESCRIPTION") old <- desc::desc_get_collate(file = desc_path) if (!identical(old, new)) { cat('Updating collate directive in ', desc_path, "\n") desc::desc_set_collate(new, file = desc_path) } invisible() } generate_collate <- function(base_path) { paths <- sort_c(dir(base_path, pattern = "[.][Rr]$", full.names = TRUE)) includes <- lapply(paths, find_includes) names(includes) <- paths n <- sum(map_int(includes, length)) if (n == 0) return() topo <- TopoSort$new() for (path in paths) { file <- base_path(path, base_path) topo$add(file) for (include in includes[[path]]) { topo$add_ancestor(file, include) } } topo$sort() } base_path <- function(path, base) { path <- normalizePath(path, winslash = "/") base <- normalizePath(base, winslash = "/") str_replace(path, fixed(paste0(base, "/")), "") } roxygen2/R/object-import.R0000644000176200001440000000250613675432100015135 0ustar liggesusers# Re-export ---------------------------------------------------------------- rd_section_reexport <- function(pkg, fun) { stopifnot(is.character(pkg), is.character(fun)) stopifnot(length(pkg) == length(fun)) rd_section("reexport", list(pkg = pkg, fun = fun)) } #' @export roxy_tag_rd.roxy_tag_.reexport <- function(x, base_path, env) { rd_section_reexport(x$val$pkg, x$val$fun) } #' @export merge.rd_section_reexport <- function(x, y, ...) { stopifnot(identical(class(x), class(y))) rd_section_reexport(c(x$value$pkg, y$value$pkg), c(x$value$fun, y$value$fun)) } #' @export format.rd_section_reexport <- function(x, ...) { pkgs <- split(x$value$fun, x$value$pkg) pkg_links <- map2(names(pkgs), pkgs, function(pkg, funs) { funs <- sort_c(funs) files <- map_chr( funs, try_find_topic_in_package, pkg = pkg, where = " in re-export" ) links <- paste0( "\\code{\\link[", pkg, ifelse(files == funs, "", paste0(":", files)), "]{", escape(funs), "}}", collapse = ", ") paste0("\\item{", pkg, "}{", links, "}") }) paste0( "\\description{\n", "These objects are imported from other packages. Follow the links\n", "below to see their documentation.\n", "\n", "\\describe{\n", paste0(" ", unlist(pkg_links), collapse = "\n\n"), "\n}}\n" ) } roxygen2/R/object-format.R0000644000176200001440000000240213540202201015072 0ustar liggesusers#' Default format for data #' #' This function is called to generate the default "Format" section for each #' data object. The default implementation will return the class and dimension #' information. #' #' @param x A data object #' @return A `character` value with valid `Rd` syntax, or `NULL`. #' @export object_format <- function(x) { UseMethod("object_format") } #' @export object_format.default <- function(x) { paste0("An object of class ", format_classes(x), " ", format_dim(x), ".") } format_classes <- function(x) { classes <- paste0("\\code{", class(x), "}") base_classes <- NULL if (length(classes) > 1L) { base_classes <- paste0( " (inherits from ", paste(classes[-1L], collapse = ", "), ")") } paste0(classes[[1L]], base_classes) } format_dim <- function(x) { if (length(dim(x)) == 2L) { paste0("with ", nrow(x), " rows and ", ncol(x), " columns") } else if (length(dim(x)) > 2L) { paste0("of dimension ", paste(dim(x), collapse = " x ")) } else { paste0("of length ", length(x)) } } # helpers ----------------------------------------------------------------- # used for testing call_to_format <- function(code, env = pkg_env()) { obj <- call_to_object(!!enexpr(code), env) object_format(obj$value) } roxygen2/R/utils-rd.R0000644000176200001440000000757014115750050014125 0ustar liggesusers# Output ------------------------------------------------------------------ # A simple object to represent rd escaped text. rd <- function(x) { structure(x, class = "rd") } #' @export c.rd <- function(...) { rd(NextMethod()) } #' @export print.rd <- function(x, ...) { out <- paste0(" ", x, collapse = "\n") cat(out) } escape <- function(x) UseMethod("escape") escape.NULL <- function(x) NULL escape.rd <- function(x) x escape.character <- function(x) { # wrap_usage uses \u{A0}, the unicode non-breaking space, which # is not necessarily valid in windows locales. useBytes is a quick # hack to fix the problem. x1 <- gsub("\\", "\\\\", x, fixed = TRUE, useBytes = TRUE) x2 <- gsub("%", "\\%", x1, fixed = TRUE, useBytes = TRUE) rd(x2) } # Works like paste, but automatically escapes all input variables, # but not literal strings build_rd <- function(..., collapse = NULL, sep = "") { args <- dots(...) env <- parent.frame() escaped <- lapply(args, function(arg) { if (is.character(arg)) return(arg) escape(eval(arg, env)) }) string <- do.call("paste", c(escaped, list(collapse = collapse, sep = sep))) rd(string) } dots <- function(...) { eval(substitute(alist(...))) } # Translate a field and values into an Rd macro. # Multiple values get their own braces. rd_macro <- function(field, ..., space = FALSE) { if (space) { values <- paste0("\n", paste0(..., collapse = "\n"), "\n") } else { values <- str_trim(c(...)) } paste0("\\", field, paste0("{", values, "}", collapse = "")) } # Input ------------------------------------------------------------------- get_tags <- function(rd, tag) { Filter(function(x) identical(attr(x, "Rd_tag"), tag), rd) } rd2text <- function(x) { chr <- as_character_rd(structure(x, class = "Rd"), deparse = TRUE) paste(chr, collapse = "") } tweak_links <- function(x, package) { tag <- attr(x, "Rd_tag") if (is.list(x)) { if (!is.null(tag) && tag == "\\link") { opt <- attr(x, "Rd_option") if (is.null(opt)) { if (has_topic(x[[1]], package)) { attr(x, "Rd_option") <- structure(package, Rd_tag = "TEXT") } } else { if (is.character(opt) && length(opt) == 1 && substr(opt, 1, 1) == "=") { topic <- substr(opt, 2, nchar(opt)) if (has_topic(topic, package)) { file <- find_topic_in_package(package, topic) attr(x, "Rd_option") <- structure(paste0(package, ":", file), Rd_tag = "TEXT") } } else if (grepl(":", opt)) { # need to fix the link to point to a file target <- str_split_fixed(opt, ":", n = 2) file <- try_find_topic_in_package( target[1], target[2], where = " in inherited text" ) attr(x, "Rd_option") <- structure(paste0(target[1], ":", file), Rd_tag = "TEXT") } } } else if (length(x) > 0) { x[] <- map(x, tweak_links, package = package) } } x } # helpers ----------------------------------------------------------------- parse_rd <- function(x) { con <- textConnection(x) on.exit(close(con), add = TRUE) tryCatch( tools::parse_Rd(con, fragment = TRUE, encoding = "UTF-8"), warning = function(cnd) NULL ) } # Generated in .onLoad() as_character_rd <- NULL make_as_character_rd <- function() { # "as.character.Rd" appears to be missing \href in TWOARGS # this code hacks the body of the function to add it fn <- internal_f("tools", "as.character.Rd") body <- body(fn) idx <- purrr::detect_index(body, ~ is_call(.x, "<-", 2) && is_symbol(.x[[2]], "TWOARG")) if (idx == 0) { return(fn) } body[[idx]][[3]] <- call_modify(body[[idx]][[3]], "\\href") body(fn) <- body fn } has_topic <- function(topic, package) { tryCatch( { out <- utils::help((topic), package = (package)) length(out) == 1 }, error = function(c) FALSE ) } roxygen2/R/object-rc.R0000644000176200001440000000476314047227003014234 0ustar liggesusers#' @export roxy_tag_rd.roxy_tag_.methods <- function(x, base_path, env) { desc <- lapply(x$val, function(x) docstring(x$value@.Data)) usage <- map_chr(x$val, function(x) { function_usage(x$value@name, formals(x$value@.Data)) }) has_docs <- !map_lgl(desc, is.null) desc <- desc[has_docs] usage <- usage[has_docs] rd_section("rcmethods", setNames(desc, usage)) } #' @export format.rd_section_rcmethods <- function(x, ...) { rd_section_description("Methods", names(x$value), x$value) } # Extract all methods from an RC definition, returning a list of "objects". rc_methods <- function(obj) { stopifnot(methods::is(obj, "refClassRepresentation")) parents <- obj@refSuperClasses parent_methods <- unlist(lapply(parents, function(x) { methods::getRefClass(x)$methods() })) method_names <- sort_c(setdiff(ls(envir = obj@refMethods), parent_methods)) methods <- mget(method_names, envir = obj@refMethods) lapply(methods, object, alias = NULL, type = "rcmethod") } add_rc_metadata <- function(val, name, class) { class(val) <- c("rcmethod", "function") attr(val, "rcclass") <- class attr(val, "rcmethod") <- name val } get_method <- function(obj, method_name) { eval(call("$", quote(obj), as.name(method_name))) } # Modified from methods:::.refMethodDoc - a function has a doc string # if it's a call to {, with more than 1 element, and the first element is # a character vector. docstring <- function(f) { stopifnot(is.function(f)) if (is.primitive(f)) return(NULL) b <- body(f) if (length(b) <= 2 || !identical(b[[1]], quote(`{`))) return(NULL) first <- b[[2]] if (!is.character(first)) return(NULL) if (first == "") return(NULL) trim_docstring(first) } # Implementation converted from # http://www.python.org/dev/peps/pep-0257/#handling-docstring-indentation trim_docstring <- function(docstring) { if (docstring == "") return("") # Convert tabs to spaces (using four spaces for tabs) # and split into a vector of lines: lines <- strsplit(gsub("\t", " ", docstring), "\n")[[1]] if (length(lines) == 1) return(strip(lines)) # Determine minimum indentation (first line doesn't count): indent <- min(leadingSpaces(lines[-1])) # Remove indentation (first line is special): trimmed <- c( strip(lines[1]), substr(lines[-1], indent + 1, 1000L) ) # Return a single string: string <- paste0(trimmed, collapse = "\n") # Strip off trailing and leading blank lines: gsub("^\n+|\n+$", "", string) } strip <- function(x) gsub("^ +| + $", "", x) roxygen2/R/markdown-escaping.R0000644000176200001440000001573113540250500015765 0ustar liggesusers#' Escape Rd markup, to avoid interpreting it as markdown #' #' This is needed, if we want to stay compatible with #' existing markup, even if markdown mode is switched on. #' Fragile Rd tags (tags that may contain markup that #' can be picked up by the markdown parser), are replaced #' by placeholders. After the markdown to Rd conversion #' is done, the original text is put back in place of the #' placeholders. #' #' The list of protected Rd tags is in `escaped_for_md`. #' #' Some Rd macros are treated specially: #' #' * For `if`, markdown is only allowed in the second argument. #' * For `ifelse` markdown is allowed in the second and third arguments. #' #' See also `roclet-rd.R` for the list of tags that #' uses the markdown-enabled parser. Some tags, e.g. #' `@aliases`, `@backref`, etc. only use the #' standard Roxygen parser. #' #' @param text Input text. Potentially contains Rd and/or #' markdown markup. #' @return For `escape_rd_for_md`: #' A \dQuote{safe} version of the input text, where #' each fragile Rd tag is replaced by a placeholder. The #' original text is added as an attribute for each placeholder. #' @rdname markdown-internals #' @keywords internal escape_rd_for_md <- function(text) { rd_tags <- find_fragile_rd_tags(text, escaped_for_md) protected <- protect_rd_tags(text, rd_tags) double_escape_md(protected) } escaped_for_md <- paste0("\\", c( "acronym", "code", "command", "CRANpkg", "deqn", "doi", "dontrun", "dontshow", "donttest", "email", "env", "eqn", "figure", "file", "if", "ifelse", "kbd", "link", "linkS4class", "method", "newcommand", "option", "out", "packageAuthor", "packageDescription", "packageDESCRIPTION", "packageIndices", "packageMaintainer", "packageTitle", "pkg", "PR", "preformatted", "renewcommand", "S3method", "S4method", "samp", "special", "testonly", "url", "var", "verb" )) #' @description #' It puts back the protected fragile Rd commands into #' the text after the markdown parsing. #' #' @param rd_text The markdown parsed and interpreted text. #' @param esc_text The original escaped text from #' `escape_rd_for_md()`. #' @return For `unescape_rd_for_md`: Rd text. #' @rdname markdown-internals unescape_rd_for_md <- function(rd_text, esc_text) { id <- attr(esc_text, "roxygen-markdown-subst")$id tags <- attr(esc_text, "roxygen-markdown-subst")$tags for (i in seq_len(nrow(tags))) { ph <- paste0(id, "-", i, "-") rd_text <- sub(ph, tags$text[i], rd_text, fixed = TRUE) } rd_text } #' Find all fragile tags (int the supplied list) in the text #' #' Ignore the tags that are embedded into a fragile tag. #' #' @param text Input text, character scalar. #' @param fragile Character vector of fragile tags to find. #' @return Data frame of fragile tags, with columns: #' `tag`, `start`, `end`, `argend`, #' `text`. #' #' @noRd find_fragile_rd_tags <- function(text, fragile) { tags <- find_all_rd_tags(text) ftags <- tags[ tags$tag %in% fragile, ] ## Remove embedded ones keep <- map_lgl(seq_len(nrow(ftags)), function(i) { sum(ftags$start <= ftags$start[i] & ftags$argend >= ftags$argend[i]) == 1 }) ftags <- ftags[keep, ] if (nrow(ftags)) { ftags$text <- str_sub(text, ftags$start, ftags$argend) } ftags } #' Find all (complete) Rd tags in a string #' #' Complete means that we include the argument(s) as well. #' #' @param text Input text, character scalar. #' #' @noRd find_all_rd_tags <- function(text) { text_len <- nchar(text) ## Find the tag names tags <- find_all_tag_names(text) ## Find the end of the argument list for each tag. Note that ## tags might be embedded into the arguments of other tags. tags$argend <- map_int(seq_len(nrow(tags)), function(i) { tag_plus <- str_sub(text, tags$end[i], text_len) findEndOfTag(tag_plus, is_code = FALSE) + tags$end[i] }) tags } #' Find all tag names in a string #' #' Note that we also protect these tags within code, strings #' and comments, for now. We'll see if this causes any #' problems. #' #' @param text Input text, scalar. #' @return Data frame, with columns: `tag`, `start`, #' `end`. #' #' @noRd find_all_tag_names <- function(text) { ## Find the tags without arguments first tag_pos <- str_locate_all(text, "\\\\[a-zA-Z][a-zA-Z0-9]*")[[1]] data.frame( stringsAsFactors = FALSE, tag = str_sub(text, tag_pos[, "start"], tag_pos[, "end"]), as.data.frame(tag_pos) ) } #' Replace fragile Rd tags with placeholders #' #' @param text The text, character scalar. #' @param rd_tags Fragile Rd tags, in a data frame, #' as returned by `find_fragile_rd_tags`. #' @return Text, after the substitution. The original #' text is added as an attribute. #' #' @noRd protect_rd_tags <- function(text, rd_tags) { id <- make_random_string() text <- str_sub_same(text, rd_tags, id) attr(text, "roxygen-markdown-subst") <- list(tags = rd_tags, id = id) text } #' Replace parts of the same string #' #' It assumes that the intervals to be replaced do not #' overlap. Gives an error otherwise. #' #' @param str String scalar. #' @param repl Data frame with columns: `start`, `end`, #' `argend`, `text`. #' @param id Placeholder string. #' @return Input string with the replacements performed. #' Note that all replacements are performed in parallel, #' at least conceptually. #' #' @noRd str_sub_same <- function(str, repl, id) { repl <- repl[ order(repl$start), ] if (is.unsorted(repl$end) || is.unsorted(repl$argend)) { stop("Replacement intervals must not overlap") } for (i in seq_len(nrow(repl))) { ## The trailing - is needed, to distinguish between -1 and -10 new_text <- paste0(id, "-", i, "-") str_sub(str, repl$start[i], repl$argend[i]) <- new_text ## Need to shift other coordinates (we shift everything, ## it is just simpler). inc <- nchar(new_text) - (repl$argend[i] - repl$start[i] + 1) repl$start <- repl$start + inc repl$end <- repl$end + inc repl$argend <- repl$argend + inc } str } #' Make a random string #' #' We use this as the placeholder, to make sure that the #' placeholder does not appear in the text. #' #' @return String scalar #' #' @noRd make_random_string <- function(length = 32) { paste( sample(c(LETTERS, letters, 0:9), length, replace = TRUE), collapse = "" ) } #' Check markdown escaping #' #' This is a regression test for Markdown escaping. #' #' @details #' Each of the following bullets should look the same when rendered: #' #' * Double escapes: \\, \\%, \\$, \\_ #' * Backticks: `\`, `\%`, `\$`, `\_` #' * `\verb{}`: \verb{\\}, \verb{\\%}, \verb{\$}, \verb{\_} #' #' \[ this isn't a link \] #' \\[ neither is this \\] #' #' @param text Input text. #' @return Double-escaped text. #' @keywords internal #' @examples #' "%" # percent #' "\"" # double quote #' '\'' # single quote double_escape_md <- function(text) { text <- gsub("\\", "\\\\", text, fixed = TRUE) # De-dup escaping used to avoid [] creating a link text <- gsub("\\\\[", "\\[", text, fixed = TRUE) text <- gsub("\\\\]", "\\]", text, fixed = TRUE) text } roxygen2/R/markdown.R0000644000176200001440000003004714115752044014204 0ustar liggesusers markdown <- function(text, tag = NULL, sections = FALSE) { tag <- tag %||% list(file = NA, line = NA) tryCatch( expanded_text <- markdown_pass1(text), error = function(e) { message <- paste0( if (!is.na(tag$file)) paste0("[", tag$file, ":", tag$line, "] "), "@", tag$tag, " in inline code: ", e$message ) stop(message, call. = FALSE) } ) escaped_text <- escape_rd_for_md(expanded_text) markdown_pass2(escaped_text, tag = tag, sections = sections) } #' Expand the embedded inline code #' #' @details #' For example this becomes two: `r 1+1`. #' Variables can be set and then reused, within the same #' tag: `r x <- 100; NULL` #' The value of `x` is `r x`. #' #' We have access to the internal functions of the package, e.g. #' since this is _roxygen2_, we can refer to the internal `markdown` #' function, and this is `TRUE`: `r is.function(markdown)`. #' #' To insert the name of the current package: `r packageName()`. #' #' The `iris` data set has `r ncol(iris)` columns: #' `r paste0("``", colnames(iris), "``", collapse = ", ")`. #' #' ```{r} #' # Code block demo #' x + 1 #' ``` #' #' Chunk options: #' #' ```{r results = "hold"} #' names(mtcars) #' nrow(mtcars) #' ``` #' #' Plots: #' #' ```{r test-figure} #' plot(1:10) #' ``` #' #' @param text Input text. #' @return Text with the inline code expanded. A character vector of the #' same length as the input `text`. #' #' @importFrom xml2 xml_ns_strip xml_find_all xml_attr #' @importFrom purrr keep #' #' @keywords internal markdown_pass1 <- function(text) { text <- paste(text, collapse = "\n") mdxml <- xml_ns_strip(md_to_mdxml(text, sourcepos = TRUE)) code_nodes <- xml_find_all(mdxml, ".//code | .//code_block") rcode_nodes <- keep(code_nodes, is_markdown_code_node) if (length(rcode_nodes) == 0) return(text) rcode_pos <- parse_md_pos(map_chr(rcode_nodes, xml_attr, "sourcepos")) out <- eval_code_nodes(rcode_nodes) str_set_all_pos(text, rcode_pos, out, rcode_nodes) } is_markdown_code_node <- function(x) { info <- str_sub(xml_attr(x, "info"), 1, 3) str_sub(xml_text(x), 1, 2) == "r " || (!is.na(info) && info %in% c("{r ", "{r}", "{r,")) } parse_md_pos <- function(text) { nums <- map(strsplit(text, "[:-]"), as.integer) data.frame( start_line = map_int(nums, 1), start_column = map_int(nums, 2), end_line = map_int(nums, 3), end_column = map_int(nums, 4) ) } eval_code_nodes <- function(nodes) { evalenv <- roxy_meta_get("evalenv") # This should only happen in our test cases if (is.null(evalenv)) evalenv <- new.env(parent = baseenv()) map_chr(nodes, eval_code_node, env = evalenv) } #' @importFrom xml2 xml_name #' @importFrom knitr knit opts_chunk eval_code_node <- function(node, env) { if (xml_name(node) == "code") { text <- str_replace(xml_text(node), "^r ", "") paste(eval(parse(text = text), envir = env), collapse = "\n") } else { text <- paste0("```", xml_attr(node, "info"), "\n", xml_text(node), "```\n") opts_chunk$set( error = FALSE, fig.path = "man/figures/", fig.process = function(path) basename(path) ) knit(text = text, quiet = TRUE, envir = env) } } str_set_all_pos <- function(text, pos, value, nodes) { # Cmark has a bug when reporting source positions for multi-line # code tags, and it does not count the indenting space in the # continuation lines. However, the bug might get fixed later, so # for now we just simply error for multi-line inline code. types <- xml_name(nodes) if (any(types == "code" & pos$start_line != pos$end_line)) { stop("multi-line `r ` markup is not supported") } # Need to split the string, because of the potential multi-line # code tags, and then also recode the positions lens <- nchar(str_split(text, fixed("\n"))[[1]]) shifts <- c(0, cumsum(lens + 1L)) shifts <- shifts[-length(shifts)] start <- shifts[pos$start_line] + pos$start_column end <- shifts[pos$end_line] + pos$end_column # Create intervals for the parts we keep keep_start <- c(1, end + 2L) keep_end <- c(start - 2L, nchar(text)) # Now piece them together out <- paste0( substring(text, keep_start, keep_end), c(value, ""), collapse = "" ) attributes(out) <- attributes(text) out } markdown_pass2 <- function(text, tag = NULL, sections = FALSE) { esc_text_linkrefs <- add_linkrefs_to_md(text) mdxml <- md_to_mdxml(esc_text_linkrefs) state <- new.env(parent = emptyenv()) state$tag <- tag state$has_sections <- sections rd <- mdxml_children_to_rd_top(mdxml, state) map_chr(rd, unescape_rd_for_md, text) } md_to_mdxml <- function(x, ...) { md <- commonmark::markdown_xml(x, hardbreaks = TRUE, extensions = "table", ...) xml2::read_xml(md) } mdxml_children_to_rd_top <- function(xml, state) { state$section_tag <- uuid() out <- map_chr(xml_children(xml), mdxml_node_to_rd, state) out <- c(out, mdxml_close_sections(state)) rd <- str_trim(paste0(out, collapse = "")) if (state$has_sections) { secs <- strsplit(rd, state$section_tag, fixed = TRUE)[[1]] %||% "" titles <- c("", state$titles) rd <- structure(str_trim(secs), names = titles) } rd } mdxml_children_to_rd <- function(xml, state) { out <- map_chr(xml_children(xml), mdxml_node_to_rd, state) paste0(out, collapse = "") } #' @importFrom xml2 xml_name xml_type xml_text xml_contents xml_attr xml_children xml_find_all mdxml_node_to_rd <- function(xml, state) { if (!inherits(xml, "xml_node") || ! xml_type(xml) %in% c("text", "element")) { roxy_tag_warning(state$tag, "Internal markdown translation failure") return("") } switch(xml_name(xml), html = , document = , unknown = mdxml_children_to_rd(xml, state), paragraph = paste0("\n\n", mdxml_children_to_rd(xml, state)), text = escape_comment(xml_text(xml)), emph = paste0("\\emph{", mdxml_children_to_rd(xml, state), "}"), strong = paste0("\\strong{", mdxml_children_to_rd(xml, state), "}"), softbreak = mdxml_break(state), linebreak = mdxml_break(state), code = mdxml_code(xml, state), code_block = mdxml_code_block(xml, state), table = mdxml_table(xml, state), list = mdxml_list(xml, state), item = mdxml_item(xml, state), link = mdxml_link(xml, state), image = mdxml_image(xml), heading = mdxml_heading(xml, state), # Only supported when including Rmds html_block = mdxml_html_block(xml, state), html_inline = mdxml_html_inline(xml, state), # Not supported block_quote = mdxml_unsupported(xml, state$tag, "block quotes"), hrule = mdxml_unsupported(xml, state$tag, "horizontal rules"), mdxml_unknown(xml, state$tag) ) } mdxml_unknown <- function(xml, tag) { roxy_tag_warning(tag, "Unknown xml node: ", xml_name(xml)) escape_comment(xml_text(xml)) } mdxml_unsupported <- function(xml, tag, feature) { roxy_tag_warning(tag, "Use of ", feature, " is not currently supported") escape_comment(xml_text(xml)) } mdxml_break <- function(state) { if (isTRUE(state$inlink)) " " else "\n" } mdxml_code <- function(xml, tag) { code <- xml_text(xml) # See escaping details at # https://cran.rstudio.com/doc/manuals/r-devel/R-exts.html#Insertions if (can_parse(code) || code %in% special) { paste0("\\code{", gsub("%", "\\\\%", code), "}") } else { paste0("\\verb{", escape_verb(code), "}") } } special <- c( "-", ":", "::", ":::", "!", "!=", "(", "[", "[[", "@", "*", "/", "&", "&&", "%*%", "%/%", "%%", "%in%", "%o%", "%x%", "^", "+", "<", "<=", "=", "==", ">", ">=", "|", "||", "~", "$", "for", "function", "if", "repeat", "while" ) mdxml_code_block <- function(xml, state) { info <- xml_attr(xml, "info")[1] if (is.na(info) || nchar(info[1]) == 0) info <- NA_character_ paste0( if (!is.na(info)) paste0("\\if{html}{\\out{
}}"), "\\preformatted{", escape_verb(xml_text(xml)), "}", if (!is.na(info)) "\\if{html}{\\out{
}}" ) } can_parse <- function(x) { tryCatch({ parse_expr(x) TRUE }, error = function(x) FALSE) } escape_verb <- function(x) { # Don't need to escape \\ because that's already handled in double_escape_md() x <- gsub("%", "\\%", x, fixed = TRUE) x <- gsub("{", "\\{", x, fixed = TRUE) x <- gsub("}", "\\}", x, fixed = TRUE) x } mdxml_table <- function(xml, state) { head <- xml_children(xml)[[1]] align <- substr(xml_attr(xml_children(head), "align", default = "left"), 1, 1) rows <- xml_find_all(xml, "d1:table_row|d1:table_header") cells <- map(rows, xml_find_all, "d1:table_cell") cells_rd <- map(cells, ~ map(.x, mdxml_children_to_rd, state = state)) rows_rd <- map_chr(cells_rd, paste0, collapse = " \\tab ") paste0("\\tabular{", paste(align, collapse = ""), "}{\n", paste(" ", rows_rd, "\\cr\n", collapse = ""), "}\n") } # A list, either bulleted or numbered mdxml_list <- function(xml, state) { type <- xml_attr(xml, "type") if (type == "ordered") { paste0("\n\\enumerate{", mdxml_children_to_rd(xml, state), "\n}") } else { paste0("\n\\itemize{", mdxml_children_to_rd(xml, state), "\n}") } } mdxml_item <- function(xml, state) { ## A single item within a list. We remove the first paragraph ## tag, to avoid an empty line at the beginning of the first item. children <- xml_children(xml) if (length(children) == 0) { cnts <- "" } else if (xml_name(children[[1]]) == "paragraph") { cnts <- paste0( mdxml_children_to_rd(children[[1]], state), paste0(map_chr(children[-1], mdxml_node_to_rd, state), collapse = "") ) } else { cnts <- mdxml_children_to_rd(xml, state) } paste0("\n\\item ", cnts) } mdxml_link <- function(xml, state) { ## Hyperlink, this can also be a link to a function dest <- xml_attr(xml, "destination") contents <- xml_contents(xml) link <- parse_link(dest, contents, state) if (!is.null(link)) { paste0(link, collapse = "") } else if (dest == "" || dest == xml_text(xml)) { paste0("\\url{", escape_comment(xml_text(xml)), "}") } else { paste0( "\\href{", escape_comment(dest), "}", "{", mdxml_link_text(contents, state), "}" ) } } mdxml_link_text <- function(xml_contents, state) { # Newlines in markdown get converted to softbreaks/linebreaks by # markdown_xml(), which then get interpreted as empty strings by # xml_text(). So we preserve newlines as spaces. inlink <- state$inlink on.exit(state$inlink <- inlink, add = TRUE) state$inlink <- TRUE text <- map_chr(xml_contents, mdxml_node_to_rd, state) paste0(text, collapse = "") } mdxml_image = function(xml) { dest <- xml_attr(xml, "destination") title <- xml_attr(xml, "title") paste0( "\\figure{", dest, "}", if (nchar(title)) paste0("{", title, "}") ) } escape_comment <- function(x) { gsub("%", "\\%", x, fixed = TRUE) } mdxml_heading <- function(xml, state) { level <- xml_attr(xml, "level") if (! state$has_sections && level == 1) { return(mdxml_unsupported(xml, state$tag, "level 1 markdown headings")) } txt <- map_chr(xml_contents(xml), mdxml_node_to_rd, state) if (level == 1) { state$titles <- c(state$titles, paste(txt, collapse = "")) } head <- paste0( mdxml_close_sections(state, level), "\n", if (level == 1) state$section_tag else "\\subsection{", if (level > 1) paste(txt, collapse = ""), if (level > 1) "}{" ) state$section <- c(state$section, level) head } mdxml_html_block <- function(xml, state) { if (state$tag$tag != "includeRmd") { return(mdxml_unsupported(xml, state$tag, "HTML blocks")) } paste0( "\\if{html}{\\out{\n", gsub("}", "\\}", xml_text(xml), fixed = TRUE), "}}\n" ) } mdxml_html_inline <- function(xml, state) { if (state$tag$tag != "includeRmd") { return(mdxml_unsupported(xml, state$tag, "inline HTML")) } paste0( "\\if{html}{\\out{", gsub("}", "\\}", xml_text(xml), fixed = TRUE), "}}" ) } #' @importFrom utils head tail mdxml_close_sections <- function(state, upto = 1L) { hmy <- 0L upto <- max(upto, 2L) while (length(state$section) && tail(state$section, 1) >= upto) { hmy <- hmy + 1L state$section <- head(state$section, -1L) } paste0(rep("\n}\n", hmy), collapse = "") } roxygen2/R/rd-describe-in.R0000644000176200001440000000654013544473137015162 0ustar liggesusers#' @export roxy_tag_parse.roxy_tag_describeIn <- function(x) { tag_name_description(x) } topic_add_describe_in <- function(topic, block, env) { tag <- block_get_tag(block, "describeIn") if (is.null(tag)) { return() } if (is.null(block$object)) { roxy_tag_warning(tag, "must be used with an object") return() } if (block_has_tags(block, "name")) { roxy_tag_warning(tag, "can not be used with @name") return() } if (block_has_tags(block, "rdname")) { roxy_tag_warning(tag, "can not be used with @rdname") return() } dest <- find_object(tag$val$name, env) label <- build_label(block$object, dest, block) if (is.null(label)) return() topic$add(rd_section_minidesc( label$type, label$label, tag$val$description )) dest$topic } # Field ------------------------------------------------------------------- rd_section_minidesc <- function(type, label, desc) { stopifnot(is.character(type), is.character(label), is.character(desc)) stopifnot(length(desc) == length(label)) rd_section("minidesc", list(type = type, desc = desc, label = label)) } #' @export merge.rd_section_minidesc <- function(x, y, ...) { stopifnot(identical(class(x), class(y))) stopifnot(identical(x$value$type, y$value$type)) rd_section_minidesc( x$value$type, label = c(x$value$label, y$value$label), desc = c(x$value$desc, y$value$desc) ) } #' @export format.rd_section_minidesc <- function(x, ...) { title <- switch(x$value$type, generic = "Methods (by class)", class = "Methods (by generic)", "function" = "Functions" ) paste0( "\\section{", title, "}{\n", "\\itemize{\n", paste0("\\item \\code{", escape(x$value$label), "}: ", x$value$desc, collapse = "\n\n"), "\n}}\n" ) } # Helpers ----------------------------------------------------------------- # Imperfect: # * will fail with S3 methods that need manual disambiguation (rare) # * can't use if @name overridden, but then you could just the use alias find_object <- function(name, env) { if (methods::isClass(name, where = env)) { object(methods::getClass(name, where = env), NULL, "s4class") } else if (exists(name, envir = env)) { object_from_name(name, env, NULL) } else { object(NULL, name, "data") } } build_label <- function(src, dest, block) { src_type <- class(src)[1] dest_type <- class(dest)[1] if (dest_type == "s4class" && src_type == "s4method") { # Label S4 methods in class with their generic type <- "class" label <- as.character(src$value@generic) } else if (dest_type == "s4generic" && src_type == "s4method") { # Label S4 methods in generic with their signature type <- "generic" sig <- src$value@defined if (length(sig) == 1) { label <- as.character(sig) } else { label <- paste0(names(sig), " = ", sig, collapse = ",") } } else if (dest_type == "function" && src_type == "s3method") { # Assuming you document S3 methods in the class constructor type <- "class" label <- attr(src$value, "s3method")[1] } else if (dest_type == "s3generic" && src_type == "s3method") { # Label S3 methods in generic with their class type <- "generic" label <- attr(src$value, "s3method")[2] } else { # Otherwise just fallback to function + topic type <- "function" label <- src$topic } list(type = type, label = label) } roxygen2/R/vignette.R0000644000176200001440000000423113560327401014201 0ustar liggesusers#' Re-build outdated vignettes. #' #' This rebuilds outdated vignettes with [tools::buildVignette]. #' By default, it will rebuild all vignettes if the source file is newer than #' the output pdf or html. (This means it will automatically re-build the #' vignette if you change the vignette source, but _not_ when you #' change the R code). If you want finer control, add a Makefile to #' `vignettes/` and roxygen2 will use that instead. #' #' To prevent RStudio from re-building the vignettes again when checking #' your package, add `--no-build-vignettes` to the "Build Source Package" #' field in your project options. #' #' @family roclets #' @export vignette_roclet <- function() { roclet("vignette") } #' @export roclet_process.roclet_vignette <- function(x, blocks, env, base_path) { } #' @export roclet_output.roclet_vignette <- function(x, results, base_path, ...) { vign_update_all(base_path) } # Determine if a vignette is out-of-date; i.e. it has no related files, or # any of the related files are older than the vignette. vign_outdated <- function(vign) { vign <- normalizePath(vign, mustWork = TRUE) name <- tools::file_path_sans_ext(basename(vign)) # Currently, the final product of a vignette can only be pdf or html related <- dir(dirname(vign), pattern = paste0(name, "\\.(pdf|html)$"), full.names = TRUE) related <- setdiff(related, vign) length(related) == 0 || mtime(vign) > mtime(related) } vign_update <- function(vign) { if (!vign_outdated(vign)) return(FALSE) message("Rebuilding ", basename(vign)) output <- tools::buildVignette(vign, dirname(vign), tangle = FALSE, clean = FALSE) TRUE } vign_update_all <- function(pkg_path) { vig_path <- file.path(pkg_path, "vignettes") if (!file.exists(vig_path)) return() if (file.exists(file.path(vig_path, "Makefile"))) { message("Updating vignettes with make") make <- Sys.getenv("MAKE", "make") old <- setwd(vig_path) on.exit(setwd(old), add = TRUE) system(make) } else { message("Updating vignettes") vigs <- tools::pkgVignettes(dir = pkg_path) invisible(map_lgl(vigs$docs, vign_update)) } } mtime <- function(x) { max(file.info(x)$mtime) } roxygen2/NEWS.md0000644000176200001440000013556714115763536013161 0ustar liggesusers# roxygen2 7.1.2 * The new `@examplesIf` tag can be used to create conditional examples. These examples only run if a specified condition holds (#962). * roxygen2 is now licensed as MIT (#1163). * Bug fix for upcoming stringr 2.0.0 release. * Code blocks with language now add `sourceCode` to the generated div; this makes syntax highlighting more consistent across downlit/pandoc/knitr/roxygen2. * Percent signs in markdown link targets, e.g. `[text](https://foo/ba%20r)` are now handled correctly (#1209). # roxygen2 7.1.1 * When processing cross package markdown links (e.g. `[pkg::fun()]`), roxygen2 now looks up the file it needs to link to, instead of linking to the topic, to avoid "Non-file package-anchored links" `R CMD check` warnings. * R6 methods and re-exported functions are always sorted in the C locale; this ensures they're always sorted the same way in every environment (#1077). * roxygen2 now supports inline markdown code and code chunks inside Rd tags. In particular in `\out{}` (#1115). # roxygen2 7.1.0 ## New features * roxygen2 now supports inline markdown code and also code chunks, using the same notation as the knitr package. For example: ```R #' This manual was generated at: `r Sys.time()`. #' ... #' `mtcars` is a data frame with `r ncol(mtcars)` columns, here #' is a summary of them: #' #' ```{r} #' summary(mtcars) #' ``` ``` See `vignette("rd-formatting")` for details. * roxygen2 now keeps using Windows (CR LF) line endings for files that already have CR LF line endings, and uses LF for new files (#989). ## Minor improvements and bug fixes * Auto-generated package documentation can now handle author ORCID comments containing full url (#1040). * Hyperlinks to R6 methods are also added in the PDF manual (#1006). * Empty annotations (alternate text) for figures added via markdown are now omitted. This caused issues when generating pkgdown web sites (#1051). * Roxygen metadata can now have a `packages` element, giving a character vector of package names to load. This makes it easier to use extension package that provide new tags for existing roclets (#1013). See `?load_options` for more details. ```yaml Roxygen: list(markdown = TRUE, packages = "roxygenlabs") ``` * `@evalNamespace()` works again (#1022). * `@description NULL` and `@details NULL` no longer fail; instead, these tags are ignored, except for `@description NULL` in package level documentation, where it can be used to suppress the auto-generated Description section (#1008). * Multiple `@format` tags are now combined (#1015). * The warning for `@section` titles spanning multiple lines now includes a hint that you're missing a colon (@maelle, #994). * Can now document objects created with `delayedAssign()` by forcing evaluation at documentation time (#1041) # roxygen2 7.0.2 * `\example{}` escaping has been improved (again!) so that special escapes within strings are correctly escaped (#990). # roxygen2 7.0.1 * `@includeRmd` has now an optional second argument, the top level section the included file will go to. It defaults to the details section (#970). Code chunks are now evaluated in a child of the global environment (#972). * `@inheritParams` does a better job of munging links. Links of the form `\link[=topic]{text}` are now automatically converted to `\link[pkg:topic]{text}` when inherited from other packages (#979). Internal `has_topic()` helper has a better implementation; this means that links should no longer be munged unnecessarily (#973). * `\example{}` escaping has been considerably simplified (#967), and is now documented in `escape_example()`. * In `\usage{}`, S3/S4 methods are no longer double-escaped (#976). * Markdown tables with cells that contain multiple elements (e.g. text and code) are now rendered correctly (#985). * Markdown code blocks containing operators and other special syntax (e.g. `function`, `if`, `+`) now converted to `\code{}` not `\verb{}` (#971). # roxygen2 7.0.0 ## New features ### New tags * `@includeRmd {path.Rmd}` converts an `.Rmd`/`.md` file to `.Rd` and includes it in the manual page. This allows sharing text between vignettes, `README.Rmd`, and the documentation. See `vignette("rd")` for details (#902). * `@order {n}` tag controls the order in which blocks are processed. You can use it to override the usual ordering which proceeds from the top of each file to the bottom. `@order 1` will be processed before `@order 2`, and before any blocks that don't have an explicit order set (#863). * `@exportS3Method` tag allows you to generate `S3method()` namespace directives (note the different in capitalisation) (#796). Its primary use is for "delayed" method registration, which allows you to define methods for generics found in suggested packages (available in R 3.6 and greater). For example, ```R #' @exportS3Method package::generic generic.foo <- function(x, ...) { } ``` will generate ``` S3method(package::generic, foo) ``` (See [`vctrs::s3_register()`](https://vctrs.r-lib.org/reference/s3_register.html) you need a version that works for earlier versions of R). It also has a two argument form allows you generate arbitrary `S3method()` directives: ```R #' @exportS3Method generic class NULL ``` ``` S3method(generic, class) ``` * New `@returns` is an alias for `@return` (#952). ### R6 roxygen2 can now document R6 classes (#922). See `vignette("rd")` for details. ### Markdown improvements * Rd comments (`%`) are now automatically escaped. You will need to replace any existing uses of `\%` with `%` (#879). * Markdown headings are supported in tags like `@description`, `@details`, and `@return` (#907, #908). Level 1 headings create a new top-level `\section{}`. Level 2 headings and below create nested `\subsections{}`. * Markdown tables are converted to a `\tabular{}` macro (#290). roxygen2 supports the [GFM table syntax](https://github.github.com/gfm/#tables-extension-) which looks like this: ```md | foo | bar | | --- | --- | | baz | bim | ``` * Markdown code (``` `foofy` ```) is converted to to either `\code{}` or `\verb{}`, depending on whether it not it parses as R code. This better matches the description of `\code{}` and `\verb{}` macros, solves a certain class of escaping problems, and should make it easier to include arbitrary "code" snippets in documentation without causing Rd failures (#654). * Markdown links can now contain formatting, e.g. `[*mean*][mean]` will now generate `\link[=mean]{\emph{mean}}`. * Use of unsupported markdown features (e.g. blockquotes, inline HTML, and horizontal rules) generates informative error messages (#804). ### Default usage * The default formatting for function usage that spans multiple lines has now changed. Previously, the usage was wrapped to produce the smallest number of lines, e.g.: ```R parse_package(path = ".", env = env_package(path), registry = default_tags(), global_options = list()) ``` Now it is wrapped so that each argument gets its own line (#820): ```R parse_package( path = ".", env = env_package(path), registry = default_tags(), global_options = list() ) ``` If you prefer the old behaviour you can put the following in your `DESCRIPTION`: ``` Roxygen: list(old_usage = TRUE) ``` ### Code loading roxygen2 now provides three strategies for loading your code (#822): * `load_pkgload()`, the default, uses [pkgload](https://github.com/r-lib/pkgload). Compared to the previous release, this now automatically recompiles your package if needed. * `load_source()` attaches required packages and `source()`s all files in `R/`. This is a cruder simulation of package loading than pkgload (and e.g. is unreliable if you use S4 extensively), but it does not require that the package be compiled. Use if the default strategy (used in roxygen2 6.1.0 and above) causes you grief. * `load_installed()` assumes you have installed the package. This is best used as part of a bigger automated workflow. You can override the default either by calling (e.g.) `roxygenise(load_code = "source"))` or by setting the `load` option in your DESCRIPTION: `Roxygen: list(load = "source")`. ### Options * As well as storing roxygen options in the `Roxygen` field of the `DESCRIPTION` you can now also store them in `man/roxygen/meta.R` (#889). The evaluation of this file should produce a named list that maps option names to values. * roxygen now also looks for templates in `man/roxygen/templates` (#888). * New `rd_family_title` option: this should be a named list, and is used to overrides the default "Other family: " prefix that `@family` generates. For example, to override the prefix generated by `@family foo` place `rd_family_title <- list(foo = "Custom prefix: ")` in `man/roxygen/meta.R` (#830, @kevinushey). ## Breaking changes * Rd comments (`%`) are automatically escaped in markdown formatted text. This is a backward incompatible change because you will need to replace existing uses of `\%` with `%` (#879). * Using `@docType package` no longer automatically adds `-name`. Instead document `_PACKAGE` to get all the defaults for package documentation, or use `@name` to override the default file name. * `@S3method` has been removed. It was deprecated in roxygen2 4.0.0 released 2014-05-02, over 5 years ago. * Using the old `wrap` option will now trigger a warning, as hasn't worked for quite some time. Suppress the error by deleting the option from your `DESCRIPTION`. ### Extending roxygen2 The process for extending roxygen2 with new tags and new roclets has been completely overhauled, and is now documented in `vignette("extending")`. If you're one of the few people who have written a roxygen2 extension, this will break your code - but the documentation, object structure, and print methods are now so much better that I hope it's not too annoying! Because this interface is now documented, it will not change in the future without warning and a deprecation cycle. If you have previously made a new roclet, the major changes are: * The previously internal data structures used to represent blocks and tags have been overhauled. They are now documented and stable. See `roxy_block()` and `roxy_tag()` for details. * `roclet_tags()` is no longer used; instead define a `roxy_tag_parse()` method. For example, if you create a new `@mytag` tag, it will generate a class of `roxy_tag_mytag`, and will be parsed by `roxy_tag_parse.roxy_tag_mytag()` method. The method should return a new `roxy_tag()` object with the `val` field set. This means that the `registry` argument is no longer needed and has been removed. * `rd_section()` and `roxy_tag_rd()` are now exported so that you can more easily extend `rd_roclet()` with your own tags that generate output in `.Rd` files. * `global_options` is no longer passed to all roclet methods. Instead, use `roxy_meta_get()` to retrieve values stored in the options (#918). * `tag_two_part()` and `tag_words()` are now simple functions, not function factories. * `tag_markdown_restricted()` has been removed because it did exactly the same thing as `tag_markdown()`. A big thanks goes to @mikldk for starting on the vignette and motivating me to make the extension process much more pleasant (#882). ## Bug fixes and minor improvements * Empty roxygen2 lines at the start of a block are now silently removed (#710). * Whitespace is automatically trimmed off the `RoxygenNote` field when comparing the installed version of roxygen2 to the version used to generate the documentation (#802). * Files generated on Windows systems now retain their existing line endings, or use unix-style line endings for new files (@jonthegeek, @jimhester, #840). * roxygen2 now recognises fully qualified S4 functions like `methods::setGeneric()`, `methods::setClass()` and `methods::setMethod()` (#880). * Package documentation now converts ORCIDs into a useful link (#721). The package logo (if found at `man/images/logo.png`) is now scaled to 120px wide (@peterdesmet, #834). * Documenting an S4 method that has a `.local()` wrapper no longer fails with an obscure error message (#847). * Functions documented in `reexports` are now sorted alphabetically by package (#765). * `@describeIn` can now be used with any combination of function types (#666, #848). * `@description` and `@detail` tags are automatically generated from the leading description block, and now have correct line numbers (#917). * `@example` and `@examples` are interwoven in the order in which they appear (#868). * In `@examples`, escaped `'` and `"` in strings are no longer doubly escaped (#873). * `@family` automatically adds `()` when linking to functions (#815), and print each link on its own line (to improve diffs). * When `@inherit`ing from external documentation, `\link{foo}` links are automatically transformed to `\link{package}{foo}` so that they work in the generated documentation (#635). `\href{}` links in external inherited are now inserted correctly (without additional `{}`) (#778). * `@inherit`ing a a function with no arguments no longer throws a confusing error message (#898). * `@inheritDotParams` automatically ignores arguments that can't be inherited through `...` because they are used by the current function (@mjskay, #885). * `@inheritDotParams` includes link to function and wraps parameters in `\code{}` (@halldc, #842). * `@inheritDotParams` can be repeated to inherit dot docs from multiple functions (@gustavdelius, #767). * `@inheritDotParams` avoids multiple `...` arguments (@gustavdelius, #857). * `@inheritParams` ignores leading dots when comparing argument names (#862). * `@inheritParams` warns if there are no parameters that require documentation (#836). * `@param` containing only whitespce gives a clear warning message (#869). * Multiple `@usage` statements in a single block now generate a warning. Previously, the first was used without a warning. # roxygen2 6.1.1 * Now specifically imports recent version of desc package (>= 1.2.0) to fix various parsing issues (@crsh, #773, #777, #779). Multi-line DESCRIPTION collate directives now correctly parsed on windows (@brodieG, #790). * `roxygenise()` no longer recompiles packages containing src code (#784). * `roxygenise()` now stops with an informative error message when run in a directory that's not the package root (@mikmart, #704). # roxygen2 6.1.0 ## New features * The `NAMESPACE` roclet now works in two passes - it first generates the `NAMESPACE` containing only import directives because this can be generated without evaluating the code in the package. This alleviates a problem where it was previously possible to get into a state that you could only get out of by carefully editing the `NAMESPACE` by hand (#372). * `@evalRd foo()` evaluates `foo()` defined in the package namespace and inserts the results into the current block (#645). The code should return a character vector with one entry for each line (and they should not start with `#'`). There are two small limitations to the current implementation: 1. The generated roxygen will not affect the `@md`/`@noMd` status 2. `@evalRd` does not work inside templates. * `@evalNamespace` does for `NAMESPACE` what `@evalRd` does for Rd files: you give it R code that produces a literal entry in `NAMESPACE` when run. This should make it easier to export functions that are generated by other functions in your package (#531, @egnha). * `@inherits` can now inherit examples (#588). * `vignette("rd")` received a thorough updating for current best-practices. The vignette still needs more work so pull requests are greatly appreciated (#650). * `roxygenise()` uses `pkgload::load_all()` instead of a home grown solution to simulate package loading (this is needed because roxygen2 uses run-time information to generate the documentation). This should reduce S4 related problems and ensures that `devtools::document()` and `roxygenise()` always have exactly the same behaviour (#568, #595). * If an inherited section cannot be found, the warning contains the help page from which that section was requested (#732, @krlmlr). * roxygen2 now always reads and writes using UTF-8 encoding. If used with a package that does not have `Encoding: UTF-8` in the DESCRIPTION, you'll now get a warning (#564, #592). ## Extension API * Roxygen blocks now have an official structure as encoded in `roxy_block()`. It is a named list containing the tags with attributes providing other metadata. * The `parsed` argument to `roclet_process()` have been replaced with separate `blocks` and `env` arguments. * New `roclet_preprocess()` generic makes it possible for roclets to perform actions before code is evaluated. * `parse_package()`, `parse_file()` and `parse_code()` provide an exported API that allows you to use roxygen's parsing code independently of creating roclets. ## Minor improvements and bug fixes * All tags (including `@alias`) are now de-duplicated and consistently sorted. This reduces spurious diffs (#586, @flying-sheep). * `@concept` now generates one `\concept` per tag (#611). * The default `@description` (i.e. the title) is now added much later in the process. That means that `@inherit description` now works when you have specified a title for the inheritor (#629) and the default description is slightly nicer when merging multiple blocks. * `@family` automatically adds its value to concepts (#611). * `@inherits`: The mechanism for extracting inherited Rd does a better job of preserving escapes (#624) * Empty `.Rbuildignore` now handled correctly (#576). * Stricter regular expression ensures only files ending with `.R` or `.r` are parsed for roxygen comments (#625). * Objects with names starting with a dot are now by default documented in files with prefix 'dot-'. * Roclets can now access global options as designed. This allows templates to use markdown formatting if set globally (#594). * You can now autogenerate package documentation even if you don't have `Authors@R` (#606). * Multiple given and/or family names are now supported in the `Authors@R` field of the DESCRIPTION file (#672, @sgibb). * If a package logo exists (`man/figures/logo.png`) it will be automatically included in generated package docs (#609). * Usage for data objects now correctly generated, avoiding double escaping other components of usage (#562). * Improvements to markdown translation: * Code in link text is now properly rendered as code (#620, @egnha). * Whitespace between words in link text is now preserved as single space for links of the form `[text][fcn]` and `[text](URL)` (#628, #754, #760, @egnha and @jennybc). * `%` in inline code (#640), code blocks (@nteetor, #699) and links (#724) is now automatically escaped. * Parsing of markdown links has been tweaked to reduce false positives (#555). If you still get a false positive, you can now put `\\` in front of the `[` to avoid it being converted to a link (#720). Links can no longer be followed by `{` to avoid spurious matches to Rd commands like `\Sexpr{}`. * Unsupported markdown features now generate a mildly helpful warning instead of throwing an utterly useless error (#560). * `person()` now supports all [MARC Relator](https://www.loc.gov/marc/relators/relaterm.html) role codes (#662, @publicus). * `topic_add_usage()` now outputs formatted "Usage" section with max width of 80 characters thanks to a now more flexible `wrap_string()` (@JoshOBrien, #719). # roxygen2 6.0.1 * Allowing empty lines in .Rbuildignore. Previously, empty lines caused all files to be ignored. (#572, @jakob-r) * Automatically generating a usage section for an infix function containing "<-" no longer removes "<-" from the function name (#554). # roxygen2 6.0.0 ## Markdown * Most fields can now be written using Markdown markup instead of the traditional Rd language. You can turn on Markdown globally by adding `Roxygen: list(markdown = TRUE)` to `DESCRIPTION`. The `@md` / `@noMd` tags turn Markdown parsing on / off for the given block. See `vignette("markdown")` for more details (#364, #431, #499, #506, #507), by @gaborcsardi ## Improved inheritance * New `@inheritDotParams` allows you to automatically generate parameter documentation for `...` for the common case where you pass `...` on to another function (#512). Because you often override some arguments, it comes with a flexible specification for argument selection: * `@inheritDotParams foo` takes all parameters from `foo()` * `@inheritDotParams foo a b e:h` takes parameters `a`, `b`, and all parameters between `e` and `h` * `@inheritDotParams foo -x -y` takes all parameters except for `x` and `y`. The documentation generated is similar to the style used in `?plot` and will eventually be incorporated in to RStudio's autocomplete. * New `@inherit` generalises `@inheritParams`, and allows to you inherit parameters, return, references, title, description, details, sections, and seealso. The default `@inherit my_fun` will inherit all, you can document an object entirely by specifying only the `@inherit` tag. Alternatively, you can select specific tags to inherit with `@inherit my_fun return params` (#384). * New `@inheritSection fun title` allows you to inherit the contents of a single section from another topic (#513). * `@inheritParams` now works recursively, so that you can inherit parameters from a function that inherited its parameters from somewhere else. It also better handles `\dots` as an alias for `...` (#504). ## Minor improvements and bug fixes ### Tags * `@aliases` are no longer sorted alphabetically, but instead match the order of their usage. This gives you more control in pkgdown. * `@describeIn` now escapes special characters in function names (#450). * `@family` see alsos are added in the same order they appear, not alphabetically (#315). Fixed an issue where `.`s were sometimes added between words within a `@family` tag (#477, @kevinushey). * `@author` is rendered after `@seealso`. * `@example` gives a nice warning message if you accidentally use it instead of `@examples` (#494). Multiple `@examples` sections are merged (#472, @krlmlr). * Roxygen will no longer write out topics that don't have a name or title, and will instead generate a warning. This makes it easier to detect if you've accidentally used `@rdname` with an incorrect value (#474). ### S3 * Non-primitive, internal S3 generics (e.g. 'rbind', 'cbind') are now properly detected as S3 generics. (#488, @kevinushey) * Ensure that `functions` with S3 class are still treated as functions (#455). * S3 method declarations via `R.methodS3::setMethodS3()` and function declarations via `R.oo::setConstructorS3()` are now supported (@HenrikBengtsson, #525). ### S4 * You can now document `setClassUnion()`s (#514). * The default alias for S4 method now re-adds trailing ANY signatures that are sometimes dropped (#460). * Back references are now wrapped over multiple lines, if long (#493, @LiNk-NY). ### Other * `"_PACKAGE"` documentation now generates a default `@seealso` combining the `URL` and `BugReport` fields, and a default `@author` field generated from the `Authors@R` field (#527). It now works from `roxygenise()`; before it only worked from `devtools::document()` (#439, @krlmlr). * Manually created `NAMESPACE` or documentation files are never overwritten, even if using `roxygen2` for the first time (@krlmlr, #436). * Changes to DESCRIPTION (i.e. `Collate:` and `RoxygenNote`) now use the desc package. This will minimise spurious changes (#430). * `default_data_format()` has been renamed to `object_format()`. * New `roclet_find()` provides a more flexible way to specify roclets: as roclet name (e.g. "rd_roclet"), in an package ("foo::roclet_bar"), or with options ("foo::roclet_bar(baz = TRUE)"). * The usage of replacement functions uses non-breaking spaces so that `<-` will never get put on its own line (#484). * Roxygen now parses nonASCII documentation correctly (as long as UTF-8 encoded or specified Encoding in DESCRIPTION) (#532, @shrektan), and ignores files listed in `.Rbuildignore` (#446, @fmichonneau). ## Extending roxygen2 * Deprecated `register.preref.parser()` and `register.preref.parsers()` have been removed. `register_tags()` has also been removed in favour of a new `roclet_tags()` generic. * `roclet()` (the constructor), `roclet_tags()`, `roclet_process()` `roclet_output()`, `roc_clean()` and now exported making it possible to create roclets in other packages. Helper functions `roxy_tag()` and `roxy_tag_warning()` are also exported. * `new_roclet()` is no longer exported - use `roclet()` instead. # roxygen2 5.0.1 * Use `ls()`, not `names()` to list elements of environment: fixes R 3.1.0 incompatibility (#422, @kevinushey). * `@export` again allows trailing new line (#415). * Fixed bug in `@noRd`, where usage would cause error (#418). # roxygen2 5.0.0 ## New features * Roxygen now records its version in a single place: the `RoxygenNote` field in the `DESCRIPTION` (#338). This will be the last time an roxygen2 upgrade changes every file in `man/`. * You can now easily re-export functions that you've imported from another package: ```R #' @export magrittr::`%>%` ``` All imported-and-re-exported functions will be documented in the same file (`rexports.Rd`), containing a brief description and links to the original documentation (#376). * You can more easily generate package documentation by documenting the special string "_PACKAGE" (@krlmlr, #349): ```R #' @details Details "_PACKAGE" ``` The title and description will be automatically filled in from the `DESCRIPTION`. * New tags `@rawRd` and `@rawNamespace` allow you to insert raw (unescaped) in Rd and the `NAMESPACE` (this is useful for conditional imports). `@evalRd()` is similar, but instead of literal Rd, you give it R code that produces literal Rd code when run. This should make it easier to experiment with new types of output (#385). * Roxygen2 now parses the source code files in the order specified in the `Collate` field in `DESCRIPTION`. This improves the ordering of the generated documentation when using `@describeIn` and/or `@rdname` split across several `.R` files, as often happens when working with S4 (#323, #324). ## Minor features and bug fixes * The contents of documented functions are now also parsed for roxygen comments. This allows, e.g., documenting a parameter's type close to where this type is checked, or documenting implementation details close to the source, and simplifies future extensions such as the documentation of R6 classes (#397, @krlmlr). * Data objects get a simpler default `@format` that describes only the object's class and dimensions. The former default, generated by generated by `str()`, didn't usually produce useful output and was quite slow. The new S3 generic `default_data_format()` generates the format and can be overridden to generate a custom format (#410, @krlmlr). * The roxygen parsers has been completely rewritten in C++ (#295). This gives a nice performance boost and gives: * Better error messages: you now get the exact the line number of the tag, not just the start of the block. * The parser has been simplified a little: tags now must always start on a new line. This is recommended practice anyway, and it means that escaping inline `@` (with `@@`) is now optional. (#235) * Unknown tags now emit a warning, rather than an error. * `@examples` no longer complains about non-matching braces inside strings (#329). * `@family` now cross-links each manual page only once, instead of linking to all aliases (@gaborcsardi, #283, #367). * The special `@include` parser has also been rewritten in C++, giving a performance boost for larger packages (#401). This is particularly important because it's also called from `devtools::load_all()`. Additionally, a space before `@include` is no longer necessary (@krlmlr, #342). * `@inheritParams foo::bar` ensures that `%` remains escaped (#313). * If you document multiple arguments with one `@param`, (e.g. `@param a,b,c`) each parameter will get a space after it so it can be wrapped in the generated Rd file (#373). * `@section`s with identical titles are now merged together, just like `@description` and `@details`. This is useful in conjunction with the `@rdname` tag. (@krlmlr, #300). * Automatic `@usage` is now correctly generated for functions with string arguments containing `"\""` (#265). * `load_options()` is now exported so `devtools::document()` doesn't have to run `update_collate()` twice (#395). * `update_collate()` only rewrites the `Collate` entry in the DESCRIPTION file when it changes (#325, #723). * An empty `NAMESPACE` file is written if it is maintained by `roxygen2` (@krlmlr, #348). * Data that is not lazy-loaded can be documented (@krlmlr, #390). ## Internal changes * `register.preref.parser()` and `register.preref.parsers()` have been deprecated - please use `register_tags()` instead. * Parser callbacks registered with `register_tags()` are now called for fields parsed from the "introduction" (the text before the first tag) (@gaborcsardi, #370). # roxygen2 4.1.1 * Formatting of the `Authors@R` field in the DESCRIPTION file is now retained (@jranke, #330). * The collate roclet falls back to `base::strwrap()` when generating the collate field. This makes roxygen2 compatible with the next version of stringr. * New "vignette" roclet. This vignette automatically rebuilds all out of date vignettes (#314). * An off-by-one error in the C++ Roxygen preparser was fixed. * The new `@backref` tag makes it possible to override the sourceref for R code generators like `Rcpp` (@krlmlr, #291, #294). # roxygen2 4.1.0 * The source of the documentation is added to autogenerated `.Rd` files. * If there are no `@include` tags, roxygen2 leaves the collate field alone. This makes it easier to convert an existing project that uses a predefined collate, but if you start with `@include` and later remove them, you'll need to also remove the collate field (#302, #303). * Protected a `dir()` with `sort_c()` - If you'd noticed an inconsistency in ordering between `devtools::document()` and `devtools::check()` this was the cause of that. * Fixed broken regular expression that caused problems with stringr 1.0.0. * The `Authors@R` field in `DESCRIPTION` is now longer wrapped(@krlmlr, #284). * `@describeIn` with plain functions now correctly includes the function name and can be applied to data documentation. (@jimhester, #285, #288). * Works again when called from `Rscript` and `methods` is not loaded (@krlmlr, #305). # roxygen2 4.0.2 * If you don't use `@exports` or other namespace directives, your namespace file will not be touched (#276). * Methods no longer automatically attempt to inherit parameters from their generic. It's too fraught with difficulty (#261). * Roxygen now understands what to do with `setReplaceMethod()` (#266). * Parameter documentation is ordered according to the order of the formals, if possible (@krlmlr, #63). * Export `is_s3_method()`. * Roxygen no longer fails when run in non-UTF-8 locales on windows. # roxygen2 4.0.1 * Explicit `updateRoxygen()` is no longer needed - `roxygenize()` does the right thing the first time it is run. * Exporting a S4 generic works (#246). * `roxygenise()` no longer complains about absence of `wrap` field because it's so unlikely that anyone wants the old behaviour (#245). # roxygen2 4.0.0 Roxygen2 4.0.0 is a major update to roxygen2 that makes provides enhanced error handling and considerably safer default behaviour. Now, roxygen2 will never overwrite a file that it did not create. This means that before you run it for the first time, you'll need to run `roxygen2::upgradeRoxygen()`. That will flag all existing files as being created by roxygen2. ## New features * Six vignettes provide a comprehensive overview of using roxygen2 in practice. Run `browseVignettes("roxygen2")` to access. * `@describeIn` makes it easier to describe multiple functions in one file. This is especially useful if you want to document methods with their generic, or with a common class, but it's also useful if you want to document multiple related functions in one file (#185). * `@field` documents the fields on a reference class (#181). It works the same way as `@slot` for S4 classes. * You can now document objects defined elsewhere (like datasets) by documenting their name as a string (#221). For example, to document an dataset called `mydata`, you can do: ```R #' Mydata set #' #' Some data I collected about myself "mydata" ``` * Roxygen2 now adds a comment to all generated files so that you know they've been generated, and should not be hand edited. * Roxygen2 no longer wraps the text in Rd files by default, i.e. the default option is `wrap = FALSE` now. To override it, you have to specify a field `Roxygen: list(wrap = TRUE)` in `DESCRIPTION` (#178). * Roxygenise automatically deletes out-of-date Rd files in `man/`. ## Improved error handling * Roxygen2 will never overwrite a file that was not generated by roxygen2. This means that the first time you use this version of roxygen, you'll need to delete all existing Rd files. `roxygenise()` gains a clean argument that will automatically remove any files previously created by roxygen2. * Parsing is stricter: many issues that were previously warnings are now errors. All errors should now give you the line number of the roxygen block associated with the error. * Every input is now checked to make sure that you have matching braces (e.g. every `{` has a matching `}`). This should prevent frustrating errors that require careful reading of `.Rd` files (#183). * `@section` titles and `@export` tags can now only span a single line to prevent common bugs. * `@S3method` is deprecated - just use `@export` (#198). * Namespace tags now throw parsing errors if you give them bad inputs (#220). * Better error message if you try to document something other than NULL, an assignment, a class, a generic or a method (#194). ## Bug fixes and minor improvements * Better parsing of non-syntactic function names in other packages when used in `@inheritParams` (#236). * Deprecated arguments to `roxygenise()` (`roxygen.dir`, `copy.package`, `overwrite`, `unlink.target`) removed. * Remove unneeded codetools and tools dependencies. * Bump required Rcpp version to 0.11.0, and remove custom makefiles. * Non-syntactic argument names (like `_x`) are now surrounded by back-ticks in the usage (#191). * The internal parsers are no longer part of the public roxygen2 interface. * Usage statements in generated roxygen statements non-longer contain non-ASCII characters and will be wrapped if long (#180). * By default, reference classes now only document their own methods, not their methods of parents (#201). * Default aliases always include the original name of the object, even if overridden by `@name`. This also means that `A <- setClass("A")` will get two aliases by default: `A` and `A-class` (#202). Use `@aliases NULL` to suppress default alias. * Non-syntactic class names (like `<-`) are now escaped in the usage section of S4 methods (#205). * Eliminated two more cases where wrapping occurred even when `wrap = FALSE`. # roxygen2 3.1.0 ## Documentation for reference classes It's now possible to document reference classes, using the "docstring" convention described in `?setRefClass`. If you want to provide a short paragraph description of what a method does, make the first component of the message a string containing the description, e.g.: ```R setRefClass("A", methods = list( f = function(a, b) { "Take numbers \code{a} and \code{b} and add them together" a + b } )) ``` Unlike the documentation for R functions, the documentation for methods can be quite succinct. Roxygen adopts the convention that documented methods are public, and will be listed in the man page for the object. Undocumented methods are private and will not be shown in the documentation. The methods for all superclasses are also listed, so that you don't need to flip through multiple pages of documentation to understand what you can do with an object. All documented methods will be placed in a bulleted list in a section titled "Methods", the method usage will be automatically prepended to the docstring. ## Minor fixes and improvements * Fixes for Rcpp 0.11.0 compatibility. * `roxygenise()` now invisible returns a list of all files generated by individual roclets. This is useful for tools that want to figure out if there are extra files in the `man/` directory. * `is_s3_generic()` now recognises group generics (#166). * Don't try and add parameters for data objects (#165). * Sort output of families using C locale (#171). * `@family` now escapes function names in references (#172). # roxygen2 3.0.0 Roxygen2 now fully supports S4 and RC (reference classes) - you should no longer need to manually add `@alias` or `@usage` tags for S4 classes, methods and generics, or for RC classes. * The default usage definitions are much better, generating the correct usage for data sets (#122), S3 methods (without additional `@method` tag), S4 generics, S4 methods, and for replacement (#119) and infix functions. Backslashes in function arguments in are correctly escaped. Usage statements also use a more sophisticated line wrapping algorithm so that they should cause fewer problems with the R CMD check line limit. (#89, #125). * S4 classes, S4 methods, and RC classes are given better default topics, and the file names corresponding to those topics are shorter. * S4 methods will automatically inherit parameter documentation from their generic. * `@slot name description` allows you to document the slots of a S4 class. S3 support has also been improved: roxygen2 now figures out whether a function is a S3 method or generic. (In the rare cases it does so incorrectly, use `@method` to manually describe the generic and class associated with a method). This means you can remove existing uses of `@method`, and can replace `@S3method` with `@export`. Roxygen now has support for package specific options through the `Roxygen` field in the `DESCRIPTION`. The value of the field should be R code that results in a list. Currently only `wrap` and `roclet` values are supported: * Turn off Rd re-wrapping with adding `Roxygen: list(wrap = FALSE)` * Change the default roclets by specifying `Roxygen: list(roclets = c("collate", "rd"))` Roxygen 3.0 also includes a number of minor fixes and improvements: * Infix functions are now escaped correctly in the `NAMESPACE`. (Thanks to @crowding, #111) * `roxygenise()` now works more like `devtools::document()` and only ever works in the current directory. The arguments `roxygen.dir`, `overwrite`, `copy.package` and `unlink.target` have been deprecated due to potential data loss problems. * The collate roclet is no longer a roclet: it processes R files using custom code (only statically, not dynamically) and is designed to be executed before the code is sourced. Run `update_collate()` to update the Collate directive based on `@include` tags - if there are none present, a collate directive will not be generated. * `@useDynLib` now works with more possible specifications - if you include a comma in the tag value, the output will be passed as is. This means that `@useDynLib mypackage, .registration = TRUE` will now generate `useDynLib(mypackage, .registration = TRUE)` in the `NAMESPACE`. (#124) * `inst` directory not created by default (#56). * Explicitly depend on `utils` and `methods` packages to make roxygen compatible with `Rscript` (#72). Import `digest` package instead of depending on it. * Always use C locale when sorting `NAMESPACE` file or tags in `.Rd` files. This ensures a consistent ordering across systems (#127). * Templates with extension `.r` are supported on case-sensitive file systems (#115). Template variables now actually work (#160, thanks to @bronaugh). * Suppress default aliases, format and usage with `@aliases NULL`, `@format NULL` and `@usage NULL`. # roxygen2 2.2.2 * Correctly use keyword `datasets` not `dataset` (Fixes #60) * Reference classes no longer given incorrect docType (data). # roxygen2 2.2.1 * Use unicode escapes in test files so tests pass on all platforms. * Work around bug in `gsub` in C locale by manually specifying `Encoding()`. # roxygen2 2.2 ## New features * Package docType will automatically add package alias, if needed. (Fixes #4) * Data docType will automatically add `datasets` keyword, default usage, and default format. (Fixes #5). Data docType automatically added to data objects. * New `@encoding` tag for manually setting non-ASCII encodings when needed. (Fixes #7) ## Bug fixes * `write.description()` now tries much harder to respect users' original DESCRIPTION field formatting instead of forcibly re-wrapping certain fields at 60 characters. * `@details` and `@description` now work correctly * `@useDynLib` now works correctly: @useDynLib packageName routine1 routine2 produces useDynLib(packageName, routine1) useDynLib(packageName, routine2) in the `NAMESPACE` file, instead of separate (wrong) useDynLib statements as before. * All namespace import directives now behave in the same way as the export directives, producing multiple single directives instead one multiple directive: `@importClassesFrom pkg a b` now produces `importClassesFrom(pkg, a)` and `importClassesFrom(pkg, b)` * In example files included with `@example` you can now use infix operators (e.g. %*%) or other things with %, because they will be preceded by a backslash in the Rd file. This behaviour was already in place for examples directly included with `@examples`. * Aliases are no longer quoted, and % is escaped with a backslash (Fixes #24). Names also have % escaped (Fixes #50) * Replacement functions (e.g. `foo<-`) now get correct usage statements: `foo() <- value` instead of `foo()<-value`. (Fixes #38) * Functions with no arguments now correctly get usage statements (Fixes #35) * Indentation in examples now preserved (Fixes #27) * roxygen2 will replace characters that are not valid in filenames with a character substitute, e.g. `[]` becomes `sub`, `<-` becomes `set` (Fixes #6) * Usage strings use non-breaking spaces to prevent string default values containing whitespace to be split across multiple lines. This may cause problems in the unlikely event that you have default value containing a non-breaking space (`"\uA0"') (Fixes #21) * Functions with quoted names now get correct usage statements (Fixes #41) * Objects that no longer exist are not documented (Fixes #42) * Errors now display file name and line number of roxygen block to help you find the problem. Thanks to code contributions from Renaud Gaujoux. (Fixes #13) * Documentation with no untagged text but with `@title`, `@description` and `@details` tags now produces correct output. # roxygen2 2.1 ## New features * package dependencies loaded automatically * added support for the `@source` tag ## Bug fixes * `NAMESPACE` file no longer needs to exist * `Collate` field in `DESCRIPTION` no longer needs to exist * `=` now recognised as way of assigning functions * `x$y <- function() {...}` no longer causes error * `@example` no longer added extra new-lines. * Correct directory normalisation under windows fixes broken test. * A special thanks goes to Yihui Xie who contributed all of the fixes and improvements (bar one) in this version! # roxygen2 2.0 ## Major changes * now works with run-time details to give more accurate output. This requires that the source code that roxygen is documenting be loaded prior to documentation. roxygen will attempt to do so, but you need to ensure required packages are loaded. Run-time data fixes some long standing bugs where roxygen couldn't correctly figure out function usage. We are not aware of any cases where you still need to use the `@usage` tag. * written in idiomatic R, and uses S3 instead of a homegrown class system. * roclets build up an internal data structure instead of writing to disk directly. This means that you can now use the `@rdname` tag to merge documentation for multiple functions into one file, and that only unique namespace directives are written to `NAMESPACE` (which makes `@importFrom` much more useful). * some features have been removed, and may or may not (based on your feedback) be reincluded. These include the callgraph roclet, and `R CMD roxygen`, which only worked on some systems. * a templating system: use the `@template` tag to insert a `brew` template stored in `man-roxygen`. Template variables can be set using `@templateVar name value` and retrieved from within the template with `<%= name %>` * extensive use of caching to make repeated runs as fast as possible. To clear caches and guarantee a complete rebuild, use `clear_caches()`. * parsing of "introduction" (the text before the first tag) has changed. Now the title consists of the first paragraph (i.e. all text before the first empty line), the second paragraph is the description and all others are put in the details. Any component can be overridden with `@title`, `@description` and `@details` as appropriate. ## Minor changes * `@name` is always output as an alias, even if `@aliases` are used. * `@export` correctly uses `@method` to generate `S3method` namespace directive ## New tags * `@rdname filename` sets the output filename (without extension). Use for functions non-alphanumeric functions (e.g. `[<-`) or if you want to document multiple functions in one file * `@template templatename` includes a documentation template (see above) * `@section Section title: contents` includes a section with any title. Don't forget the colon! That separates the title of the section from its contents. * `@description` and `@details` tags allow you to specify description and details components in a template * `@family family name` automatically adds see-also cross-references between all functions in a family. A function can belong to multiple families. * `@inheritParams name` allows you to inherit the documentation for parameters from another function, either within the current package (`function`) or in any other installed package (`package:function`). Currently only supports single inheritance (i.e. you can't inherit from a function that inherits from another function), but you can have multiple @inheritParams tags. * `@format` has been implemented; it existed in the roxygen package but was actually ignored roxygen2/MD50000644000176200001440000003550314116067732012354 0ustar liggesuserscf14ee3c8178d8aaab1dc67e349dfa34 *DESCRIPTION 6726c2d6f3f89d4188b3976c034855b9 *LICENSE 2256760e6987d7f39ee38e91ebafa939 *NAMESPACE ba280fec24e1d98cb98ab19ab9d7d160 *NEWS.md 1a0351ff60c05dea6f077468d14c9cc7 *R/block.R ad3fc08136fb72b1c88d970ae48ea815 *R/collate.R 1642db96ca01adbe0645eac51d44c7f7 *R/cpp11.R 269baef89724bd8c816067c665036152 *R/field.R ed95c3ab1d29cd4bc006b8cf42ebd5ff *R/load.R 30718d1201883bf4d002f5340f8661da *R/markdown-escaping.R 232d8c50f84a4f882817b67def86fa30 *R/markdown-link.R 45ea60500069ef9b60b58fa695e2855d *R/markdown-state.R 0d8db848dd7d3dff6e40575c8c702806 *R/markdown.R 92f71df66313b882c7df510385be7076 *R/namespace.R 2bd71002ff5fe4d149b460348885fe77 *R/object-defaults.R 2db30ae88929c2ad4065e480c2f82efc *R/object-format.R 6a7e4103ca73ba3bede9f241b4cea584 *R/object-from-call.R df695c7189ad08185c3dc580975dcde3 *R/object-import.R 5bfec1430e056da8e5d6a3745f410d44 *R/object-package.R e9e7dc00bb8c05dfe2703cfb8f16359b *R/object-r6.R a49a7da3027fc0fb0b815a1fe95f3d1c *R/object-rc.R 49759e832ce2e24c97f228b21d637cfe *R/object-s3.R 44df3c358805dc2e843cd434ad59c43e *R/options.R 0e62a924bd6f8a715e1cfe9dd6089b18 *R/package_files.R 4a10ca1f74f135494bee54dd905ef50c *R/parse.R 87c69905a0d8bfad17e7b4fe8e1d7eb7 *R/rd-backref.R 1161f8d94a23c01efe719a498cc66ce6 *R/rd-describe-in.R afa6a941d59fd0dec634b9bfb8ae7092 *R/rd-examples.R 2f343a2bf37db7cb4ff9f7a182263295 *R/rd-family.R ce2190725a618b67e91e4957fa67752d *R/rd-find-link-files.R 32fbc645e47a0508782680bf69666326 *R/rd-include-rmd.R b22e255415dfa98b2dcea2f63dc87b81 *R/rd-inherit.R 56bd4e8ce0882ed4e6000afcc91ae3ac *R/rd-markdown.R 2292d47ed4931d532a7de376e6cf2798 *R/rd-name-alias.R d14c78ba2ffbc529d3926efe1e6b7da7 *R/rd-params.R ab9b4c6aeeb4af51b4a83520aab7480d *R/rd-r6.R 8683bf665c4f48f48256480ef7eef7c0 *R/rd-raw.R fe6cd90194430889584b6d90b45337d2 *R/rd-s4.R 67ad11b12febf4d67d074f323dc75420 *R/rd-section.R 7dc37a98ee9b55dc82ef7cd1b6276a07 *R/rd-simple.R 65c42d1102cec6bf852283912f2aa362 *R/rd-template.R 8711ba4e5e5c0804bc1e106f3df80adc *R/rd-usage.R b493e52c23b358aed6a3f3a054ac9b7f *R/rd.R 02c5ebcd5fe6d6eb56a5db1fb758f475 *R/roclet.R 514b13ffe69985abc570a813a91a220a *R/roxygen.R ddc2d21624d7dc6e3b07daa61f0add07 *R/roxygenize.R e0e2c44dc66e5f604f7cc230ba0ea2a2 *R/safety.R a29a83549ad6014373e1ac9df8e1d7e7 *R/select-args.R a53fa85b09b9c8868fb9cab2859d0703 *R/tag-parser.R c8d7d8579e240139c3e436e046599418 *R/tag.R 8a0416cecd6bfdf083e476d54f7318d2 *R/tokenize.R 5488ff7a1d21bb45b81ce81ddd81a1bd *R/topic.R 4da445edb13b7bbe475528a66f1f8df2 *R/topics.R 3ab3ddcc81eb5436dcc3e85f3455e5a7 *R/topo-sort.R 4a03394536203e479c5b7e70b7ec6f23 *R/util-locale.R 22593c3d8108ff8cb5104c0e8cfcca5b *R/utils-io.R b9ce428095cdfa7a894ee786e860129f *R/utils-rd.R e42c0f882d1bb25373d4d6fcebfc669b *R/utils.R be3dbfe1e4e543af14ed29154c59e12b *R/vignette.R 4df50b4923df32583a121ab3f3c4c368 *R/zzz.R a0b189be099127f378ea8ea565837374 *README.md 507bd765e93b67c845dfa816672bbba9 *build/vignette.rds 60df2756bccccc34ac571b0c6672a928 *inst/doc/extending.R a1df4c743ba3d15507a2f40caecc8bf8 *inst/doc/extending.Rmd fd2932dc8ce68a260cf4f4618c2f0e58 *inst/doc/extending.html 82f10b855e7d2eb955ebae2f12ed9da1 *inst/doc/namespace.R 5219c1e7049d9997f4b97e1632178e7f *inst/doc/namespace.Rmd ff96bffcb2fd64ff487b712d89137fd1 *inst/doc/namespace.html 9046bef9d45df32c3adf69975b05f5ab *inst/doc/rd-formatting.R d9ad63543f21c060269adc86c702ad31 *inst/doc/rd-formatting.Rmd b59e87a63e21e8305c2f27544ee8a6ab *inst/doc/rd-formatting.html fdb7208cb9b7a86d36d92eef3ac79c7a *inst/doc/rd.R 14f7ec711abf4b2a9a5a223fe8cb767b *inst/doc/rd.Rmd 1a9cc63659e5d849564a9a9206862a2e *inst/doc/rd.html 9c4278c4baee055d5f33968ae842ed1f *inst/doc/roxygen2.R a18578e965b92269ba5997881206c98f *inst/doc/roxygen2.Rmd decd9ce539ea7755585cf8c4306c8888 *inst/doc/roxygen2.html 2ab4aa920ecabeb56de2436ffe2a4742 *man/RoxyTopic.Rd ee44179196cd41e424888dafcdee974a *man/double_escape_md.Rd 7a90f135e7865de509a8d7518e3938f8 *man/escape_examples.Rd 65ecd016d614dcf02fe22ae86b757c4b *man/figures/logo.png 2970c99d6a9942eada933591d0006c3f *man/figures/test-figure-1.png c04c11bc534ff8187476878394205f93 *man/is_s3_generic.Rd f1725e8eede7d5dfb28abaff439974a8 *man/load.Rd 8932c80315ddffb00a9a98fde21fc82f *man/load_options.Rd fe342bc1885bc7111186179abb8ab5a0 *man/markdown-internals.Rd 5ee1273982aa827796bf569fbfeb1279 *man/markdown-test.Rd 6c979acf39bbe316d2e731b6db47bee8 *man/markdown_pass1.Rd d75bf030978ddf3c3c28cd78aa677642 *man/namespace_roclet.Rd 83620c541a0719217c5c7e92b191d5e1 *man/object.Rd 4a041e626e236a848ef35943e4b93ffd *man/object_format.Rd 53e4d4decf9174c9b14edf8f859bf940 *man/parse_package.Rd 129d3aad1273da03e2776f64bfb081fa *man/rd_roclet.Rd e143910d6e854b195b567cce4062c9e6 *man/rd_section.Rd d1a570ce5e2a9c4b8f3c0d5b77507c87 *man/roc_proc_text.Rd 3b638616f3d31b277acb7d6718aaa9c8 *man/roclet.Rd 55f6a83aef0b163542266cbd3e5351a6 *man/roclet_find.Rd 09b5464f861027a7c7e9354716d8c66a *man/roxy_block.Rd 77a9c52439ce7eefd7c05bed5d1426b3 *man/roxy_tag.Rd cbaeb4b8f5c628adf2d57b085db1c291 *man/roxy_tag_rd.Rd 9117b283de99566eedf420d5a641accb *man/roxygen/templates/rd.R 15fb55cbecc2f7953bf09376515d1c28 *man/roxygen2-package.Rd 27aa88be4987ffa55030649af897b42f *man/roxygenize.Rd a1f680309aab8e1167f739462d822c10 *man/tag_parsers.Rd 343edc77b4cc1a1c8e758aabded5fe4a *man/update_collate.Rd 305c9623afc6327c0c3b9e25d193d2e2 *man/vignette_roclet.Rd a3db42cf00ccc7381a3f718acc13b494 *src/cpp11.cpp fecfbfb6f902fe7c544a801e5d94f43e *src/escapeExamples.cpp c2a88da4a40f1916edc96a5a393a1eb5 *src/isComplete.cpp c2031a287457e490af02408283d4091e *src/leadingSpaces.cpp eb95e48e9bb9a94ef88bddafe3b69504 *src/parser2.cpp 826298505f75ea1b162d2cab3a1f00ff *src/wrapUsage.cpp 0c02cbdd58c833b2cdc5ceabc7432901 *tests/testthat.R e686310a87142a0e59ff1e55565b8fbc *tests/testthat/Rd-example-1.R 4453aeecf77fbf36b95091b2a814fd4e *tests/testthat/Rd-example-2.R c0b393cde4b9539bbf2434630c0945d7 *tests/testthat/Rd-example-3.R dc7e3daa600d9358a557f9f5733684dd *tests/testthat/Rd-example-4.txt c8e3c693f5892d7c420ef06a58cec8af *tests/testthat/collate/belt.R 29edb1140b31a818b5514e75134b789e *tests/testthat/collate/jacket.R 8d463634a317b5ba8c0b5377d1a8e9e4 *tests/testthat/collate/pants.R ca35c56c0c379f292f8fab68b3a19f61 *tests/testthat/collate/shirt.R d1240ac026fdfb6e30bb2092caa57cc4 *tests/testthat/collate/shoes.R ca35c56c0c379f292f8fab68b3a19f61 *tests/testthat/collate/socks.R 1e1e34f6c314f9a3f28a0d8782494713 *tests/testthat/collate/tie.R ca35c56c0c379f292f8fab68b3a19f61 *tests/testthat/collate/undershorts.R 37baf697a226b7582659e1ffc440cee5 *tests/testthat/collate/watch.R a56313f94011e845e4d7f94e7a51a263 *tests/testthat/description-example.txt 37dcd46925a49849dd4ae206b08a77aa *tests/testthat/description-example_2.txt de9e9082f8f26ba5b37048120a9c26c4 *tests/testthat/empty/DESCRIPTION ca35c56c0c379f292f8fab68b3a19f61 *tests/testthat/empty/R/empty-package.R 328347034d6b99d5fc52d553331869f8 *tests/testthat/escapes.Rd 9ef8a64319bfa4c69d014e844865ea19 *tests/testthat/helper-pkg.R 63eee6763c9bace10c994ec5b9adceac *tests/testthat/helper-test.R d41d8cd98f00b204e9800998ecf8427e *tests/testthat/made-by-roxygen/empty.Rd 8e73ac305e731a371f92350f610bed57 *tests/testthat/made-by-roxygen/with-header.Rd b5f24ca1515530c7e8ce1fcc85b671d4 *tests/testthat/made-by-roxygen/without-header.Rd 073104afbb7d5c6d43390603875598a4 *tests/testthat/man-roxygen/values.R ea256d4d5972f4acb68d10dfdfe02e14 *tests/testthat/markdown-code-errors.txt 8b54e5a89fbda3af5e077053d40bec76 *tests/testthat/no-desc/NAMESPACE ca35c56c0c379f292f8fab68b3a19f61 *tests/testthat/no-desc/R/no-description.R c6335cc2a7ba870fdc7e402c38cf991d *tests/testthat/roxygen-block-1.R 821cbd88b6d2399710bd0fdaa7b26243 *tests/testthat/roxygen-block-2.R eab9a7f869fcdef3d1f126d58d39f9e1 *tests/testthat/roxygen-block-3-A.Rd 52407c289f4045ad223a430a4d790f1c *tests/testthat/roxygen-block-3-B.Rd e42407e034368f6c0cd31604ec8a1d02 *tests/testthat/roxygen-block-3-C.Rd da65b3642564a626561d671116c30f36 *tests/testthat/roxygen-block-3-warnings.txt 0afd340b523acd4b5b39c0792258cde3 *tests/testthat/roxygen-block-3.R 05573ff82dfeb474063ba887ff2b11aa *tests/testthat/roxygen-example-1.R d41d8cd98f00b204e9800998ecf8427e *tests/testthat/templates/man-roxygen/UCase.R d41d8cd98f00b204e9800998ecf8427e *tests/testthat/templates/man-roxygen/lcase.r 073104afbb7d5c6d43390603875598a4 *tests/testthat/templates/man/roxygen/templates/new-path.R 00772aea9c1e15a15874ac0d21dd3f48 *tests/testthat/test-block-print.txt bc3169da2d6b84bf3704b02d572be06f *tests/testthat/test-block.R 043eb9f7236cc9c70ee978357d9568c9 *tests/testthat/test-collate.R b02a05fda188593b0e99daa40f2ad8e4 *tests/testthat/test-load.R aa911ccb40e8b79fb71f1f9c17a8de9f *tests/testthat/test-markdown-code.R 957d179c1e9491f92656351a34c4e2ce *tests/testthat/test-markdown-link.R 9b999a05f869c2cd85c50f34a70d7dab *tests/testthat/test-markdown-state.R d3304dc977f21651369279aa12cd49dd *tests/testthat/test-markdown-table.txt 5c48ac85177d97d02ea787d3d10b220c *tests/testthat/test-markdown.R a46ca38d3a7890cb99aab522dbea1a1e *tests/testthat/test-namespace.R e9aef040af14dbdfba9753adfdcbc0e3 *tests/testthat/test-object-defaults.R 88a66b01b7ec111513713ce1b32109e1 *tests/testthat/test-object-format-r4.txt a0923d8dfa86d94eb49df3ab0d117883 *tests/testthat/test-object-format.R d9dc92c896fb87a14e911b0b5c4903bc *tests/testthat/test-object-format.txt 93ac9aebbbf21230f98fde2ac395b9e7 *tests/testthat/test-object-from-call.R 58b768eed1ada993a44263bcc0db46d5 *tests/testthat/test-object-import.R 9ea96182f4f54280dba8c9f9e9a68b56 *tests/testthat/test-object-import.txt 77ba1c1707bedcdf5ebc74d86d34695a *tests/testthat/test-object-package-author.txt f7a6ec787fb96389df2e84071c1bc56e *tests/testthat/test-object-package.R 422c2838bd28bd6f4d19856fb1413586 *tests/testthat/test-object-rc.R 2cb525eb4ae88c7ed2879d8e4d0725ef *tests/testthat/test-object-s3.R 424408cee64145731a2ef4a65c65656d *tests/testthat/test-object-usage-wrap-new.txt 0905220ba35d67744224f214ad4d817c *tests/testthat/test-object-usage-wrap-old.txt 559b2d8e20cd2274fa21030f571a2182 *tests/testthat/test-options.R 7571cf2b48cc60b5918057a5fe0f2724 *tests/testthat/test-options/DESCRIPTION c0d9bd2424dbc167e528dedd53b98822 *tests/testthat/test-options/man/roxygen/meta.R ff338a7c1899a53efa682a196526ba6b *tests/testthat/test-options/meta-character.R 52a3c7d9ac1c4434e2f891e89491d6e7 *tests/testthat/test-options/meta-error.R 14478807ceb5913520190dfd33fc5bff *tests/testthat/test-package_files.R a6e88deab0de552973600a24f2213638 *tests/testthat/test-parse.R f06533769347dfa8511d2329e1881085 *tests/testthat/test-rd-backref.R b1cfd954204230ef430430e28b996108 *tests/testthat/test-rd-describe-in.R 9a725554c96484260270378acbebf3af *tests/testthat/test-rd-examples-dontrun-escape-2.txt a9e38cd58280e7d67aecd695aa5b44e5 *tests/testthat/test-rd-examples-dontrun-escape.txt 5d8c5b579fb2e6cffbf73d428ca016e7 *tests/testthat/test-rd-examples-interleave.txt 7d2c4c736f9376870d6f308071da9cdd *tests/testthat/test-rd-examples.R 411a2fa92ae96f248a9a313c8c2c1772 *tests/testthat/test-rd-examplesIf.txt 559069934e0ee58f921da10a900c2821 *tests/testthat/test-rd-family.R 4bbd36914f80bbc79358a1447e80ad84 *tests/testthat/test-rd-include-rmd.R c1c56af6d811ce04ff899e85c86e2389 *tests/testthat/test-rd-inherit-dots-inherit.txt c67e3f93eef7850ef1dda60bbea227c5 *tests/testthat/test-rd-inherit-dots-multi.txt c4a6ed374590d26254de37fc7c595f5c *tests/testthat/test-rd-inherit-dots.txt 27c1d0df1ea4310be1745464304ce1ac *tests/testthat/test-rd-inherit-link.txt 85efaf3bbd18083e661d0279d3c3a20b *tests/testthat/test-rd-inherit.R f2e5b4e60268703274430ff6d5b3fd1a *tests/testthat/test-rd-markdown-escaping.R e41ea29cdf47f1f17b65a2fb623140ee *tests/testthat/test-rd-markdown.R 8202f554b09398679b1a6ea960c54193 *tests/testthat/test-rd-name-alias.R c772ee7cfa55b7b6af427922ae88e037 *tests/testthat/test-rd-params.R 909d89319917a99c7846bde601686828 *tests/testthat/test-rd-r6.R f1aa93aff11cc78cb43e5e61feff9372 *tests/testthat/test-rd-raw.R e56fceb1fe313a968501efa2689614b1 *tests/testthat/test-rd-s4.R 9b59ef05e04207660fd38c1a31e4fb2a *tests/testthat/test-rd-section.R c08e8abe6f7dacfb2ec99433bd08a627 *tests/testthat/test-rd-simple.R 35d23824e88f8dbad4c7b3f9497c66b4 *tests/testthat/test-rd-template.R 841c1b43f52cc2b407d0a2c79929b37d *tests/testthat/test-rd-usage.R 4f2c6d55e4f007e8f7ad5e99df4d9b94 *tests/testthat/test-rd.R 2172f642f5b33c1af1482ade98f6528b *tests/testthat/test-safety.R 5d6193f0934ef974bbd79ce4d30d1db2 *tests/testthat/test-select-args.R e8e7007fd104a6af7103a4dd6a315e3a *tests/testthat/test-tag.R 10ebabe170b3f5261c79a38676027709 *tests/testthat/test-tokenize.R 13b62df4a3bfa6c96f1f874a10f6c416 *tests/testthat/test-topic.R 102dda56f848d9704365cde64c350cd1 *tests/testthat/test-utils-io.R c516c2839fabb108866b9a9ca4765420 *tests/testthat/test-utils-rd.R 5af6838505f55dce36b19b60d2c8d094 *tests/testthat/test-utils.R 423691bf9ad0792c809b5ac131f60211 *tests/testthat/testCollateNoIncludes/DESCRIPTION 012592abf4b40a8d741b299df2ded05a *tests/testthat/testCollateNoIncludes/NAMESPACE 1936220d3bd92a5d178052a74c55a6b2 *tests/testthat/testCollateNoIncludes/R/a.r 5dc6a5b47f4272a583e1a76ce68ae884 *tests/testthat/testCollateNoIncludes/R/b.r 3089550a7728ca2e7a1e6ce610a4e0d6 *tests/testthat/testCollateOverwrite/DESCRIPTION 09b2f9e44bf5543befeaafc2c0ead6f1 *tests/testthat/testCollateOverwrite/R/a.r d119cb97e3acb0ddacf52c658960de8c *tests/testthat/testCollateOverwrite/R/b.r f7c6f75c5ab44892408392add791c734 *tests/testthat/testCollateParse/DESCRIPTION 62853d4d57a96b75cd7ffb7b7be73281 *tests/testthat/testCollateParse/R/b.r d4dffe82e14a669b1369195a3bb4be11 *tests/testthat/testCollateParse/R/c.r 38018efd31973c00e191d80641db81a2 *tests/testthat/testEagerData/DESCRIPTION 1c9a6674a40bfc331c5d06dabfd3b5a5 *tests/testthat/testEagerData/R/a.r 8b7270f2ffa38e863594416e35322ecb *tests/testthat/testEagerData/data/a.rda 1c65a07303e051957ff827d1440ecd68 *tests/testthat/testLazyData/DESCRIPTION dc21c19f0d6968ee25d441b2cf46017d *tests/testthat/testLazyData/NAMESPACE 1c9a6674a40bfc331c5d06dabfd3b5a5 *tests/testthat/testLazyData/R/a.r 8b7270f2ffa38e863594416e35322ecb *tests/testthat/testLazyData/data/a.rda 407d7852ba60cff5faf5670a5b417ab9 *tests/testthat/testNamespace/DESCRIPTION b1b61b677cc8c9a85d50edffc7d21e74 *tests/testthat/testNamespace/NAMESPACE 38d13539cf9635b93a0810e1f452f44c *tests/testthat/testNamespace/R/a.r f79b5e26f0b92d1545bd22db4084a0ef *tests/testthat/testNonASCII/DESCRIPTION 6771c1b73ec140ec70430460e9596d57 *tests/testthat/testNonASCII/R/a.r 796877413bf89f4760a687d3ecb0e053 *tests/testthat/testRbuildignore/DESCRIPTION 0b8f7598d11eec67e849a9d01d4adbe4 *tests/testthat/testRbuildignore/R/a.R 8ac0741e375b73b0582a2c6c1ee50296 *tests/testthat/testRbuildignore/R/ignore_me.R 816bcfd7d7d9023f71bcf15a55bc435b *tests/testthat/testUtf8Escape/DESCRIPTION d1e8df72ac79d2182b48f682ee7a4f38 *tests/testthat/testUtf8Escape/R/a.r a1df4c743ba3d15507a2f40caecc8bf8 *vignettes/extending.Rmd 5219c1e7049d9997f4b97e1632178e7f *vignettes/namespace.Rmd d9ad63543f21c060269adc86c702ad31 *vignettes/rd-formatting.Rmd 14f7ec711abf4b2a9a5a223fe8cb767b *vignettes/rd.Rmd a18578e965b92269ba5997881206c98f *vignettes/roxygen2.Rmd roxygen2/inst/0000755000176200001440000000000014115763565013021 5ustar liggesusersroxygen2/inst/doc/0000755000176200001440000000000014115763565013566 5ustar liggesusersroxygen2/inst/doc/rd.R0000644000176200001440000001677214115763564014332 0ustar liggesusers## ---- include = FALSE--------------------------------------------------------- knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ## ----------------------------------------------------------------------------- #' Sum of vector elements #' #' `sum` returns the sum of all the values present in its arguments. #' #' This is a generic function: methods can be defined for it directly #' or via the [Summary()] group generic. For this to work properly, #' the arguments `...` should be unnamed, and dispatch is on the #' first argument. sum <- function(..., na.rm = TRUE) {} ## ----------------------------------------------------------------------------- #' Sum of vector elements #' #' @description #' `sum` returns the sum of all the values present in its arguments. #' #' @details #' This is a generic function: methods can be defined for it directly #' or via the [Summary()] group generic. For this to work properly, #' the arguments `...` should be unnamed, and dispatch is on the #' first argument. ## ----------------------------------------------------------------------------- #' Sum of vector elements #' #' `sum()` returns the sum of all the values present in its arguments. #' #' This is a generic function: methods can be defined for it directly #' or via the [Summary] group generic. For this to work properly, #' the arguments `...` should be unnamed, and dispatch is on the #' first argument. #' #' @param ... Numeric, complex, or logical vectors. #' @param na.rm A logical scalar. Should missing values (including `NaN`) #' be removed? #' @return If all inputs are integer and logical, then the output #' will be an integer. If integer overflow #' () occurs, the output #' will be NA with a warning. Otherwise it will be a length-one numeric or #' complex vector. #' #' Zero-length vectors have sum 0 by definition. See #' for more details. #' @examples #' sum(1:10) #' sum(1:5, 6:10) #' sum(F, F, F, T, T) #' #' sum(.Machine$integer.max, 1L) #' sum(.Machine$integer.max, 1) #' #' \dontrun{ #' sum("a") #' } sum <- function(..., na.rm = TRUE) {} ## ----------------------------------------------------------------------------- #' An S4 class to represent a bank account #' #' @slot balance A length-one numeric vector Account <- setClass("Account", slots = list(balance = "numeric") ) ## ----------------------------------------------------------------------------- #' R6 Class Representing a Person #' #' @description #' A person has a name and a hair color. #' #' @details #' A person can also greet you. Person <- R6::R6Class("Person", public = list( #' @field name First or full name of the person. name = NULL, #' @field hair Hair color of the person. hair = NULL, #' @description #' Create a new person object. #' @param name Name. #' @param hair Hair color. #' @return A new `Person` object. initialize = function(name = NA, hair = NA) { self$name <- name self$hair <- hair self$greet() }, #' @description #' Change hair color. #' @param val New hair color. #' @examples #' P <- Person("Ann", "black") #' P$hair #' P$set_hair("red") #' P$hair set_hair = function(val) { self$hair <- val }, #' @description #' Say hi. greet = function() { cat(paste0("Hello, my name is ", self$name, ".\n")) } ) ) ## ----------------------------------------------------------------------------- #' Prices of 50,000 round cut diamonds #' #' A dataset containing the prices and other attributes of almost 54,000 #' diamonds. #' #' @format A data frame with 53940 rows and 10 variables #' \describe{ #' \item{price}{price in US dollars (\$326--\$18,823)} #' \item{carat}{weight of the diamond (0.2--5.01)} #' \item{cut}{quality of the cut (Fair, Good, Very Good, Premium, Ideal)} #' \item{color}{diamond colour, from D (best) to J (worst)} #' \item{clarity}{a measurement of how clear the diamond is (I1 (worst), SI2, #' SI1, VS2, VS1, VVS2, VVS1, IF (best))} #' \item{x}{length in mm (0--10.74)} #' \item{y}{width in mm (0--58.9)} #' \item{z}{depth in mm (0--31.8)} #' \item{depth}{total depth percentage = z / mean(x, y) = 2 * z / (x + y) (43--79)} #' \item{table}{width of top of diamond relative to widest point (43--95)} #' } #' @source "diamonds" ## ---- eval = FALSE------------------------------------------------------------ # #' @details # #' The only function you're likely to need from roxygen2 is [roxygenize()]. # #' Otherwise refer to the vignettes to see how to format the documentation. # #' @keywords internal # "_PACKAGE" ## ----------------------------------------------------------------------------- #' @section Warning: #' Do not operate heavy machinery within 8 hours of using this function. ## ----------------------------------------------------------------------------- #' @details # Warning #' Do not operate heavy machinery within 8 hours of using this function. ## ----------------------------------------------------------------------------- #' @details # Warning #' You must not call this function unless ... #' #' ## Exceptions #' Apart from the following special cases... ## ----------------------------------------------------------------------------- #' @family aggregations #' @seealso [prod()] for products, [cumsum()] for cumulative sums, and #' [colSums()]/[rowSums()] marginal sums over high-dimensional arrays. ## ---- eval = FALSE------------------------------------------------------------ # list( # rd_family_title = list(aggregations = "Aggregation functions") # ) ## ----------------------------------------------------------------------------- #' Foo bar generic #' #' @param x Object to foo. foobar <- function(x) UseMethod("x") #' @describeIn foobar Difference between the mean and the median foobar.numeric <- function(x) abs(mean(x) - median(x)) #' @describeIn foobar First and last values pasted together in a string. foobar.character <- function(x) paste0(x[1], "-", x[length(x)]) ## ----------------------------------------------------------------------------- #' Basic arithmetic #' #' @param x,y numeric vectors. add <- function(x, y) x + y #' @rdname add times <- function(x, y) x * y ## ----------------------------------------------------------------------------- #' Basic arithmetic #' #' @param x,y numeric vectors. #' @name arith NULL #' @rdname arith add <- function(x, y) x + y #' @rdname arith times <- function(x, y) x * y ## ----------------------------------------------------------------------------- #' @rdname arith #' @order 2 add <- function(x, y) x + y #' @rdname arith #' @order 1 times <- function(x, y) x * y ## ----------------------------------------------------------------------------- my_params <- function() { c( "@param x An integer vector", "@param y A character vector" ) } #' A title #' #' @eval my_params() #' @export foo <- function(x, y) { } ## ----------------------------------------------------------------------------- #' A title #' #' @param x An integer vector #' @param y A character vector #' @export foo <- function(x, y) { } ## ----------------------------------------------------------------------------- my_note <- function(x) { paste0("\\note{", paste0(x, "\n", collapse =""), "}") } #' @evalRd my_note(c( #' "This is the first line", #' "This is the second line" #' )) NULL ## ----------------------------------------------------------------------------- #' @backref src/file.cpp #' @backref src/file.h roxygen2/inst/doc/extending.html0000644000176200001440000013577314115763564016460 0ustar liggesusers Extending roxygen2

Extending roxygen2

Basics

Roxygen is extensible with user-defined roclets. It means that you can take advantage of Roxygen’s parser and extend it with your own @tags.

There are two primary ways to extend roxygen2:

  • Add new tag that generates a new top-level section in .Rd files.

  • Add a new roclet that does anything you like.

This vignette will introduce you to the key data structures in roxygen2, and then show you how to use these two extension points. This vignette is very rough, so you should expect to have to also read some roxygen2 source code to understand all the extension points. Hopefully it’s useful enough to help you get started, and if you have problems, please file an issue!

library(roxygen2)

Key data structures

Before we talk about extending roxygen2, we need to first discuss two important data structures that power roxygen: tags and blocks.

Tags

A tag (a list with S3 class roxy_tag) represents a single tag. It has the following fields:

  • tag: the name of the tag.

  • raw: the raw contents of the tag (i.e. everything from the end of this tag to the beginning of the next).

  • val: the parsed value, which we’ll come back to shortly.

  • file and line: the location of the tag in the package. Used with roxy_tag_warning() to produce informative error messages.

You can construct tag objects by hand with roxy_tag():

roxy_tag("name", "Hadley")
#> [????:???] @name 'Hadley' {unparsed}
str(roxy_tag("name", "Hadley"))
#> List of 5
#>  $ file: chr NA
#>  $ line: int NA
#>  $ raw : chr "Hadley"
#>  $ tag : chr "name"
#>  $ val : NULL
#>  - attr(*, "class")= chr [1:2] "roxy_tag_name" "roxy_tag"

However, you should rarely need to do so, because you’ll typically have them given to you in a block object, as you’ll see shortly.

Blocks

A block (a list with S3 class roxy_block) represents a single roxygen block. It has the following fields:

  • tags: a list of roxy_tags.
  • call: the R code associated with the block (usually a function call).
  • file and line: the location of the R code.
  • object: the evaluated R object associated with the code.

The easiest way to see the basic structure of a roxy_block() is to generate one by parsing a roxygen block with parse_text():

text <- "
  #' This is a title
  #'
  #' This is the description.
  #'
  #' @param x,y A number
  #' @export
  f <- function(x, y) x + y
"

# parse_text() returns a list of blocks, so I extract the first
block <- parse_text(text)[[1]]
block
#> <roxy_block> [<text>:8]
#>   $tag
#>     [line:  1] @title 'This is a title' {parsed}
#>     [line:  3] @description 'This is the description.' {parsed}
#>     [line:  6] @param 'x,y A number' {parsed}
#>     [line:  7] @export '' {parsed}
#>     [????:???] @usage '<generated>' {parsed}
#>     [????:???] @.formals '<generated>' {parsed}
#>     [????:???] @backref '<text>' {parsed}
#>   $call   f <- function(x, y) x + y
#>   $object <function> 
#>     $topic f
#>     $alias f

Adding a new .Rd tag

The easiest way to extend roxygen2 is to create a new tag that adds output to .Rd files. This requires two steps:

  1. Define a roxy_tag_parse() method that describes how to parse our new tag.

  2. Define a roxy_tag_rd() method that describes how to convert the tag into .Rd commands.

To illustrate the basic idea we’ll create a new @tip tag that will create a bulleted list of tips about how to use a function. The idea is to take something like this:

#' @tip The mean of a logical vector is the proportion of `TRUE` values.
#' @tip You can compute means of dates and date-times!

And generate Rd like this:

\section{Tips and tricks}{
\itemize{
  \item The mean of a logical vector is the proportion of \code{TRUE} values.
  \item You can compute means of dates and date-times!
}
}

The first step is to define a method for roxy_tag_parse() that describes how to turn the parse the tag text. The name of the class will be roxy_tag_{tag}, which in this case is roxy_tag_tip. This function takes a roxy_tag as input, and it’s job is to set x$val to a convenient parsed value that will be used later by the roclet. Here we want to process the text using markdown so we can just use tag_markdown():

roxy_tag_parse.roxy_tag_tip <- function(x) {
  tag_markdown(x)
}

We check this works by using parse_text():

text <- "
  #' Title
  #'
  #' @tip The mean of a logical vector is the proportion of `TRUE` values.
  #' @tip You can compute means of dates and date-times!
  #' @md
  f <- function(x, y) {
    # ...
  }
"
block <- parse_text(text)[[1]]
block
#> <roxy_block> [<text>:7]
#>   $tag
#>     [line:  1] @title 'Title' {parsed}
#>     [line:  4] @tip 'The mean of a logical vector is the proportion ...' {parsed}
#>     [line:  5] @tip 'You can compute means of dates and date-times!' {parsed}
#>     [line:  6] @md '' {parsed}
#>     [????:???] @usage '<generated>' {parsed}
#>     [????:???] @.formals '<generated>' {parsed}
#>     [????:???] @backref '<text>' {parsed}
#>   $call   f <- function(x, y) { ...
#>   $object <function> 
#>     $topic f
#>     $alias f

str(block$tags[[2]])
#> List of 5
#>  $ file: chr "<text>"
#>  $ line: int 4
#>  $ tag : chr "tip"
#>  $ raw : chr "The mean of a logical vector is the proportion of `TRUE` values."
#>  $ val : chr "The mean of a logical vector is the proportion of \\code{TRUE} values."
#>  - attr(*, "class")= chr [1:2] "roxy_tag_tip" "roxy_tag"

(Here I explicit turn markdown parsing on using @md; it’s usually turned on for a package using roxygen options).

Next we define a method for roxy_tag_rd(), which must create an rd_section(). We’re going to create a new section called tip. It will contain a character vector of tips:

roxy_tag_rd.roxy_tag_tip <- function(x, base_path, env) {
  rd_section("tip", x$val)
}

This additional layer is needed because there can multiple tags of the same time in a single block, and multiple blocks can contribute to the same .Rd file. The job of the rd_section is to combine all the tags into a single top-level Rd section. Each tag generates an rd_section which is then combined with any previous section using merge(). The default merge.rd_section() just concatenates the values together (rd_section(x$type, c(x$value, y$value))); you can override this method if you need more sophisticated behaviour.

We then need to define a format() method to converts this object into text for the .Rd file:

format.rd_section_tip <- function(x, ...) {
  paste0(
    "\\section{Tips and tricks}{\n",
    "\\itemize{\n",
    paste0("  \\item ", x$value, "\n", collapse = ""),
    "}\n",
    "}\n"
  )
}

We can now try this out with roclet_text():

topic <- roc_proc_text(rd_roclet(), text)[[1]]
topic$get_section("tip")
#> \section{Tips and tricks}{
#> \itemize{
#>   \item The mean of a logical vector is the proportion of \code{TRUE} values.
#>   \item You can compute means of dates and date-times!
#> }
#> }
#> 

Note that there is no namespacing so if you’re defining multiple new tags I recommend using your package name as common prefix.

Creating a new roclet

Creating a new roclet is usually a two part process. First, you define new tags that your roclet will work with. Second, you define a roclet that tells roxygen how to process an entire package.

Custom tags

In this example we will make a new @memo tag to enable printing the memos at the console when the roclet runs. We choose that the @memo has this syntax:

@memo [Headline] Description

As an example:

@memo [EFFICIENCY] Currently brute-force; find better algorithm.

As above, we first define a parse method:

roxy_tag_parse.roxy_tag_memo <- function(x) {
  if (!grepl("^\\[.*\\].*$", x$raw)) {
    roxy_tag_warning(x, "Invalid memo format")
    return()
  }

  parsed <- stringi::stri_match(str = x$raw, regex = "\\[(.*)\\](.*)")[1, ]

  x$val <- list(
    header = parsed[[2]], 
    message = parsed[[3]]
  )
  x
}

Then check it works with parse_text():

text <- "
  #' @memo [TBI] Remember to implement this!
  #' @memo [API] Check best API
  f <- function(x, y) {
    # ...
  }
"
block <- parse_text(text)[[1]]
block
#> <roxy_block> [<text>:4]
#>   $tag
#>     [line:  2] @memo '[TBI] Remember to implement this!' {parsed}
#>     [line:  3] @memo '[API] Check best API' {parsed}
#>     [????:???] @usage '<generated>' {parsed}
#>     [????:???] @.formals '<generated>' {parsed}
#>     [????:???] @backref '<text>' {parsed}
#>   $call   f <- function(x, y) { ...
#>   $object <function> 
#>     $topic f
#>     $alias f

str(block$tags[[1]])
#> List of 5
#>  $ file: chr "<text>"
#>  $ line: int 2
#>  $ tag : chr "memo"
#>  $ raw : chr "[TBI] Remember to implement this!"
#>  $ val :List of 2
#>   ..$ header : chr "TBI"
#>   ..$ message: chr " Remember to implement this!"
#>  - attr(*, "class")= chr [1:2] "roxy_tag_memo" "roxy_tag"

The roclet

Next we create a constructor for the roclet, which uses roclet(). Our memo roclet doesn’t have any options so this is very simple:

memo_roclet <- function() {
  roclet("memo")
}

To give the roclet behaviour, you need to define method. There are two methods that almost every roclet will use:

  • roclet_process() is called with a list of blocks, and returns an object of your choosing.

  • roclet_output(): performs side-effects (usually writing to disk) using the result from roclet_process()

For this roclet, we’ll have roclet_process() collect all the memo tags into a named list:

roclet_process.roclet_memo <- function(x, blocks, env, base_path) {
  results <- list()
  
  for (block in blocks) {
    tags <- block_get_tags(block, "memo")

    for (tag in tags) {
      msg <- paste0("[", tag$file, ":", tag$line, "] ", tag$val$message)
      results[[tag$val$header]] <- c(results[[tag$val$header]], msg)
    }
  }
  
  results
}

And then have roclet_output() just print them to the screen:

roclet_output.roclet_memo <- function(x, results, base_path, ...) {
  for (header in names(results)) {
    messages <- results[[header]]
    cat(paste0(header, ": ", "\n"))
    cat(paste0(" * ", messages, "\n", collapse = ""))
  }

  invisible(NULL)
}

Then you can test it works by using roc_proc_text():

results <- roc_proc_text(memo_roclet(), "
#' @memo [TBI] Remember to implement this!
#' @memo [API] Check best API
f <- function(x, y) {
  # ...
}

#' @memo [API] Consider passing z option
g <- function(x, y) {
  # ...
}
")
roclet_output(memo_roclet(), results)
#> TBI: 
#>  * [<text>:2]  Remember to implement this!
#> API: 
#>  * [<text>:3]  Check best API
#>  * [<text>:8]  Consider passing z option
roxygen2/inst/doc/roxygen2.Rmd0000644000176200001440000001346613631761325016013 0ustar liggesusers--- title: "Introduction to roxygen2" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Getting started with roxygen2} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ``` Documentation is one of the most important aspects of good code. Without it, users won't know how to use your package, and are unlikely to do so. Documentation is also useful for you in the future (so you remember what the heck you were thinking!), and for other developers working on your package. The goal of roxygen2 is to make documenting your code as easy as possible. R provides a standard way of documenting packages: you write `.Rd` files in the `man/` directory. These files use a custom syntax, loosely based on latex. Roxygen2 provides a number of advantages over writing `.Rd` files by hand: * Code and documentation are adjacent so when you modify your code, it's easy to remember that you need to update the documentation. * Roxygen2 dynamically inspects the objects that it's documenting, so it can automatically add data that you'd otherwise have to write by hand. * It abstracts over the differences in documenting S3 and S4 methods, generics and classes so you need to learn fewer details. As well as generating `.Rd` files, roxygen will also create a `NAMESPACE` for you, and will manage the `Collate` field in `DESCRIPTION`. This vignette provides a high-level description of roxygen2 and how the three main components work. The other vignettes provide more detail on the most important individual components: * [Generating .Rd files](rd.html) and [text formatting](rd-formatting.html) describe how to generate function documentation via `.Rd` files * [Managing your `NAMESPACE`](namespace.html) describes how to generate a `NAMESPACE` file, how namespacing works in R, and how you can use Roxygen2 to be specific about what your package needs and supplies. * See [update_collate()] for the details of `@include`, which for complicated reasons is not implemented as a roclet. ## Running roxygen There are three main ways to run roxygen: * `roxygen2::roxygenise()`. * `devtools::document()`. * `Ctrl + Shift + D`, if you're using RStudio. You can mix handwritten Rd and roxygen2; roxygen2 will never overwrite a file it didn't create. ## Basic process There are three steps in the transformation from roxygen comments in your source file to human readable documentation: 1. You add roxygen comments to your source file. 2. `roxygen2::roxygenise()` converts roxygen comments to `.Rd` files. 3. R converts `.Rd` files to human readable documentation. The process starts when you add specially formatted roxygen comments to your source file. Roxygen comments start with `#'` so you can continue to use regular comments for other purposes. ```{r} #' Add together two numbers #' #' @param x A number #' @param y A number #' @return The sum of \code{x} and \code{y} #' @examples #' add(1, 1) #' add(10, 1) add <- function(x, y) { x + y } ``` For the example, above, this will generate `man/add.Rd` that looks like: ``` % Generated by roxygen2 (3.2.0): do not edit by hand \name{add} \alias{add} \title{Add together two numbers} \usage{ add(x, y) } \arguments{ \item{x}{A number} \item{y}{A number} } \value{ The sum of \code{x} and \code{y} } \description{ Add together two numbers } \examples{ add(1, 1) add(10, 1) } ``` Rd files are a special file format loosely based on LaTeX. You can read more about the Rd format in the [R extensions](https://cran.r-project.org/doc/manuals/R-exts.html#Rd-format) manual. With roxygen2, there are few reasons to know about Rd files, so here I'll avoid discussing them as much as possible, focussing instead on what you need to know about roxygen2. When you use `?x`, `help("x")` or `example("x")` R looks for an Rd file containing `\alias{x}`. It then parses the file, converts it into html and displays it. These functions look for an Rd file in _installed_ packages. This isn't very useful for package development, because you want to use the `.Rd` files in the _source_ package. For this reason, we recommend that you use roxygen2 in conjunction with devtools: `devtools::load_all()` automatically adds shims so that `?` and friends will look in the development package. Note, however, that this preview does not work with intra-package links. To preview those, you'll need to install the package. If you use RStudio, the easiest way to do this is to click the "Build & Reload button". ### Rcpp You can also use roxygen2 with Rcpp. Simply include roxygen2 comments in your C++ code (using `//` instead of `#`), and Rcpp will automatically carry the comments along into `RcppExports.R` where roxygen2 will find them. For example, dplyr has `between.cpp` which starts: ```cpp //' Do values in a numeric vector fall in specified range? //' //' This is a shortcut for `x >= left & x <= right`, implemented //' efficiently in C++ for local values, and translated to the //' appropriate SQL for remote tables. //' //' @param x A numeric vector of values //' @param left,right Boundary values //' @export //' @examples //' between(1:12, 7, 9) //' //' x <- rnorm(1e2) //' x[between(x, -1, 1)] // [[Rcpp::export(rng = false)]] Rcpp::LogicalVector between(Rcpp::NumericVector x, double left, double right) { } ``` This is automatically translated to the following R code in `RcppExports.R`: ```{r, eval = FALSE} #' Do values in a numeric vector fall in specified range? #' #' This is a shortcut for `x >= left & x <= right`, implemented #' efficiently in C++ for local values, and translated to the #' appropriate SQL for remote tables. #' #' @param x A numeric vector of values #' @param left,right Boundary values #' @export #' @examples #' between(1:12, 7, 9) #' #' x <- rnorm(1e2) #' x[between(x, -1, 1)] between <- function(x, left, right) { } ``` roxygen2/inst/doc/rd-formatting.Rmd0000644000176200001440000005073214115761663017013 0ustar liggesusers--- title: "Rd formatting" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Rd formatting} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ``` # Introduction Starting from version 6.0.0, roxygen supports markdown markup within most roxygen tags. Roxygen uses the [commonmark package](https://github.com/r-lib/commonmark), which is based on the CommonMark Reference Implementation to parse these tags. See for more about the parser and the markdown language it supports. You can also still use the `.Rd` syntax, some of which we will present below in the [Rd syntax](#rd-syntax) section. # Turning on markdown support There are two ways to turn on markdown support for a package: globally, at the package level, and locally at the block level. To turn on markdown for the whole package, insert this entry into the `DESCRIPTION` file of the package: ``` Roxygen: list(markdown = TRUE) ``` The position of the entry in the file does not matter. After this, all Roxygen documentation will be parsed as markdown. Alternatively, you can use the `@md` tag to turn on markdown support for a single documentation chunk. This is a good option to write any new documentation for existing packages in markdown. There is also a new `@noMd` tag. Use this if you turned on markdown parsing globally, but need to avoid it for a single chunk. This tag is handy if the markdown parser interferes with more complex Rd syntax. Here is an example roxygen chunk that uses markdown. ```r #' Use roxygen to document a package #' #' This function is a wrapper for the [roxygen2::roxygenize()] function from #' the roxygen2 package. See the documentation and vignettes of #' that package to learn how to use roxygen. #' #' @param pkg package description, can be path or package name. See #' [as.package()] for more information #' @param clean,reload Deprecated. #' @inheritParams roxygen2::roxygenise #' @seealso [roxygen2::roxygenize()], `browseVignettes("roxygen2")` #' @export #' @md ``` # Syntax ## Sections The usual markdown heading markup creates sections and subsections. Top level headings, i.e. '`#`' create sections, via the `\section{}` Rd tag. '`#`' may only appear after the `@description` and `@details` tags. Since `@details` can appear multiple times in a block, you can always precede a '`#`' section with `@details`, if you prefer to place it towards the end of the block, after `@return` for example: ```r #' @details #' Trim the leading and trailing whitespace from a character vector. #' #' @param x Character vector. #' @return Character vector, with the whitespace trimmed. #' #' @details # This will be a new section #' ... ``` Top level sections are always placed at a fixed position in the manual page, after the parameters and the details, but before `\note{}`, `\seealso{}` and the `\examples{}`. Their order will be the same as in the roxygen block. ## Subsections Headings at level two and above may appear inside any roxygen tag that formats lines of text. E.g. `@description`, `@details`, `@return`, etc. They create subsections, via the `\subsection{}` Rd tag. They are allowed within top level sections as well, i.e. after '`#`'. Subsections can be nested. Example: ```r #' @details #' ## Subsection within details #' ### Sub-subsection #' ... text ... ``` ## Emphasis *Emphasis* and **strong** (bold) text are supported. For emphasis, put the text between asterisks or underline characters. For strong text, use two asterisks at both sides. ```r #' @references #' Robert E Tarjan and Mihalis Yannakakis. (1984). Simple #' linear-time algorithms to test chordality of graphs, test acyclicity #' of hypergraphs, and selectively reduce acyclic hypergraphs. #' *SIAM Journal of Computation* **13**, 566-579. ``` ```r #' See `::is_falsy` for the definition of what is _falsy_ #' and what is _truthy_. ``` ## Code Inline code is supported via backticks. ```r #' @param ns Optionally, a named vector giving prefix-url pairs, as #' produced by `xml_ns`. If provided, all names will be explicitly #' qualified with the ns prefix, i.e. if the element `bar` is defined ... ``` You can also use this syntax to run custom R code and insert its output into the manual page. See section 'Dynamic R code' below. For blocks of code, put your code between triple backticks: ```r #' ``` #' pkg <- make_packages( #' foo1 = { f <- function() print("hello!") ; d <- 1:10 }, #' foo2 = { f <- function() print("hello again!") ; d <- 11:20 } #' ) #' foo1::f() #' foo2::f() #' foo1::d #' foo2::d #' dispose_packages(pkg) #' ``` ``` Note that this is not needed in `@examples`, since its contents are formatted as R code, anyway. You can use similar syntax to include a block of R code and/or its output in the manual page. See section 'Dynamic R code' below. ## Lists Regular Markdown lists are recognized and converted to `\enumerate{}` or `\itemize{}` lists: ```r #' There are two ways to use this function: #' 1. If its first argument is not named, then it returns a function #' that can be used to color strings. #' 1. If its first argument is named, then it also creates a #' style with the given name. This style can be used in #' `style`. One can still use the return value #' of the function, to create a style function. ``` ```r #' The style (the `...` argument) can be anything of the #' following: #' * An R color name, see `colors()`. #' * A 6- or 8-digit hexa color string, e.g. `#ff0000` means #' red. Transparency (alpha channel) values are ignored. #' * A one-column matrix with three rows for the red, green #' and blue channels, as returned by [grDevices::col2rgb()] ``` Nested lists are also supported. Note that you do not have to leave an empty line before the list. This is different from some markdown parsers. ## Tables Use [GFM table formatting](https://github.github.com/gfm/#tables-extension-): ```r | foo | bar | | --- | --- | | baz | bim | ``` By default, columns are left-aligned. Use colons to generate right and center aligned columns: ```r | left | center | right | | :--- | :----: | ----: | | 1 | 2 | 3 | ``` ## Links Markdown hyperlinks work as usual: ```r #' See more about the markdown markup at the #' [Commonmark web site](http://commonmark.org/help) ``` URLs inside angle brackets are also automatically converted to hyperlinks: ```r #' The main R web site is at . ``` Markdown notation can also be used to create links to other help topics. There are two basic forms: * `[ref]`: The target topic and the link text are one and the same. * `[text][ref]`: Link text differs from the target. First we explore the simplest form: `[ref]`. The presence of trailing parentheses, e.g., `[func()]`, signals that the target `func` is a function, which causes two things to happen: * The link text `func()` is automatically typeset as code. * The parentheses are stripped in the derived Rd link target. +--------------------+------------------------+---------------------------------------------+ | `[ref]`\ | Links to help\ | Notes | | examples | topic for ... | | +:===================+:=======================+:============================================+ | `[func()]`\ | a function in same\ | Always typeset as code.\ | | `[pkg::func()]` | package or in `pkg` | Produces Rd: `\code{\link[=func]{func()}}`\ | | | | or `\code{\link[pkg:func]{pkg::func()}}` | +--------------------+------------------------+---------------------------------------------+ | `[thing]`\ | a topic in same\ | Use for a topic that documents `NULL` and name is set\ | | `[pkg::thing]` | package or in `pkg` | via `@name`, e.g., a dataset or concept.\ | | | | Not typeset as code.\ | | | | Produces Rd: `\link{thing}` or\ | | | | `\link[pkg:thing]{pkg::thing}` | +--------------------+------------------------+---------------------------------------------+ | ``[`thing`]``\ | a topic in same\ | Same as above, but explicit backticks\ | | ``[`pkg::thing`]`` | package or in `pkg` | mean that it **is** typeset as code.\ | | | | Good for documenting a class.\ | | | | Produces Rd: `\code{\link{thing}}` or\ | | | | `\code{\link[pkg:thing]{pkg::thing}`} | +--------------------+------------------------+---------------------------------------------+ Use the second form `[text][ref]` to link to the topic specified by `ref`, but with `text` as the link text. +-----------------------+------------------------+-----------------------------+ | `[text][ref]`\ | Links to help\ | Notes | | examples | topic for ... | | +:======================+:=======================+:============================+ | `[text][func()]`\ | a function in same\ | Text is not typeset as code.\ | | `[text][pkg::func()]` | package or in `pkg` | Produces Rd: `\link[=func]{text}` or\ | | | | `\link[pkg:func]{text}` | +-----------------------+------------------------+-----------------------------+ | `[text][thing]`\ | a topic in same\ | Text is not typeset as code.\ | | `[text][pkg::thing]` | package or in `pkg` | Use for a topic that documents `NULL`\ | | | | and name is set via `@name`,\ | | | | e.g., a dataset or concept.\ | | | | Produces Rd: `\link[=thing]{text}` or\ | | | | `\link[pkg:thing]{text}` | +-----------------------+------------------------+-----------------------------+ In the `[text][ref]`, the link text is treated like normal text by default. * Use backticks to typeset the link text as code: ``[`text`][ref]``. It is never appropriate to use backticks around the `ref` in this form. * No, do not do this: ``[text][`blah-blah`]`` * Yes, do this instead: `[text][blah-blah]` S3 and S4 class *not done yet* +-----------------------+------------------------+--------------------------+ | Examples | Help topic\ | Notes | | | for what? | | +:======================+:=======================+:=========================+ | `[abc-class]`\ | an S4 class named\ | In Rd: `\linkS4class{abc}` or\ | | `[pkg::abc-class]` | "abc" in same package\ | `\link[pkg:abc-class]{pkg::abc}` | | | or in `pkg` | | +-----------------------+------------------------+--------------------------+ | `[abc][abc-class]` | *is this a thing? | ??? `\link[=abc-class]{abc}` | +-----------------------+------------------------+--------------------------+ ## Images Markdown syntax for inline images works. The image files must be in the `man/figures` directory: ```r #' Here is an example plot: #' ![](example-plot.jpg "Example Plot Title") ``` # Dynamic R code Similarly to the knitr package, you can use the markdown inline code markup or markdown code blocks to evaluate R code and insert its output into the manual page. ## Inline code To do this, prefix the code with `r `, i.e. the lowercase letter 'r' and a space character. Roxygen will interpret the rest of the text within backticks as R code and evaluate it, and replace the backtick expression with its value. After all such substitutions, the text of the whole tag is interpreted as markdown, as usual. For example, the following will insert the date and the R version of the roxygen run. ```r #' Roxygen created this manual page on `r "\x60r Sys.Date()\x60"` using R version #' `r "\x60r getRversion()\x60"`. ``` The value of the R expression is converted to a character string, with `paste(collapse = "\n")`. So you don't need explicitly convert to a character value, numeric values or any R object with an `as.character()` S3 method is fine. Also, you can insert multiple lines by returning a character vector. If you want to run R code without inserting any output, return an empty string or `NULL`. The value of the expression is inserted into the text of the tag without interpreting it, before the markdown to `.Rd` conversion, so you can create markdown markup dynamically: ```r #' The `iris` data set has `r "\x60r ncol(iris)\x60"` columns: #' `r "\x60r paste0(\"\x60\x60\", colnames(iris), \"\x60\x60\", collapse = \", \")\x60"`. ``` Note that you need to escape backtick characters, if they appear in the R expression, by doubling them, like above. The result after the dynamic R code evaluation will be: ``` The `iris` data set has 5 columns: `Sepal.Length`, `Sepal.Width`, `Petal.Length`, `Petal.Width`, `Species`. ``` And the final result in the `.Rd` file will look as: ``` The \code{iris} data set has 5 columns: \code{Sepal.Length}, \code{Sepal.Width}, \code{Petal.Length}, \code{Petal.Width}, \code{Species}. ``` The R code is evaluated in a new environment that is the child of the package environment of the package you are documenting. This means that you can call (internal or exported) functions of the package. `packageName()` will also report the name of the package: ```r #' To insert the name of the current package: `r "\x60r packageName()\x60"`. ``` A new evaluation environment is created for each roxygen _block_. So the output of this code: ```r #' @title ... `r "\x60r myvar <- \"foo\"; NULL\x60"` `r "\x60r myvar\x60"` #' #' @description ... `r "\x60r myvar\x60"` ``` will be: ```r #' @title ... foo #' #' @description ... foo ``` Currently the whole code expression must be on the same line, multi-line expressions are not supported. ## Code blocks Markdown code blocks can be dynamic as well, if you use `r "\x60\x60\x60{r}"` to start them, just like in knitr documents. ```r #' ```{r} #' # This block of code will be evaluated #' summary(iris) #' ``` ``` Within a roxygen block, code blocks and inline code use the same evaluation environment, so variables created in one of them can be used in others. Code blocks support knitr chunk options, e.g. to keep the output of several expressions together, you can specify `results= "hold"`: ```r #' ```{r results = "hold"} #' names(mtcars) #' nrow(mtcars) #' ``` ``` Plots will create `.png` files in the `man/figures` directory. The file names are created from the chunk names: ```r #' ```{r iris-pairs-plot} #' pairs(iris[1:4], main = "Anderson's Iris Data -- 3 species", #' pch = 21, bg = c("red", "green3", "blue")[unclass(iris$Species)]) #' ``` ``` Note that the generated `.png` files will be added to the package, and they can considerably increase the size of the package. Note that code block support is currently experimental, and somewhat limited. Some of the known limitations: * Because the code blocks are evaluated individually, they cannot refer to each other. * Some knitr chunk options are reset at the start of every code block, so if you want to change these, you'll have to specify them for every chunk. These are currently `error`, `fig.path`, `fig.process`. * Some knitr options might not create meaningful output. * The markdown code runs every time you call `roxygenize()` (or `devtools::document()`) to generated the Rd files. This potentially makes `roxygenize()` (much) slower. You can turn on knitr caching as usual, but make sure to omit the cache from the package. # Roxygen and Rd tags *not* parsed as markdown Some of the roxygen tags are not parsed as markdown. Most of these are unlikely to contain text that needs markup, so this is not an important restriction. Tags without markdown support: `@aliases`, `@backref`, `@docType`, `@encoding`, `@evalRd`, `@example`, `@examples`, `@family`, `@inheritParams`, `@keywords`, `@method` `@name`, `@md`, `@noMd`, `@noRd`, `@rdname`, `@rawRd`, `@usage`. When mixing `Rd` and markdown notation, most `Rd` tags may contain markdown markup, the ones that can *not* are: `r paste0("\x60", roxygen2:::escaped_for_md, "\x60", collapse = ", ")`. # Possible problems ## Mixing markdown and `Rd` markup Note that turning on markdown does *not* turn off the standard `Rd` syntax. We suggest that you use the regular `Rd` tags in a markdown roxygen chunk only if necessary. The two parsers do occasionally interact, and the markdown parser can pick up and reformat Rd syntax, causing an error, or corrupted manuals. ## Leading whitespace Leading whitespace is interpreted by the commonmark parser, whereas it is ignored by the `Rd` parser (except in `\preformatted{}`). Make sure that you only include leading whitespace intentionally, for example for nested lists. ## Spurious lists The Commonmark parser does not require an empty line before lists, and this might lead to unintended lists if a line starts with a number followed by a dot, or with an asterisk followed by whitespace: ```r #' You can see more about this topic in the book cited below, on page #' 42. Clearly, the numbered list that starts here is not intentional. ``` ## Links to operators Links to operators or objects that contain special characters, do not work currently. E.g. to link to the `%>%` operator in the `magrittr` package, instead of `[magrittr::%>%]`, you will need to use the `Rd` notation: `\code{\link[magrittr]{\%>\%}}`. # Rd syntax Within roxygen tags, you can use `.Rd` syntax to format text. Below we show you examples of the most important `.Rd` markup commands. The full details are described in [R extensions](https://cran.r-project.org/doc/manuals/R-exts.html#Marking-text). Before roxygen version 6.0.0 this was the only supported syntax. Now all of the formatting described below can be achived more easily with markdown syntax, with the important exception of [mathematical expressions](https://cran.r-project.org/doc/manuals/R-exts.html#Mathematics). Note that `\` and `%` are special characters. To insert literals, escape with a backslash: `\\`, `\%`. ## Character formatting * `\emph{italics}` * `\strong{bold}` * `\code{r_function_call(with = "arguments")}`, `\code{NULL}`, `\code{TRUE}` * `\pkg{package_name}` ## Links To other documentation: * `\code{\link{function}}`: function in this package * `\code{\link[MASS]{abbey}}`: function in another package * `\link[=dest]{name}`: link to dest, but show name * `\code{\link[MASS:abbey]{name}}`: link to function in another package, but show name. * `\linkS4class{abc}`: link to an S4 class To the web: * `\url{http://rstudio.com}` * `\href{http://rstudio.com}{Rstudio}` * `\email{hadley@@rstudio.com}` (note the doubled `@`) ## Lists * Ordered (numbered) lists: ```{r} #' \enumerate{ #' \item First item #' \item Second item #' } ``` * Unordered (bulleted) lists ```{r} #' \itemize{ #' \item First item #' \item Second item #' } ``` * Definition (named) lists ```{r} #' \describe{ #' \item{One}{First item} #' \item{Two}{Second item} #' } ``` ## Mathematics Standard LaTeX (with no extensions): * `\eqn{a + b}`: inline equation * `\deqn{a + b}`: display (block) equation ## Tables Tables are created with `\tabular{}`. It has two arguments: 1. Column alignment, specified by letter for each column (`l` = left, `r` = right, `c` = centre.) 2. Table contents, with columns separated by `\tab` and rows by `\cr`. The following function turns an R data frame into the correct format, adding a row consisting of the (bolded) column names and prepending each row with `#' ` for pasting directly into the documentation. ```{r} tabular <- function(df, ...) { stopifnot(is.data.frame(df)) align <- function(x) if (is.numeric(x)) "r" else "l" col_align <- purrr::map_chr(df, align) cols <- lapply(df, format, ...) contents <- do.call("paste", c(cols, list(sep = " \\tab ", collapse = "\\cr\n#' "))) paste("#' \\tabular{", paste(col_align, collapse = ""), "}{\n#' ", paste0("\\strong{", names(df), "}", sep = "", collapse = " \\tab "), " \\cr\n#' ", contents, "\n#' }\n", sep = "") } cat(tabular(mtcars[1:5, 1:5])) ``` roxygen2/inst/doc/rd-formatting.R0000644000176200001440000000224314115763564016466 0ustar liggesusers## ---- include = FALSE--------------------------------------------------------- knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ## ----------------------------------------------------------------------------- #' \enumerate{ #' \item First item #' \item Second item #' } ## ----------------------------------------------------------------------------- #' \itemize{ #' \item First item #' \item Second item #' } ## ----------------------------------------------------------------------------- #' \describe{ #' \item{One}{First item} #' \item{Two}{Second item} #' } ## ----------------------------------------------------------------------------- tabular <- function(df, ...) { stopifnot(is.data.frame(df)) align <- function(x) if (is.numeric(x)) "r" else "l" col_align <- purrr::map_chr(df, align) cols <- lapply(df, format, ...) contents <- do.call("paste", c(cols, list(sep = " \\tab ", collapse = "\\cr\n#' "))) paste("#' \\tabular{", paste(col_align, collapse = ""), "}{\n#' ", paste0("\\strong{", names(df), "}", sep = "", collapse = " \\tab "), " \\cr\n#' ", contents, "\n#' }\n", sep = "") } cat(tabular(mtcars[1:5, 1:5])) roxygen2/inst/doc/extending.Rmd0000644000176200001440000002215613556660006016217 0ustar liggesusers--- title: "Extending roxygen2" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Extending roxygen2} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ``` ## Basics Roxygen is extensible with user-defined __roclets__. It means that you can take advantage of Roxygen's parser and extend it with your own `@tags`. There are two primary ways to extend roxygen2: * Add new tag that generates a new top-level section in `.Rd` files. * Add a new roclet that does anything you like. This vignette will introduce you to the key data structures in roxygen2, and then show you how to use these two extension points. This vignette is very rough, so you should expect to have to also read some roxygen2 source code to understand all the extension points. Hopefully it's useful enough to help you get started, and if you have problems, please [file an issue](https://github.com/r-lib/roxygen2/issues/new)! ```{r setup} library(roxygen2) ``` ## Key data structures Before we talk about extending roxygen2, we need to first discuss two important data structures that power roxygen: tags and blocks. ### Tags A tag (a list with S3 class `roxy_tag`) represents a single tag. It has the following fields: * `tag`: the name of the tag. * `raw`: the raw contents of the tag (i.e. everything from the end of this tag to the beginning of the next). * `val`: the parsed value, which we'll come back to shortly. * `file` and `line`: the location of the tag in the package. Used with `roxy_tag_warning()` to produce informative error messages. You _can_ construct tag objects by hand with `roxy_tag()`: ```{r} roxy_tag("name", "Hadley") str(roxy_tag("name", "Hadley")) ``` However, you should rarely need to do so, because you'll typically have them given to you in a block object, as you'll see shortly. ### Blocks A block (a list with S3 class `roxy_block`) represents a single roxygen block. It has the following fields: * `tags`: a list of `roxy_tags`. * `call`: the R code associated with the block (usually a function call). * `file` and `line`: the location of the R code. * `object`: the evaluated R object associated with the code. The easiest way to see the basic structure of a `roxy_block()` is to generate one by parsing a roxygen block with `parse_text()`: ```{r} text <- " #' This is a title #' #' This is the description. #' #' @param x,y A number #' @export f <- function(x, y) x + y " # parse_text() returns a list of blocks, so I extract the first block <- parse_text(text)[[1]] block ``` ## Adding a new `.Rd` tag The easiest way to extend roxygen2 is to create a new tag that adds output to `.Rd` files. This requires two steps: 1. Define a `roxy_tag_parse()` method that describes how to parse our new tag. 1. Define a `roxy_tag_rd()` method that describes how to convert the tag into `.Rd` commands. To illustrate the basic idea we'll create a new `@tip` tag that will create a bulleted list of tips about how to use a function. The idea is to take something like this: ```{r} #' @tip The mean of a logical vector is the proportion of `TRUE` values. #' @tip You can compute means of dates and date-times! ``` And generate Rd like this: ```latex \section{Tips and tricks}{ \itemize{ \item The mean of a logical vector is the proportion of \code{TRUE} values. \item You can compute means of dates and date-times! } } ``` The first step is to define a method for `roxy_tag_parse()` that describes how to turn the parse the tag text. The name of the class will be `roxy_tag_{tag}`, which in this case is `roxy_tag_tip`. This function takes a `roxy_tag` as input, and it's job is to set `x$val` to a convenient parsed value that will be used later by the roclet. Here we want to process the text using markdown so we can just use `tag_markdown()`: ```{r} roxy_tag_parse.roxy_tag_tip <- function(x) { tag_markdown(x) } ``` ```{r, include = FALSE} # Needed for vignette registerS3method("roxy_tag_parse", "roxy_tag_tip", roxy_tag_parse.roxy_tag_tip) ``` We check this works by using `parse_text()`: ```{r} text <- " #' Title #' #' @tip The mean of a logical vector is the proportion of `TRUE` values. #' @tip You can compute means of dates and date-times! #' @md f <- function(x, y) { # ... } " block <- parse_text(text)[[1]] block str(block$tags[[2]]) ``` (Here I explicit turn markdown parsing on using `@md`; it's usually turned on for a package using roxygen options). Next we define a method for `roxy_tag_rd()`, which must create an `rd_section()`. We're going to create a new section called `tip`. It will contain a character vector of tips: ```{r} roxy_tag_rd.roxy_tag_tip <- function(x, base_path, env) { rd_section("tip", x$val) } ``` ```{r, include = FALSE} # Needed for vignette registerS3method("roxy_tag_rd", "roxy_tag_tip", roxy_tag_rd.roxy_tag_tip) ``` This additional layer is needed because there can multiple tags of the same time in a single block, and multiple blocks can contribute to the same `.Rd` file. The job of the `rd_section` is to combine all the tags into a single top-level Rd section. Each tag generates an `rd_section` which is then combined with any previous section using `merge()`. The default `merge.rd_section()` just concatenates the values together (`rd_section(x$type, c(x$value, y$value))`); you can override this method if you need more sophisticated behaviour. We then need to define a `format()` method to converts this object into text for the `.Rd` file: ```{r} format.rd_section_tip <- function(x, ...) { paste0( "\\section{Tips and tricks}{\n", "\\itemize{\n", paste0(" \\item ", x$value, "\n", collapse = ""), "}\n", "}\n" ) } ``` ```{r, include = FALSE} # Needed for vignette registerS3method("format", "rd_section_tip", format.rd_section_tip) ``` We can now try this out with `roclet_text()`: ```{r} topic <- roc_proc_text(rd_roclet(), text)[[1]] topic$get_section("tip") ``` Note that there is no namespacing so if you're defining multiple new tags I recommend using your package name as common prefix. ## Creating a new roclet Creating a new roclet is usually a two part process. First, you define new tags that your roclet will work with. Second, you define a roclet that tells roxygen how to process an entire package. ### Custom tags In this example we will make a new `@memo` tag to enable printing the memos at the console when the roclet runs. We choose that the `@memo` has this syntax: ``` @memo [Headline] Description ``` As an example: ``` @memo [EFFICIENCY] Currently brute-force; find better algorithm. ``` As above, we first define a parse method: ```{r} roxy_tag_parse.roxy_tag_memo <- function(x) { if (!grepl("^\\[.*\\].*$", x$raw)) { roxy_tag_warning(x, "Invalid memo format") return() } parsed <- stringi::stri_match(str = x$raw, regex = "\\[(.*)\\](.*)")[1, ] x$val <- list( header = parsed[[2]], message = parsed[[3]] ) x } ``` ```{r, include = FALSE} # Needed for vignette registerS3method("roxy_tag_parse", "roxy_tag_memo", roxy_tag_parse.roxy_tag_memo) ``` Then check it works with `parse_text()`: ```{r} text <- " #' @memo [TBI] Remember to implement this! #' @memo [API] Check best API f <- function(x, y) { # ... } " block <- parse_text(text)[[1]] block str(block$tags[[1]]) ``` ### The roclet Next we create a constructor for the roclet, which uses `roclet()`. Our `memo` roclet doesn't have any options so this is very simple: ```{r} memo_roclet <- function() { roclet("memo") } ``` To give the roclet behaviour, you need to define method. There are two methods that almost every roclet will use: * `roclet_process()` is called with a list of blocks, and returns an object of your choosing. * `roclet_output()`: performs side-effects (usually writing to disk) using the result from `roclet_process()` For this roclet, we'll have `roclet_process()` collect all the memo tags into a named list: ```{r} roclet_process.roclet_memo <- function(x, blocks, env, base_path) { results <- list() for (block in blocks) { tags <- block_get_tags(block, "memo") for (tag in tags) { msg <- paste0("[", tag$file, ":", tag$line, "] ", tag$val$message) results[[tag$val$header]] <- c(results[[tag$val$header]], msg) } } results } ``` And then have `roclet_output()` just print them to the screen: ```{r} roclet_output.roclet_memo <- function(x, results, base_path, ...) { for (header in names(results)) { messages <- results[[header]] cat(paste0(header, ": ", "\n")) cat(paste0(" * ", messages, "\n", collapse = "")) } invisible(NULL) } ``` ```{r, include = FALSE} # Needed for vignette registerS3method("roclet_process", "roclet_memo", roclet_process.roclet_memo) registerS3method("roclet_output", "roclet_memo", roclet_output.roclet_memo) ``` Then you can test it works by using `roc_proc_text()`: ```{r} results <- roc_proc_text(memo_roclet(), " #' @memo [TBI] Remember to implement this! #' @memo [API] Check best API f <- function(x, y) { # ... } #' @memo [API] Consider passing z option g <- function(x, y) { # ... } ") roclet_output(memo_roclet(), results) ``` roxygen2/inst/doc/rd.Rmd0000644000176200001440000006663214047223751014644 0ustar liggesusers--- title: "Rd (documentation) tags" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Rd (documentation) tags} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ``` ## Basics A roxygen __block__ is a sequence of lines starting with `#'` (optionally preceded by whitespace). Blocks gain additional structure through the use of __tags__ like `@tag details`. Tags must start at the beginning of a line, and the content of a tag extends to the start of the next tag (or the end of the block). Text within roxygen blocks can be formatted using markdown or `Rd` commands; see `vignette("rd-formatting")` for details. ## The description block Each documentation block starts with some text which defines the title, the description, and the details. Here's an example showing what the documentation for `sum()` might look like if it had been written with roxygen: ```{r} #' Sum of vector elements #' #' `sum` returns the sum of all the values present in its arguments. #' #' This is a generic function: methods can be defined for it directly #' or via the [Summary()] group generic. For this to work properly, #' the arguments `...` should be unnamed, and dispatch is on the #' first argument. sum <- function(..., na.rm = TRUE) {} ``` This introductory block is broken up as follows: * The first sentence is the __title__: that's what you see when you look at `help(package = mypackage)` and is shown at the top of each help file. It should generally fit on one line, be written in sentence case, and not end in a full stop. * The second paragraph is the __description__: this comes first in the documentation and should briefly describe what the function does. * The third and subsequent paragraphs go into the __details__: this is a (often long) section that comes after the argument description and should provide any other important details of how the function operates. The details are optional. You can also use explicit `@title`, `@description`, and `@details` tags. This is unnecessary unless you want to have a multi-paragraph description, bulleted list, or other more exotic structure. ```{r} #' Sum of vector elements #' #' @description #' `sum` returns the sum of all the values present in its arguments. #' #' @details #' This is a generic function: methods can be defined for it directly #' or via the [Summary()] group generic. For this to work properly, #' the arguments `...` should be unnamed, and dispatch is on the #' first argument. ``` ## Object specifics Further details of roxygen2 depend on what you're documenting. The following sections describe the most commonly used tags for functions, S3, S4, datasets, and packages. ### Functions Functions are the mostly commonly documented objects. Most functions use three tags: * `@param name description` describes the inputs to the function. The description should provide a succinct summary of the type of the parameter (e.g. a string, a numeric vector), and if not obvious from the name, what the parameter does. The description should start with a capital letter and end with a full stop. It can span multiple lines (or even paragraphs) if necessary. All parameters must be documented. You can document multiple arguments in one place by separating the names with commas (no spaces). For example, to document both `x` and `y`, you can say `@param x,y Numeric vectors`. * `@examples` provides executable R code showing how to use the function in practice. This is a very important part of the documentation because many people look at the examples before reading anything. Example code must work without errors as it is run automatically as part of `R CMD check`. However for the purpose of illustration, it's often useful to include code that causes an error. `\dontrun{}` allows you to include code in the example that is never used. There are two other special commands. `\dontshow{}` is run, but not shown in the help page: this can be useful for informal tests. `\donttest{}` is run in examples, but not run automatically in `R CMD check`. This is useful if you have examples that take a long time to run. The options are summarised below. Command | example | help | R CMD check | R CMD check --as-cran ------------ | --------- | ------ | ----------- | --------------------- `\dontrun{}` | | x | | `\dontshow{}`| x | | x | x `\donttest{}`| x | x | | x Note that `R CMD check --as-cran` is run for incoming CRAN checks but not for regular CRAN checks. For finer control you can use `@examplesIf ```r #' @examplesIf interactive() #' browseURL("https://roxygen2.r-lib.org") ``` will generate ``` \examples{ \dontshow{if (interactive() (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} gh_organizations(since = 42) \dontshow{\}) # examplesIf} } ``` This way the code evaluating whether the example can be run is not shown to users reading the help, but it still prevents R CMD check failures. Instead of including examples directly in the documentation, you can put them in separate files and use `@example path/relative/to/package/root` to insert them into the documentation. * `@return description` describes the output from the function. This is not always necessary, but is a good idea if you return different types of outputs depending on the input, or you're returning an S3, S4 or RC object. We could use these new tags to improve our documentation of `sum()` as follows: ```{r} #' Sum of vector elements #' #' `sum()` returns the sum of all the values present in its arguments. #' #' This is a generic function: methods can be defined for it directly #' or via the [Summary] group generic. For this to work properly, #' the arguments `...` should be unnamed, and dispatch is on the #' first argument. #' #' @param ... Numeric, complex, or logical vectors. #' @param na.rm A logical scalar. Should missing values (including `NaN`) #' be removed? #' @return If all inputs are integer and logical, then the output #' will be an integer. If integer overflow #' () occurs, the output #' will be NA with a warning. Otherwise it will be a length-one numeric or #' complex vector. #' #' Zero-length vectors have sum 0 by definition. See #' for more details. #' @examples #' sum(1:10) #' sum(1:5, 6:10) #' sum(F, F, F, T, T) #' #' sum(.Machine$integer.max, 1L) #' sum(.Machine$integer.max, 1) #' #' \dontrun{ #' sum("a") #' } sum <- function(..., na.rm = TRUE) {} ``` Indent the second and subsequent lines of a tag so that when scanning the documentation so it's easy to see where one tag ends and the next begins. Tags that always span multiple lines (like `@example`) should start on a new line and don't need to be indented. ### S3 * S3 __generics__ are regular functions, so document them as such. If necessary, include a `@section` that provides additional details for method implementors * S3 __classes__ have no formal definition, so document the [constructor](https://adv-r.hadley.nz/s3.html#s3-constructor). * It is your choice whether or not to document S3 __methods__. Generally, it's not necessary to document straightforward methods for common generics like `print()`. (You should, however, always `@export` S3 methods). If your method is more complicated, you should document it by setting `@rdname`. Typically you will document methods with their generic, so you'd document `foofy.data.frame` by setting `@rdname`. In base R, you can find documentation for more complex methods like `?predict.lm`, `?predict.glm`, and `?anova.glm`. Generally, roxygen2 will automatically figure out the generic that the method belongs to, and you should only need to use `@method` if there is ambiguity. For example, is `all.equal.data.frame()` the `equal.data.frame` method for `all()`, or the `data.frame` method for `all.equal()`?. If this happens to you, disambiguate with (e.g.) `@method all.equal data.frame`. ### S4 S4 __generics__ are also functions, so document them as such. Document __S4 classes__ by adding a roxygen block before `setClass()`. Use `@slot` to document the slots of the class. Here's a simple example: ```{r} #' An S4 class to represent a bank account #' #' @slot balance A length-one numeric vector Account <- setClass("Account", slots = list(balance = "numeric") ) ``` S4 __methods__ are a little more complicated. Unlike S3 methods, all S4 methods must be documented. You can document them in three places: * In the class. Most appropriate if the corresponding generic uses single dispatch and you created the class. * In the generic. Most appropriate if the generic uses multiple dispatch and you control it. * In its own file. Most appropriate if the method is complex. or the either two options don't apply. Use either `@rdname` or `@describeIn` to control where method documentation goes. See the next section for more details. ### R6 Starting from version 7.0.0 roxygen treats documentation for R6 classes specially: * R6 methods can be documented in-line, i.e. the method's documentation comments come right before the definition of the method. * Method documentation can use the `@description`, `@details`, `@param`, `@return` and `@examples` tags. These are used to create a subsection for the method, within a separate 'Methods' section. All roxygen comment lines of a method documentation must appear after a tag. * `@param` tags that appear before the class definition are automatically inherited by all methods, if needed. * R6 fields and active bindings can make use of the `@field` tag. Their documentation should also be in-line. * Roxygen2 checks that all public methods, public fields, active bindings and all method arguments are documented, and issues warnings otherwise. * To turn off the special handling of R6 classes and go back to the roxygen2 6.x.x behavior, use the `r6 = FALSE` option in `DESCRIPTION`, in the `Roxygen` entry: `Roxygen: list(r6 = FALSE)`. Roxygen2 automatically generates additional sections for an R6 class: * A section with information about the superclass(es) of the class, with links. In HTML this includes a list of all inherited methods, with links. * An 'Examples' section that contains all class and method examples. This section is run by `R CMD check`, so method examples must work without errors. An example from the R6 tutorial: ```{r} #' R6 Class Representing a Person #' #' @description #' A person has a name and a hair color. #' #' @details #' A person can also greet you. Person <- R6::R6Class("Person", public = list( #' @field name First or full name of the person. name = NULL, #' @field hair Hair color of the person. hair = NULL, #' @description #' Create a new person object. #' @param name Name. #' @param hair Hair color. #' @return A new `Person` object. initialize = function(name = NA, hair = NA) { self$name <- name self$hair <- hair self$greet() }, #' @description #' Change hair color. #' @param val New hair color. #' @examples #' P <- Person("Ann", "black") #' P$hair #' P$set_hair("red") #' P$hair set_hair = function(val) { self$hair <- val }, #' @description #' Say hi. greet = function() { cat(paste0("Hello, my name is ", self$name, ".\n")) } ) ) ``` ### Datasets Datasets are usually stored as `.rdata` files in `data/` and not as regular R objects in the package. This means you need to document them slightly differently: instead of documenting the data directly, you quote the dataset's name. ```{r} #' Prices of 50,000 round cut diamonds #' #' A dataset containing the prices and other attributes of almost 54,000 #' diamonds. #' #' @format A data frame with 53940 rows and 10 variables #' \describe{ #' \item{price}{price in US dollars (\$326--\$18,823)} #' \item{carat}{weight of the diamond (0.2--5.01)} #' \item{cut}{quality of the cut (Fair, Good, Very Good, Premium, Ideal)} #' \item{color}{diamond colour, from D (best) to J (worst)} #' \item{clarity}{a measurement of how clear the diamond is (I1 (worst), SI2, #' SI1, VS2, VS1, VVS2, VVS1, IF (best))} #' \item{x}{length in mm (0--10.74)} #' \item{y}{width in mm (0--58.9)} #' \item{z}{depth in mm (0--31.8)} #' \item{depth}{total depth percentage = z / mean(x, y) = 2 * z / (x + y) (43--79)} #' \item{table}{width of top of diamond relative to widest point (43--95)} #' } #' @source "diamonds" ``` Note the use of two additional tags that are particularly useful for documenting data: * `@format`, which gives an overview of the structure of the dataset. This should include a __definition list__ that describes each variable. There's currently no way to generate this with markdown, so this is one of the few places you'll need to Rd markup directly. * `@source` where you got the data form, often a URL. ### Packages As well as documenting every object inside the package, you can also document the package itself by documenting the special sentinel `"_PACKAGE"`. We recommend placing package documentation in `{pkgname}-package.R`, and have `@keywords internal`. Here's an example: ```{r, eval = FALSE} #' @details #' The only function you're likely to need from roxygen2 is [roxygenize()]. #' Otherwise refer to the vignettes to see how to format the documentation. #' @keywords internal "_PACKAGE" ``` Package documentation is a good place to put `@section Package options:` that documents options used by the package. Some notes: * Package documentation will automatically include information parsed from the `DESCRIPTION`, including title, description, list of authors, and useful URLs. * By default, aliases will be added so that both `?pkgname` and `package?pkgname` will find the package help. If there's an existing function called `pkgname`, use `@aliases {pkgname}-package` to override the default. * `usethis::use_package_doc()` will generate a basic template to get you started. * Use `@references` to point to published material about the package that users might find helpful. ## Sections You can add arbitrary sections with the `@section` tag. This is a useful way of breaking a long details section into multiple chunks with useful headings. Section titles should be in sentence case, must fit on one line, and must be followed by a colon. ```{r} #' @section Warning: #' Do not operate heavy machinery within 8 hours of using this function. ``` You can also create sections using the markdown syntax for headers. For example, the previously-defined section can be created with markdown headers like this: ```{r} #' @details # Warning #' Do not operate heavy machinery within 8 hours of using this function. ``` Note that '`#`' may only appear after the `@description` and `@details` tags. Since `@details` can appear multiple times in a block, you can always precede a '`#`' section with `@details`. To add a subsection, use level two or greater headings: ```{r} #' @details # Warning #' You must not call this function unless ... #' #' ## Exceptions #' Apart from the following special cases... ``` If you find yourself adding a lot of sections, you might consider using a vignette instead. ## Do repeat yourself There is a tension between the DRY (do not repeat yourself) principle of programming and the need for documentation to be self-contained. It's frustrating to have to navigate through multiple help files in order to pull together all the pieces you need. Roxygen2 provides several ways to avoid repeating yourself in code documentation, while assembling information from multiple places in one documentation file: * Cross-link documentation files with `@seealso` and `@family`. * Inherit documentation from another topic with `@inherit`, `@inheritParams`, and `@inheritSection`. * Document multiple functions in the same topic with `@describeIn` or `@rdname`. * Run arbitrary R code with the markdown markup for inline code, see section 'Dynamic R code' in `vignette("rd-formatting")`. * Run arbitrary R code with `@eval`. * Create reusable templates with `@template` and `@templateVar`. ### Cross-references There are two tags that make it easier for people to navigate around your documentation: `@seealso` and `@family`. `@seealso` allows you to point to other useful resources, either on the web `` or to other documentation with `[function_name()]`. If you have a family of related functions, you can use `@family {family}` to cross-reference each function to every other function within the family. A function can be a member of multiple families. For `sum()`, this might look like: ```{r} #' @family aggregations #' @seealso [prod()] for products, [cumsum()] for cumulative sums, and #' [colSums()]/[rowSums()] marginal sums over high-dimensional arrays. ``` By default `@family {family}`, will generate the see also text "Other {family}:", so the `@family` name should be plural (i.e., "model building helpers" not "model building helper"). You can override the default title by providing a `rd_family_title` list in `man/roxygen/meta.R`: ```{r, eval = FALSE} list( rd_family_title = list(aggregations = "Aggregation functions") ) ``` ### Inheriting documentation from other topics You can inherit documentation from other functions in a few ways: * `@inherit source_function` will inherit parameters, return, references, description, details, sections, and seealso from `source_function()`. * `@inherit source_function return details` will inherit selected components from `source_function()` * `@inheritParams source_function` inherits just the parameter documentation from `source_function()`. * `@inheritSection source_function Section title` will inherit the single `@section` called "Section title" from `source_function()`. All of these work recursively so you can inherit documentation from a function that has inherited it from elsewhere. You can also inherit documentation from functions provided by another package by using `pkg::source_function`. ### Documenting multiple functions in the same file 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` `@describeIn` is designed for the most common cases: * documenting methods in a generic * documenting methods in a class * documenting functions with the same (or similar arguments) It generates a new section, named either "Methods (by class)", "Methods (by generic)" or "Functions". The section contains a bulleted list describing each function, labelled so that you know what function or method it's talking about. Here's an example, documenting an imaginary new generic: ```{r} #' Foo bar generic #' #' @param x Object to foo. foobar <- function(x) UseMethod("x") #' @describeIn foobar Difference between the mean and the median foobar.numeric <- function(x) abs(mean(x) - median(x)) #' @describeIn foobar First and last values pasted together in a string. foobar.character <- function(x) paste0(x[1], "-", x[length(x)]) ``` #### `@rdname` `@rdname` is a more general purpose tool. It overrides the default file name generated by roxygen and merges documentation for multiple objects into one file. This gives you complete freedom to combine documentation however you see fit. There are two ways to use `@rdname`. You can add documentation to an existing function: ```{r} #' Basic arithmetic #' #' @param x,y numeric vectors. add <- function(x, y) x + y #' @rdname add times <- function(x, y) x * y ``` Or, you can create a dummy documentation file by documenting `NULL` and setting an informative `@name`. ```{r} #' Basic arithmetic #' #' @param x,y numeric vectors. #' @name arith NULL #' @rdname arith add <- function(x, y) x + y #' @rdname arith times <- function(x, y) x * y ``` ### 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. ```{r} #' @rdname arith #' @order 2 add <- function(x, y) x + y #' @rdname arith #' @order 1 times <- function(x, y) x * y ``` ### Evaluating arbitrary code Another technique is the `@eval` tag. It evaluates code and treatments the result as if it was a literal roxygen tags. This makes it possible to eliminate duplication by writing functions. The code will be evaluated in the package environment and should yield a character vector of roxygen comments (but without the leading `#'`). For example, this code + roxygen block: ```{r} my_params <- function() { c( "@param x An integer vector", "@param y A character vector" ) } #' A title #' #' @eval my_params() #' @export foo <- function(x, y) { } ``` Is equivalent to: ```{r} #' A title #' #' @param x An integer vector #' @param y A character vector #' @export foo <- function(x, y) { } ``` Note that `@eval` cannot be embedded into another roxygen tag. If you want to dynamically generate part of a roxygen tag, see section 'Dynamic R code' in `vignette("rd-formatting")`. A related function is `@evalRd`. It works in the same way as `@eval` (i.e. it's evaluated in the package environment) but rather than yielding roxygen comments that are processed as if they had been typed directly, it yields top-level Rd code that is inserted directly into the generated `.Rd` file. It is primarily useful if you want to generate Rd structure that is not currently supported by roxygen2. For example, this block: ```{r} my_note <- function(x) { paste0("\\note{", paste0(x, "\n", collapse =""), "}") } #' @evalRd my_note(c( #' "This is the first line", #' "This is the second line" #' )) NULL ``` Would generate this Rd: ```latex \note{ This is the first line This is the second line } ``` ### Roxygen templates Roxygen templates are R files that contain only roxygen comments and that live in the `man-roxygen` directory. Use `@template file-name` (without extension) to insert the contents of a template into the current documentation. You can make templates more flexible by using template variables defined with `@templateVar name value`. Template files are run with brew, so you can retrieve values (or execute any other arbitrary R code) with `<%= name %>`. Note that templates are parsed a little differently to regular blocks, so you'll need to explicitly set the title, description and details with `@title`, `@description` and `@details`. ## Including external `.Rmd`/`.md` files Starting from roxygen2 7.0.0, you can use `@includeRmd path/to/file.Rmd` to include an external `.Rmd` or `.md` document into a manual page (the path is relative from the source package root directory). You can include the same file in multiple documentation files, and for the first time, share content across documentation and vignettes. ### Sections `@includeRmd` supports headings in the external Rmd. The rules are as follows: * All text before the first level 1 heading (i.e. `#`), is added to the details section. If you prefer a different section, then write the name of the section after the path in the `@includeRmd` tag, in all lowercase. Example: `@includeRmd path description`. This currently does not work with user defined sections (created with `@section`). * Level 1 headings generate their own section (`\section{}`). * Other headings (level 2 and so on) create subsections (`\subsection{}`) within the section they appear in. All content in the Rmd file will go either in the details or in new top level sections. It is currently not possible to document function arguments, return values, etc. in external Rmd documents. ### Links 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. ### Caching and figures `@includeRmd` tries to set up knitr to support caching in the Rmd file. It sets the cache path to the default knitr cache path of the included Rmd file (i.e. `foo/bar/file_cache/` for `foo/bar/file.Rmd`), so if you do not change the cache path within the Rmd itself, then everything should work out of the box. You should add these cache paths to `.gitignore` and `.Rbuildignore`. `@includeRmd` also sets the knitr figure path of the (`fig.path`) to the default figure path of the included Rmd. Overriding this default is unlikely to work. ### Sharing text between vignettes and the manual `@includeRmd` helps avoiding repetition, as you can use the same `.Rmd` or `.md` document in the manual and also in the `README.md` file or in vignettes. One way to include an Rmd file in another one is to use child documents: ```` ```{r child = "common.Rmd"}`r ''` ``` ```` If the Rmd file has links to other help topics, then some care is needed, as those links while not work in Rmd files. A workaround is to specify external HTML links for them. These external locations will _not_ be used for `@includeRmd`, which always links them 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. ## Other tags ### Indexing Three other tags make it easier for the user to find documentation within R's help system: * Aliases form the index that `?` searches. Use `@aliases space separated aliases` to add additional aliases. * `@concept` add extra keywords that will be found with `help.search()` * Use `@keywords keyword1 keyword2 ...` to add standardised keywords. Keywords are optional, but if present, must be taken from the predefined list found `file.path(R.home("doc"), "KEYWORDS")`. Apart from `@keywords internal`, these tags are not very useful because most people find documentation using Google. `@keywords internal` is useful because it removes the function from the documentation index; it's useful for functions aimed primarily at other developers, not typical users of the package. ### Back references The original source location is added as a comment to the second line of each generated `.Rd` file in the following form: ``` % Please edit documentation in ... ``` `roxygen2` tries to capture all locations from which the documentation is assembled. For code that *generates* R code with Roxygen comments (e.g., the Rcpp package), the `@backref` tag is provided. This allows specifying the "true" source of the documentation, and will substitute the default list of source files. Use one tag per source file: ```{r} #' @backref src/file.cpp #' @backref src/file.h ``` roxygen2/inst/doc/namespace.html0000644000176200001440000003040014115763564016404 0ustar liggesusers NAMESPACE tags

NAMESPACE tags

The package NAMESPACE is one of the most confusing parts of building a package. Roxygen2 aims to make it as easy as possible to build a package that is a well-behaved member of the R ecosystem. This is a little frustrating at first, but soon becomes second-nature.

Exports

For a function to be usable outside of your package, you must export it. By default roxygen2 doesn’t export anything from your package. If you want an object to be publicly available, you must explicitly tag it with @export.

Use the following guidelines to decide what to export:

  • Functions: export functions that you want to make available. Exported functions must be documented, and you must be cautious when changing their interface.

  • Datasets: all datasets are publicly available. They exist outside of the package namespace and should not be exported.

  • S3 classes: if you want others to be able to create instances of the class @export the constructor function.

  • S3 generics: the generic is a function so @export if you want it to be usable outside the package

  • S3 methods: every S3 method must be exported, even if the generic is not. Otherwise the S3 method table will not be generated correctly and internal generics will not find the correct method.

    If you are providing a method for a generic defined in another package, you must also import that generic.

  • S4 classes: if you want others to be able to extend your class, @export it. If you want others to create instances of your class, but not extend it, @export the constructor function, but not the class.

    ```R
    # Can extend and create
    #' @export
    setClass("A")
    
    # Can extend, but constructor not exported
    #' @export
    B <- setClass("B")
    
    # Can create, but not extend
    #' @export C
    C <- setClass("C")
    
    # Can create and extend
    #' @export D
    #' @exportClass D
    D <- setClass("D")
    ```
  • S4 generics: @export if you want the generic to be publicly usable.

  • S4 methods: you only need to @export methods for generics that you did not define.

  • RC classes: the same principles apply as for S4 classes. @export will only export the class.

Specialised exports

Generally, roxygen2 can generate the correct namespace directive when @exporting a specific object. However, you may want to override the defaults and exercise greater control. In this case you can use the more specialised tags described below:

  • @export foo generates export(foo)
  • @exportClass foo generates exportClasses(foo)
  • @exportMethod foo generates exportMethods(foo)
  • @exportPattern foo generates exportPattern(foo)

For even more specialised cases you can use @rawNamespace code which inserts code literally into the NAMESPACE. If you need to automate this, @evalNamespace foo() will evaluate the foo() in the package environment and insert the results into NAMESPACE. Because evalNamespace() is run in the package environment, it can only generate exports, not imports.

Imports

The NAMESPACE also controls which functions from other packages are made available to your package. Only unique directives are saved to the NAMESPACE file, so you can repeat them as needed to maintain a close link between the functions where they are needed and the namespace file.

If you are using just a few functions from another package, the recommended option is to note the package name in the Imports: field of the DESCRIPTION file and call the function(s) explicitly using ::, e.g., pkg::fun(). Alternatively, though no longer recommended due to its poorer readability, use @importFrom, e.g., @importFrom pgk fun, and call the function(s) without ::.

If you are using many functions from another package, use @import package to import them all and make available without using ::.

If you want to add a new method to an S3 generic, import it with @importFrom pkg generic.

If you are using S4 you may also need:

  • @importClassesFrom package classa classb ... to import selected S4 classes.

  • @importMethodsFrom package methoda methodb ... to import selected S4 methods.

To import compiled code from another package, use @useDynLib

  • @useDynLib package imports all compiled functions.

  • @useDynLib package routinea routineb imports selected compiled functions.

  • Any @useDynLib specification containing a comma, e.g. @useDynLib mypackage, .registration = TRUE will be inserted as is into the the NAMESPACE, e.g. useDynLib(mypackage, .registration = TRUE)

roxygen2/inst/doc/rd.html0000644000176200001440000021176214115763565015072 0ustar liggesusers Rd (documentation) tags

Rd (documentation) tags

Basics

A roxygen block is a sequence of lines starting with #' (optionally preceded by whitespace). Blocks gain additional structure through the use of tags like @tag details. Tags must start at the beginning of a line, and the content of a tag extends to the start of the next tag (or the end of the block).

Text within roxygen blocks can be formatted using markdown or Rd commands; see vignette("rd-formatting") for details.

The description block

Each documentation block starts with some text which defines the title, the description, and the details. Here’s an example showing what the documentation for sum() might look like if it had been written with roxygen:

#' Sum of vector elements
#'
#' `sum` returns the sum of all the values present in its arguments.
#'
#' This is a generic function: methods can be defined for it directly
#' or via the [Summary()] group generic. For this to work properly,
#' the arguments `...` should be unnamed, and dispatch is on the
#' first argument.
sum <- function(..., na.rm = TRUE) {}

This introductory block is broken up as follows:

  • The first sentence is the title: that’s what you see when you look at help(package = mypackage) and is shown at the top of each help file. It should generally fit on one line, be written in sentence case, and not end in a full stop.

  • The second paragraph is the description: this comes first in the documentation and should briefly describe what the function does.

  • The third and subsequent paragraphs go into the details: this is a (often long) section that comes after the argument description and should provide any other important details of how the function operates. The details are optional.

You can also use explicit @title, @description, and @details tags. This is unnecessary unless you want to have a multi-paragraph description, bulleted list, or other more exotic structure.

#' Sum of vector elements
#' 
#' @description
#' `sum` returns the sum of all the values present in its arguments.
#'
#' @details
#' This is a generic function: methods can be defined for it directly
#' or via the [Summary()] group generic. For this to work properly,
#' the arguments `...` should be unnamed, and dispatch is on the
#' first argument.

Object specifics

Further details of roxygen2 depend on what you’re documenting. The following sections describe the most commonly used tags for functions, S3, S4, datasets, and packages.

Functions

Functions are the mostly commonly documented objects. Most functions use three tags:

  • @param name description describes the inputs to the function. The description should provide a succinct summary of the type of the parameter (e.g. a string, a numeric vector), and if not obvious from the name, what the parameter does. The description should start with a capital letter and end with a full stop. It can span multiple lines (or even paragraphs) if necessary. All parameters must be documented.

    You can document multiple arguments in one place by separating the names with commas (no spaces). For example, to document both x and y, you can say @param x,y Numeric vectors.

  • @examples provides executable R code showing how to use the function in practice. This is a very important part of the documentation because many people look at the examples before reading anything. Example code must work without errors as it is run automatically as part of R CMD check.

    However for the purpose of illustration, it’s often useful to include code that causes an error. \dontrun{} allows you to include code in the example that is never used. There are two other special commands. \dontshow{} is run, but not shown in the help page: this can be useful for informal tests. \donttest{} is run in examples, but not run automatically in R CMD check. This is useful if you have examples that take a long time to run. The options are summarised below.

Command example help R CMD check R CMD check –as-cran
\dontrun{} x
\dontshow{} x x x
\donttest{} x x x

Note that R CMD check --as-cran is run for incoming CRAN checks but not for regular CRAN checks.

For finer control you can use `@examplesIf

#' @examplesIf interactive()
#' browseURL("https://roxygen2.r-lib.org")

will generate

\examples{
\dontshow{if (interactive() (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf}
gh_organizations(since = 42)
\dontshow{\}) # examplesIf}
}

This way the code evaluating whether the example can be run is not shown to users reading the help, but it still prevents R CMD check failures.

Instead of including examples directly in the documentation, you can put them in separate files and use @example path/relative/to/package/root to insert them into the documentation.

  • @return description describes the output from the function. This is not always necessary, but is a good idea if you return different types of outputs depending on the input, or you’re returning an S3, S4 or RC object.

  • We could use these new tags to improve our documentation of sum() as follows:

    #' Sum of vector elements
    #'
    #' `sum()` returns the sum of all the values present in its arguments.
    #'
    #' This is a generic function: methods can be defined for it directly
    #' or via the [Summary] group generic. For this to work properly,
    #' the arguments `...` should be unnamed, and dispatch is on the
    #' first argument.
    #'
    #' @param ... Numeric, complex, or logical vectors.
    #' @param na.rm A logical scalar. Should missing values (including `NaN`)
    #'   be removed?
    #' @return If all inputs are integer and logical, then the output
    #'   will be an integer. If integer overflow 
    #'   (<http://en.wikipedia.org/wiki/Integer_overflow>) occurs, the output
    #'   will be NA with a warning. Otherwise it will be a length-one numeric or
    #'   complex vector.
    #'
    #'   Zero-length vectors have sum 0 by definition. See
    #'   <http://en.wikipedia.org/wiki/Empty_sum> for more details.
    #' @examples
    #' sum(1:10)
    #' sum(1:5, 6:10)
    #' sum(F, F, F, T, T)
    #'
    #' sum(.Machine$integer.max, 1L)
    #' sum(.Machine$integer.max, 1)
    #'
    #' \dontrun{
    #' sum("a")
    #' }
    sum <- function(..., na.rm = TRUE) {}

    Indent the second and subsequent lines of a tag so that when scanning the documentation so it’s easy to see where one tag ends and the next begins. Tags that always span multiple lines (like @example) should start on a new line and don’t need to be indented.

    S3

    • S3 generics are regular functions, so document them as such. If necessary, include a @section that provides additional details for method implementors

    • S3 classes have no formal definition, so document the constructor.

    • It is your choice whether or not to document S3 methods. Generally, it’s not necessary to document straightforward methods for common generics like print(). (You should, however, always @export S3 methods).

      If your method is more complicated, you should document it by setting @rdname. Typically you will document methods with their generic, so you’d document foofy.data.frame by setting @rdname. In base R, you can find documentation for more complex methods like ?predict.lm, ?predict.glm, and ?anova.glm.

      Generally, roxygen2 will automatically figure out the generic that the method belongs to, and you should only need to use @method if there is ambiguity. For example, is all.equal.data.frame() the equal.data.frame method for all(), or the data.frame method for all.equal()?. If this happens to you, disambiguate with (e.g.) @method all.equal data.frame.

    S4

    S4 generics are also functions, so document them as such.

    Document S4 classes by adding a roxygen block before setClass(). Use @slot to document the slots of the class. Here’s a simple example:

    #' An S4 class to represent a bank account
    #'
    #' @slot balance A length-one numeric vector
    Account <- setClass("Account",
      slots = list(balance = "numeric")
    )

    S4 methods are a little more complicated. Unlike S3 methods, all S4 methods must be documented. You can document them in three places:

    • In the class. Most appropriate if the corresponding generic uses single dispatch and you created the class.

    • In the generic. Most appropriate if the generic uses multiple dispatch and you control it.

    • In its own file. Most appropriate if the method is complex. or the either two options don’t apply.

    Use either @rdname or @describeIn to control where method documentation goes. See the next section for more details.

    R6

    Starting from version 7.0.0 roxygen treats documentation for R6 classes specially:

    • R6 methods can be documented in-line, i.e. the method’s documentation comments come right before the definition of the method.

    • Method documentation can use the @description, @details, @param, @return and @examples tags. These are used to create a subsection for the method, within a separate ‘Methods’ section. All roxygen comment lines of a method documentation must appear after a tag.

    • @param tags that appear before the class definition are automatically inherited by all methods, if needed.

    • R6 fields and active bindings can make use of the @field tag. Their documentation should also be in-line.

    • Roxygen2 checks that all public methods, public fields, active bindings and all method arguments are documented, and issues warnings otherwise.

    • To turn off the special handling of R6 classes and go back to the roxygen2 6.x.x behavior, use the r6 = FALSE option in DESCRIPTION, in the Roxygen entry: Roxygen: list(r6 = FALSE).

    Roxygen2 automatically generates additional sections for an R6 class:

    • A section with information about the superclass(es) of the class, with links. In HTML this includes a list of all inherited methods, with links.

    • An ‘Examples’ section that contains all class and method examples. This section is run by R CMD check, so method examples must work without errors.

    An example from the R6 tutorial:

    #' R6 Class Representing a Person
    #'
    #' @description
    #' A person has a name and a hair color.
    #'
    #' @details
    #' A person can also greet you.
    
    Person <- R6::R6Class("Person",
    public = list(
    
        #' @field name First or full name of the person.
        name = NULL,
    
        #' @field hair Hair color of the person.
        hair = NULL,
    
        #' @description
        #' Create a new person object.
        #' @param name Name.
        #' @param hair Hair color.
        #' @return A new `Person` object.
        initialize = function(name = NA, hair = NA) {
          self$name <- name
          self$hair <- hair
          self$greet()
        },
    
        #' @description
        #' Change hair color.
        #' @param val New hair color.
        #' @examples
        #' P <- Person("Ann", "black")
        #' P$hair
        #' P$set_hair("red")
        #' P$hair
        set_hair = function(val) {
          self$hair <- val
        },
    
        #' @description
        #' Say hi.
        greet = function() {
          cat(paste0("Hello, my name is ", self$name, ".\n"))
        }
      )
    )

    Datasets

    Datasets are usually stored as .rdata files in data/ and not as regular R objects in the package. This means you need to document them slightly differently: instead of documenting the data directly, you quote the dataset’s name.

    #' Prices of 50,000 round cut diamonds
    #'
    #' A dataset containing the prices and other attributes of almost 54,000
    #' diamonds.
    #'
    #' @format A data frame with 53940 rows and 10 variables
    #' \describe{
    #'   \item{price}{price in US dollars (\$326--\$18,823)}
    #'   \item{carat}{weight of the diamond (0.2--5.01)}
    #'   \item{cut}{quality of the cut (Fair, Good, Very Good, Premium, Ideal)}
    #'   \item{color}{diamond colour, from D (best) to J (worst)}
    #'   \item{clarity}{a measurement of how clear the diamond is (I1 (worst), SI2,
    #'     SI1, VS2, VS1, VVS2, VVS1, IF (best))}
    #'   \item{x}{length in mm (0--10.74)}
    #'   \item{y}{width in mm (0--58.9)}
    #'   \item{z}{depth in mm (0--31.8)}
    #'   \item{depth}{total depth percentage = z / mean(x, y) = 2 * z / (x + y) (43--79)}
    #'   \item{table}{width of top of diamond relative to widest point (43--95)}
    #' }
    #' @source <http://www.diamondse.info/>
    "diamonds"
    #> [1] "diamonds"

    Note the use of two additional tags that are particularly useful for documenting data:

    • @format, which gives an overview of the structure of the dataset. This should include a definition list that describes each variable. There’s currently no way to generate this with markdown, so this is one of the few places you’ll need to Rd markup directly.

    • @source where you got the data form, often a URL.

    Packages

    As well as documenting every object inside the package, you can also document the package itself by documenting the special sentinel "_PACKAGE". We recommend placing package documentation in {pkgname}-package.R, and have @keywords internal. Here’s an example:

    #' @details
    #' The only function you're likely to need from roxygen2 is [roxygenize()]. 
    #' Otherwise refer to the vignettes to see how to format the documentation.
    #' @keywords internal
    "_PACKAGE"

    Package documentation is a good place to put @section Package options: that documents options used by the package.

    Some notes:

    • Package documentation will automatically include information parsed from the DESCRIPTION, including title, description, list of authors, and useful URLs.

    • By default, aliases will be added so that both ?pkgname and package?pkgname will find the package help. If there’s an existing function called pkgname, use @aliases {pkgname}-package to override the default.

    • usethis::use_package_doc() will generate a basic template to get you started.

    • Use @references to point to published material about the package that users might find helpful.

    Sections

    You can add arbitrary sections with the @section tag. This is a useful way of breaking a long details section into multiple chunks with useful headings. Section titles should be in sentence case, must fit on one line, and must be followed by a colon.

    #' @section Warning:
    #' Do not operate heavy machinery within 8 hours of using this function.

    You can also create sections using the markdown syntax for headers. For example, the previously-defined section can be created with markdown headers like this:

    #' @details # Warning
    #' Do not operate heavy machinery within 8 hours of using this function.

    Note that ‘#’ may only appear after the @description and @details tags. Since @details can appear multiple times in a block, you can always precede a ‘#’ section with @details.

    To add a subsection, use level two or greater headings:

    #' @details # Warning
    #' You must not call this function unless ...
    #'
    #' ## Exceptions
    #' Apart from the following special cases...

    If you find yourself adding a lot of sections, you might consider using a vignette instead.

    Do repeat yourself

    There is a tension between the DRY (do not repeat yourself) principle of programming and the need for documentation to be self-contained. It’s frustrating to have to navigate through multiple help files in order to pull together all the pieces you need. Roxygen2 provides several ways to avoid repeating yourself in code documentation, while assembling information from multiple places in one documentation file:

    • Cross-link documentation files with @seealso and @family.

    • Inherit documentation from another topic with
      @inherit, @inheritParams, and @inheritSection.

    • Document multiple functions in the same topic with @describeIn or @rdname.

    • Run arbitrary R code with the markdown markup for inline code, see section ‘Dynamic R code’ in vignette("rd-formatting").

    • Run arbitrary R code with @eval.

    • Create reusable templates with @template and @templateVar.

    Cross-references

    There are two tags that make it easier for people to navigate around your documentation: @seealso and @family. @seealso allows you to point to other useful resources, either on the web <http://www.r-project.org> or to other documentation with [function_name()]. If you have a family of related functions, you can use @family {family} to cross-reference each function to every other function within the family. A function can be a member of multiple families.

    For sum(), this might look like:

    #' @family aggregations
    #' @seealso [prod()] for products, [cumsum()] for cumulative sums, and
    #'   [colSums()]/[rowSums()] marginal sums over high-dimensional arrays.

    By default @family {family}, will generate the see also text “Other {family}:”, so the @family name should be plural (i.e., “model building helpers” not “model building helper”). You can override the default title by providing a rd_family_title list in man/roxygen/meta.R:

    list(
      rd_family_title = list(aggregations = "Aggregation functions")
    )

    Inheriting documentation from other topics

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

    • @inherit source_function will inherit parameters, return, references, description, details, sections, and seealso from source_function().

    • @inherit source_function return details will inherit selected components from source_function()

    • @inheritParams source_function inherits just the parameter documentation from source_function().

    • @inheritSection source_function Section title will inherit the single @section called “Section title” from source_function().

    All of these work recursively so you can inherit documentation from a function that has inherited it from elsewhere.

    You can also inherit documentation from functions provided by another package by using pkg::source_function.

    Documenting multiple functions in the same file

    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

    @describeIn is designed for the most common cases:

    • documenting methods in a generic
    • documenting methods in a class
    • documenting functions with the same (or similar arguments)

    It generates a new section, named either “Methods (by class)”, “Methods (by generic)” or “Functions”. The section contains a bulleted list describing each function, labelled so that you know what function or method it’s talking about. Here’s an example, documenting an imaginary new generic:

    #' Foo bar generic
    #'
    #' @param x Object to foo.
    foobar <- function(x) UseMethod("x")
    
    #' @describeIn foobar Difference between the mean and the median
    foobar.numeric <- function(x) abs(mean(x) - median(x))
    
    #' @describeIn foobar First and last values pasted together in a string.
    foobar.character <- function(x) paste0(x[1], "-", x[length(x)])

    @rdname

    @rdname is a more general purpose tool. It overrides the default file name generated by roxygen and merges documentation for multiple objects into one file. This gives you complete freedom to combine documentation however you see fit. There are two ways to use @rdname. You can add documentation to an existing function:

    #' Basic arithmetic
    #'
    #' @param x,y numeric vectors.
    add <- function(x, y) x + y
    
    #' @rdname add
    times <- function(x, y) x * y

    Or, you can create a dummy documentation file by documenting NULL and setting an informative @name.

    #' Basic arithmetic
    #'
    #' @param x,y numeric vectors.
    #' @name arith
    NULL
    #> NULL
    
    #' @rdname arith
    add <- function(x, y) x + y
    
    #' @rdname arith
    times <- function(x, y) x * y

    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

    Evaluating arbitrary code

    Another technique is the @eval tag. It evaluates code and treatments the result as if it was a literal roxygen tags. This makes it possible to eliminate duplication by writing functions. The code will be evaluated in the package environment and should yield a character vector of roxygen comments (but without the leading #').

    For example, this code + roxygen block:

    my_params <- function() {
      c(
        "@param x An integer vector",
        "@param y A character vector"
      )
    }
    
    #' A title
    #' 
    #' @eval my_params()
    #' @export
    foo <- function(x, y) {
    }

    Is equivalent to:

    #' A title
    #' 
    #' @param x An integer vector
    #' @param y A character vector
    #' @export
    foo <- function(x, y) {
    }

    Note that @eval cannot be embedded into another roxygen tag. If you want to dynamically generate part of a roxygen tag, see section ‘Dynamic R code’ in vignette("rd-formatting").

    A related function is @evalRd. It works in the same way as @eval (i.e. it’s evaluated in the package environment) but rather than yielding roxygen comments that are processed as if they had been typed directly, it yields top-level Rd code that is inserted directly into the generated .Rd file. It is primarily useful if you want to generate Rd structure that is not currently supported by roxygen2.

    For example, this block:

    my_note <- function(x) {
      paste0("\\note{", paste0(x, "\n", collapse =""), "}")
    }
    
    #' @evalRd my_note(c(
    #'   "This is the first line",
    #'   "This is the second line"
    #' ))
    NULL
    #> NULL

    Would generate this Rd:

    \note{
    This is the first line
    This is the second line
    }

    Roxygen templates

    Roxygen templates are R files that contain only roxygen comments and that live in the man-roxygen directory. Use @template file-name (without extension) to insert the contents of a template into the current documentation.

    You can make templates more flexible by using template variables defined with @templateVar name value. Template files are run with brew, so you can retrieve values (or execute any other arbitrary R code) with <%= name %>.

    Note that templates are parsed a little differently to regular blocks, so you’ll need to explicitly set the title, description and details with @title, @description and @details.

    Including external .Rmd/.md files

    Starting from roxygen2 7.0.0, you can use @includeRmd path/to/file.Rmd to include an external .Rmd or .md document into a manual page (the path is relative from the source package root directory). You can include the same file in multiple documentation files, and for the first time, share content across documentation and vignettes.

    Sections

    @includeRmd supports headings in the external Rmd. The rules are as follows:

    • All text before the first level 1 heading (i.e. #), is added to the details section. If you prefer a different section, then write the name of the section after the path in the @includeRmd tag, in all lowercase. Example: @includeRmd path description. This currently does not work with user defined sections (created with @section).

    • Level 1 headings generate their own section (\section{}).

    • Other headings (level 2 and so on) create subsections (\subsection{}) within the section they appear in.

    All content in the Rmd file will go either in the details or in new top level sections. It is currently not possible to document function arguments, return values, etc. in external Rmd documents.

    Caching and figures

    @includeRmd tries to set up knitr to support caching in the Rmd file. It sets the cache path to the default knitr cache path of the included Rmd file (i.e. foo/bar/file_cache/ for foo/bar/file.Rmd), so if you do not change the cache path within the Rmd itself, then everything should work out of the box. You should add these cache paths to .gitignore and .Rbuildignore.

    @includeRmd also sets the knitr figure path of the (fig.path) to the default figure path of the included Rmd. Overriding this default is unlikely to work.

    Sharing text between vignettes and the manual

    @includeRmd helps avoiding repetition, as you can use the same .Rmd or .md document in the manual and also in the README.md file or in vignettes. One way to include an Rmd file in another one is to use child documents:

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

    If the Rmd file has links to other help topics, then some care is needed, as those links while not work in Rmd files. A workaround is to specify external HTML links for them. These external locations will not be used for @includeRmd, which always links them 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.

    Other tags

    Indexing

    Three other tags make it easier for the user to find documentation within R’s help system:

    • Aliases form the index that ? searches. Use @aliases space separated aliases to add additional aliases.

    • @concept add extra keywords that will be found with help.search()

    • Use @keywords keyword1 keyword2 ... to add standardised keywords. Keywords are optional, but if present, must be taken from the predefined list found file.path(R.home("doc"), "KEYWORDS").

    Apart from @keywords internal, these tags are not very useful because most people find documentation using Google. @keywords internal is useful because it removes the function from the documentation index; it’s useful for functions aimed primarily at other developers, not typical users of the package.

    Back references

    The original source location is added as a comment to the second line of each generated .Rd file in the following form:

    % Please edit documentation in ...

    roxygen2 tries to capture all locations from which the documentation is assembled. For code that generates R code with Roxygen comments (e.g., the Rcpp package), the @backref tag is provided. This allows specifying the “true” source of the documentation, and will substitute the default list of source files. Use one tag per source file:

    #' @backref src/file.cpp
    #' @backref src/file.h
    roxygen2/inst/doc/namespace.Rmd0000644000176200001440000001140713631761325016163 0ustar liggesusers--- title: "NAMESPACE tags" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{NAMESPACE tags} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ``` The package `NAMESPACE` is one of the most confusing parts of building a package. Roxygen2 aims to make it as easy as possible to build a package that is a well-behaved member of the R ecosystem. This is a little frustrating at first, but soon becomes second-nature. ## Exports For a function to be usable outside of your package, you must __export__ it. By default roxygen2 doesn't export anything from your package. If you want an object to be publicly available, you must explicitly tag it with `@export`. Use the following guidelines to decide what to export: * Functions: export functions that you want to make available. Exported functions must be documented, and you must be cautious when changing their interface. * Datasets: all datasets are publicly available. They exist outside of the package namespace and should not be exported. * S3 classes: if you want others to be able to create instances of the class `@export` the constructor function. * S3 generics: the generic is a function so `@export` if you want it to be usable outside the package * S3 methods: every S3 method _must_ be exported, even if the generic is not. Otherwise the S3 method table will not be generated correctly and internal generics will not find the correct method. If you are providing a method for a generic defined in another package, you must also import that generic. * S4 classes: if you want others to be able to extend your class, `@export` it. If you want others to create instances of your class, but not extend it, `@export` the constructor function, but not the class. ```R # Can extend and create #' @export setClass("A") # Can extend, but constructor not exported #' @export B <- setClass("B") # Can create, but not extend #' @export C C <- setClass("C") # Can create and extend #' @export D #' @exportClass D D <- setClass("D") ``` * S4 generics: `@export` if you want the generic to be publicly usable. * S4 methods: you only need to `@export` methods for generics that you did not define. * RC classes: the same principles apply as for S4 classes. `@export` will only export the class. ### Specialised exports Generally, roxygen2 can generate the correct namespace directive when `@export`ing a specific object. However, you may want to override the defaults and exercise greater control. In this case you can use the more specialised tags described below: * `@export foo` generates `export(foo)` * `@exportClass foo` generates `exportClasses(foo)` * `@exportMethod foo` generates `exportMethods(foo)` * `@exportPattern foo` generates `exportPattern(foo)` For even more specialised cases you can use `@rawNamespace code` which inserts `code` literally into the `NAMESPACE`. If you need to automate this, `@evalNamespace foo()` will evaluate the `foo()` in the package environment and insert the results into `NAMESPACE`. Because `evalNamespace()` is run in the package environment, it can only generate exports, not imports. ## Imports The `NAMESPACE` also controls which functions from other packages are made available to your package. Only unique directives are saved to the `NAMESPACE` file, so you can repeat them as needed to maintain a close link between the functions where they are needed and the namespace file. If you are using just a few functions from another package, the recommended option is to note the package name in the `Imports:` field of the `DESCRIPTION` file and call the function(s) explicitly using `::`, e.g., `pkg::fun()`. Alternatively, though no longer recommended due to its poorer readability, use `@importFrom`, e.g., `@importFrom pgk fun`, and call the function(s) without `::`. If you are using many functions from another package, use `@import package` to import them all and make available without using `::`. If you want to add a new method to an S3 generic, import it with `@importFrom pkg generic`. If you are using S4 you may also need: * `@importClassesFrom package classa classb ...` to import selected S4 classes. * `@importMethodsFrom package methoda methodb ...` to import selected S4 methods. To import compiled code from another package, use `@useDynLib` * `@useDynLib package` imports all compiled functions. * `@useDynLib package routinea routineb` imports selected compiled functions. * Any `@useDynLib` specification containing a comma, e.g. `@useDynLib mypackage, .registration = TRUE` will be inserted as is into the the NAMESPACE, e.g. `useDynLib(mypackage, .registration = TRUE)` roxygen2/inst/doc/namespace.R0000644000176200001440000000021114115763564015636 0ustar liggesusers## ---- include = FALSE--------------------------------------------------------- knitr::opts_chunk$set(comment = "#>", collapse = TRUE) roxygen2/inst/doc/roxygen2.html0000644000176200001440000005426314115763565016243 0ustar liggesusers Introduction to roxygen2

    Introduction to roxygen2

    Documentation is one of the most important aspects of good code. Without it, users won’t know how to use your package, and are unlikely to do so. Documentation is also useful for you in the future (so you remember what the heck you were thinking!), and for other developers working on your package. The goal of roxygen2 is to make documenting your code as easy as possible. R provides a standard way of documenting packages: you write .Rd files in the man/ directory. These files use a custom syntax, loosely based on latex. Roxygen2 provides a number of advantages over writing .Rd files by hand:

    • Code and documentation are adjacent so when you modify your code, it’s easy to remember that you need to update the documentation.

    • Roxygen2 dynamically inspects the objects that it’s documenting, so it can automatically add data that you’d otherwise have to write by hand.

    • It abstracts over the differences in documenting S3 and S4 methods, generics and classes so you need to learn fewer details.

    As well as generating .Rd files, roxygen will also create a NAMESPACE for you, and will manage the Collate field in DESCRIPTION.

    This vignette provides a high-level description of roxygen2 and how the three main components work. The other vignettes provide more detail on the most important individual components:

    • Generating .Rd files and text formatting describe how to generate function documentation via .Rd files

    • Managing your NAMESPACE describes how to generate a NAMESPACE file, how namespacing works in R, and how you can use Roxygen2 to be specific about what your package needs and supplies.

    • See [update_collate()] for the details of @include, which for complicated reasons is not implemented as a roclet.

    Running roxygen

    There are three main ways to run roxygen:

    • roxygen2::roxygenise().

    • devtools::document().

    • Ctrl + Shift + D, if you’re using RStudio.

    You can mix handwritten Rd and roxygen2; roxygen2 will never overwrite a file it didn’t create.

    Basic process

    There are three steps in the transformation from roxygen comments in your source file to human readable documentation:

    1. You add roxygen comments to your source file.
    2. roxygen2::roxygenise() converts roxygen comments to .Rd files.
    3. R converts .Rd files to human readable documentation.

    The process starts when you add specially formatted roxygen comments to your source file. Roxygen comments start with #' so you can continue to use regular comments for other purposes.

    #' Add together two numbers
    #'
    #' @param x A number
    #' @param y A number
    #' @return The sum of \code{x} and \code{y}
    #' @examples
    #' add(1, 1)
    #' add(10, 1)
    add <- function(x, y) {
      x + y
    }

    For the example, above, this will generate man/add.Rd that looks like:

    % Generated by roxygen2 (3.2.0): do not edit by hand
    \name{add}
    \alias{add}
    \title{Add together two numbers}
    \usage{
    add(x, y)
    }
    \arguments{
      \item{x}{A number}
    
      \item{y}{A number}
    }
    \value{
    The sum of \code{x} and \code{y}
    }
    \description{
    Add together two numbers
    }
    \examples{
    add(1, 1)
    add(10, 1)
    }

    Rd files are a special file format loosely based on LaTeX. You can read more about the Rd format in the R extensions manual. With roxygen2, there are few reasons to know about Rd files, so here I’ll avoid discussing them as much as possible, focussing instead on what you need to know about roxygen2.

    When you use ?x, help("x") or example("x") R looks for an Rd file containing \alias{x}. It then parses the file, converts it into html and displays it. These functions look for an Rd file in installed packages. This isn’t very useful for package development, because you want to use the .Rd files in the source package. For this reason, we recommend that you use roxygen2 in conjunction with devtools: devtools::load_all() automatically adds shims so that ? and friends will look in the development package. Note, however, that this preview does not work with intra-package links. To preview those, you’ll need to install the package. If you use RStudio, the easiest way to do this is to click the “Build & Reload button”.

    Rcpp

    You can also use roxygen2 with Rcpp. Simply include roxygen2 comments in your C++ code (using // instead of #), and Rcpp will automatically carry the comments along into RcppExports.R where roxygen2 will find them.

    For example, dplyr has between.cpp which starts:

    //' Do values in a numeric vector fall in specified range?
    //'
    //' This is a shortcut for `x >= left & x <= right`, implemented
    //' efficiently in C++ for local values, and translated to the
    //' appropriate SQL for remote tables.
    //'
    //' @param x A numeric vector of values
    //' @param left,right Boundary values
    //' @export
    //' @examples
    //' between(1:12, 7, 9)
    //'
    //' x <- rnorm(1e2)
    //' x[between(x, -1, 1)]
    // [[Rcpp::export(rng = false)]]
    Rcpp::LogicalVector between(Rcpp::NumericVector x, double left, double right) {
    }

    This is automatically translated to the following R code in RcppExports.R:

    #' Do values in a numeric vector fall in specified range?
    #'
    #' This is a shortcut for `x >= left & x <= right`, implemented
    #' efficiently in C++ for local values, and translated to the
    #' appropriate SQL for remote tables.
    #'
    #' @param x A numeric vector of values
    #' @param left,right Boundary values
    #' @export
    #' @examples
    #' between(1:12, 7, 9)
    #'
    #' x <- rnorm(1e2)
    #' x[between(x, -1, 1)]
    between <- function(x, left, right) {
    }
    roxygen2/inst/doc/roxygen2.R0000644000176200001440000000172114115763565015467 0ustar liggesusers## ---- include = FALSE--------------------------------------------------------- knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ## ----------------------------------------------------------------------------- #' Add together two numbers #' #' @param x A number #' @param y A number #' @return The sum of \code{x} and \code{y} #' @examples #' add(1, 1) #' add(10, 1) add <- function(x, y) { x + y } ## ---- eval = FALSE------------------------------------------------------------ # #' Do values in a numeric vector fall in specified range? # #' # #' This is a shortcut for `x >= left & x <= right`, implemented # #' efficiently in C++ for local values, and translated to the # #' appropriate SQL for remote tables. # #' # #' @param x A numeric vector of values # #' @param left,right Boundary values # #' @export # #' @examples # #' between(1:12, 7, 9) # #' # #' x <- rnorm(1e2) # #' x[between(x, -1, 1)] # between <- function(x, left, right) { # } roxygen2/inst/doc/rd-formatting.html0000644000176200001440000015344014115763564017237 0ustar liggesusers Rd formatting

    Rd formatting

    Introduction

    Starting from version 6.0.0, roxygen supports markdown markup within most roxygen tags. Roxygen uses the commonmark package, which is based on the CommonMark Reference Implementation to parse these tags. See https://commonmark.org/help/ for more about the parser and the markdown language it supports. You can also still use the .Rd syntax, some of which we will present below in the Rd syntax section.

    Turning on markdown support

    There are two ways to turn on markdown support for a package: globally, at the package level, and locally at the block level.

    To turn on markdown for the whole package, insert this entry into the DESCRIPTION file of the package:

    Roxygen: list(markdown = TRUE)

    The position of the entry in the file does not matter. After this, all Roxygen documentation will be parsed as markdown.

    Alternatively, you can use the @md tag to turn on markdown support for a single documentation chunk. This is a good option to write any new documentation for existing packages in markdown.

    There is also a new @noMd tag. Use this if you turned on markdown parsing globally, but need to avoid it for a single chunk. This tag is handy if the markdown parser interferes with more complex Rd syntax.

    Here is an example roxygen chunk that uses markdown.

    #' Use roxygen to document a package
    #'
    #' This function is a wrapper for the [roxygen2::roxygenize()] function from
    #' the roxygen2 package. See the documentation and vignettes of
    #' that package to learn how to use roxygen.
    #'
    #' @param pkg package description, can be path or package name.  See
    #'   [as.package()] for more information
    #' @param clean,reload Deprecated.
    #' @inheritParams roxygen2::roxygenise
    #' @seealso [roxygen2::roxygenize()], `browseVignettes("roxygen2")`
    #' @export
    #' @md

    Syntax

    Sections

    The usual markdown heading markup creates sections and subsections. Top level headings, i.e. ‘#’ create sections, via the \section{} Rd tag. ‘#’ may only appear after the @description and @details tags. Since @details can appear multiple times in a block, you can always precede a ‘#’ section with @details, if you prefer to place it towards the end of the block, after @return for example:

    #' @details
    #' Trim the leading and trailing whitespace from a character vector.
    #'
    #' @param x Character vector.
    #' @return Character vector, with the whitespace trimmed.
    #'
    #' @details # This will be a new section
    #' ...

    Top level sections are always placed at a fixed position in the manual page, after the parameters and the details, but before \note{}, \seealso{} and the \examples{}. Their order will be the same as in the roxygen block.

    Subsections

    Headings at level two and above may appear inside any roxygen tag that formats lines of text. E.g. @description, @details, @return, etc. They create subsections, via the \subsection{} Rd tag. They are allowed within top level sections as well, i.e. after ‘#’. Subsections can be nested. Example:

    #' @details
    #' ## Subsection within details
    #' ### Sub-subsection
    #' ... text ...

    Emphasis

    Emphasis and strong (bold) text are supported. For emphasis, put the text between asterisks or underline characters. For strong text, use two asterisks at both sides.

    #' @references
    #' Robert E Tarjan and Mihalis Yannakakis. (1984). Simple
    #' linear-time algorithms to test chordality of graphs, test acyclicity
    #' of hypergraphs, and selectively reduce acyclic hypergraphs.
    #' *SIAM Journal of Computation* **13**, 566-579.
    #' See `::is_falsy` for the definition of what is _falsy_
    #' and what is _truthy_.

    Code

    Inline code is supported via backticks.

    #' @param ns Optionally, a named vector giving prefix-url pairs, as
    #'   produced by `xml_ns`. If provided, all names will be explicitly
    #'   qualified with the ns prefix, i.e. if the element `bar` is defined ...

    You can also use this syntax to run custom R code and insert its output into the manual page. See section ‘Dynamic R code’ below.

    For blocks of code, put your code between triple backticks:

    #' ```
    #' pkg <- make_packages(
    #'   foo1 = { f <- function() print("hello!") ; d <- 1:10 },
    #'   foo2 = { f <- function() print("hello again!") ; d <- 11:20 }
    #' )
    #' foo1::f()
    #' foo2::f()
    #' foo1::d
    #' foo2::d
    #' dispose_packages(pkg)
    #' ```

    Note that this is not needed in @examples, since its contents are formatted as R code, anyway.

    You can use similar syntax to include a block of R code and/or its output in the manual page. See section ‘Dynamic R code’ below.

    Lists

    Regular Markdown lists are recognized and converted to \enumerate{} or \itemize{} lists:

    #' There are two ways to use this function:
    #' 1. If its first argument is not named, then it returns a function
    #'    that can be used to color strings.
    #' 1. If its first argument is named, then it also creates a
    #'    style with the given name. This style can be used in
    #'    `style`. One can still use the return value
    #'    of the function, to create a style function.
    #' The style (the `...` argument) can be anything of the
    #' following:
    #' * An R color name, see `colors()`.
    #' * A 6- or 8-digit hexa color string, e.g. `#ff0000` means
    #'   red. Transparency (alpha channel) values are ignored.
    #' * A one-column matrix with three rows for the red, green
    #'   and blue channels, as returned by [grDevices::col2rgb()]

    Nested lists are also supported.

    Note that you do not have to leave an empty line before the list. This is different from some markdown parsers.

    Tables

    Use GFM table formatting:

    | foo | bar |
    | --- | --- |
    | baz | bim |

    By default, columns are left-aligned. Use colons to generate right and center aligned columns:

    | left | center | right |
    | :--- | :----: | ----: |
    | 1    | 2      | 3     |

    Images

    Markdown syntax for inline images works. The image files must be in the man/figures directory:

    #' Here is an example plot:
    #' ![](example-plot.jpg "Example Plot Title")

    Dynamic R code

    Similarly to the knitr package, you can use the markdown inline code markup or markdown code blocks to evaluate R code and insert its output into the manual page.

    Inline code

    To do this, prefix the code with r, i.e. the lowercase letter ‘r’ and a space character. Roxygen will interpret the rest of the text within backticks as R code and evaluate it, and replace the backtick expression with its value. After all such substitutions, the text of the whole tag is interpreted as markdown, as usual.

    For example, the following will insert the date and the R version of the roxygen run.

    #' Roxygen created this manual page on `r Sys.Date()` using R version
    #' `r getRversion()`.

    The value of the R expression is converted to a character string, with paste(collapse = "\n"). So you don’t need explicitly convert to a character value, numeric values or any R object with an as.character() S3 method is fine. Also, you can insert multiple lines by returning a character vector. If you want to run R code without inserting any output, return an empty string or NULL.

    The value of the expression is inserted into the text of the tag without interpreting it, before the markdown to .Rd conversion, so you can create markdown markup dynamically:

    #' The `iris` data set has `r ncol(iris)` columns:
    #' `r paste0("``", colnames(iris), "``", collapse = ", ")`.

    Note that you need to escape backtick characters, if they appear in the R expression, by doubling them, like above. The result after the dynamic R code evaluation will be:

    The `iris` data set has 5 columns:
    `Sepal.Length`, `Sepal.Width`, `Petal.Length`, `Petal.Width`, `Species`.

    And the final result in the .Rd file will look as:

    The \code{iris} data set has 5 columns:
    \code{Sepal.Length}, \code{Sepal.Width}, \code{Petal.Length}, \code{Petal.Width}, \code{Species}.

    The R code is evaluated in a new environment that is the child of the package environment of the package you are documenting. This means that you can call (internal or exported) functions of the package. packageName() will also report the name of the package:

    #' To insert the name of the current package: `r packageName()`.

    A new evaluation environment is created for each roxygen block. So the output of this code:

    #' @title ... `r myvar <- "foo"; NULL` `r myvar`
    #'
    #' @description ... `r myvar`

    will be:

    #' @title ... foo
    #'
    #' @description ... foo

    Currently the whole code expression must be on the same line, multi-line expressions are not supported.

    Code blocks

    Markdown code blocks can be dynamic as well, if you use ```{r} to start them, just like in knitr documents.

    #' ```{r}
    #' # This block of code will be evaluated
    #' summary(iris)
    #' ```

    Within a roxygen block, code blocks and inline code use the same evaluation environment, so variables created in one of them can be used in others.

    Code blocks support knitr chunk options, e.g. to keep the output of several expressions together, you can specify results= "hold":

    #' ```{r results = "hold"}
    #' names(mtcars)
    #' nrow(mtcars)
    #' ```

    Plots will create .png files in the man/figures directory. The file names are created from the chunk names:

    #' ```{r iris-pairs-plot}
    #' pairs(iris[1:4], main = "Anderson's Iris Data -- 3 species",
    #'   pch = 21, bg = c("red", "green3", "blue")[unclass(iris$Species)])
    #' ```

    Note that the generated .png files will be added to the package, and they can considerably increase the size of the package.

    Note that code block support is currently experimental, and somewhat limited. Some of the known limitations:

    • Because the code blocks are evaluated individually, they cannot refer to each other.
    • Some knitr chunk options are reset at the start of every code block, so if you want to change these, you’ll have to specify them for every chunk. These are currently error, fig.path, fig.process.
    • Some knitr options might not create meaningful output.
    • The markdown code runs every time you call roxygenize() (or devtools::document()) to generated the Rd files. This potentially makes roxygenize() (much) slower. You can turn on knitr caching as usual, but make sure to omit the cache from the package.

    Roxygen and Rd tags not parsed as markdown

    Some of the roxygen tags are not parsed as markdown. Most of these are unlikely to contain text that needs markup, so this is not an important restriction. Tags without markdown support: @aliases, @backref, @docType, @encoding, @evalRd, @example, @examples, @family, @inheritParams, @keywords, @method @name, @md, @noMd, @noRd, @rdname, @rawRd, @usage.

    When mixing Rd and markdown notation, most Rd tags may contain markdown markup, the ones that can not are: \acronym, \code, \command, \CRANpkg, \deqn, \doi, \dontrun, \dontshow, \donttest, \email, \env, \eqn, \figure, \file, \if, \ifelse, \kbd, \link, \linkS4class, \method, \newcommand, \option, \out, \packageAuthor, \packageDescription, \packageDESCRIPTION, \packageIndices, \packageMaintainer, \packageTitle, \pkg, \PR, \preformatted, \renewcommand, \S3method, \S4method, \samp, \special, \testonly, \url, \var, \verb.

    Possible problems

    Mixing markdown and Rd markup

    Note that turning on markdown does not turn off the standard Rd syntax. We suggest that you use the regular Rd tags in a markdown roxygen chunk only if necessary. The two parsers do occasionally interact, and the markdown parser can pick up and reformat Rd syntax, causing an error, or corrupted manuals.

    Leading whitespace

    Leading whitespace is interpreted by the commonmark parser, whereas it is ignored by the Rd parser (except in \preformatted{}). Make sure that you only include leading whitespace intentionally, for example for nested lists.

    Spurious lists

    The Commonmark parser does not require an empty line before lists, and this might lead to unintended lists if a line starts with a number followed by a dot, or with an asterisk followed by whitespace:

    #' You can see more about this topic in the book cited below, on page
    #' 42. Clearly, the numbered list that starts here is not intentional.

    Rd syntax

    Within roxygen tags, you can use .Rd syntax to format text. Below we show you examples of the most important .Rd markup commands. The full details are described in R extensions. Before roxygen version 6.0.0 this was the only supported syntax. Now all of the formatting described below can be achived more easily with markdown syntax, with the important exception of mathematical expressions.

    Note that \ and % are special characters. To insert literals, escape with a backslash: \\, \%.

    Character formatting

    • \emph{italics}

    • \strong{bold}

    • \code{r_function_call(with = "arguments")}, \code{NULL}, \code{TRUE}

    • \pkg{package_name}

    Lists

    • Ordered (numbered) lists:

      #' \enumerate{
      #'   \item First item
      #'   \item Second item
      #' }
    • Unordered (bulleted) lists

      #' \itemize{
      #'   \item First item
      #'   \item Second item
      #' }
    • Definition (named) lists

      #' \describe{
      #'   \item{One}{First item}
      #'   \item{Two}{Second item}
      #' }

    Mathematics

    Standard LaTeX (with no extensions):

    • \eqn{a + b}: inline equation

    • \deqn{a + b}: display (block) equation

    Tables

    Tables are created with \tabular{}. It has two arguments:

    1. Column alignment, specified by letter for each column (l = left, r = right, c = centre.)

    2. Table contents, with columns separated by \tab and rows by \cr.

    The following function turns an R data frame into the correct format, adding a row consisting of the (bolded) column names and prepending each row with #' for pasting directly into the documentation.

    tabular <- function(df, ...) {
      stopifnot(is.data.frame(df))
    
      align <- function(x) if (is.numeric(x)) "r" else "l"
      col_align <- purrr::map_chr(df, align)
    
      cols <- lapply(df, format, ...)
      contents <- do.call("paste",
        c(cols, list(sep = " \\tab ", collapse = "\\cr\n#'   ")))
    
      paste("#' \\tabular{", paste(col_align, collapse = ""), "}{\n#'   ",
        paste0("\\strong{", names(df), "}", sep = "", collapse = " \\tab "), " \\cr\n#'   ",
        contents, "\n#' }\n", sep = "")
    }
    
    cat(tabular(mtcars[1:5, 1:5]))
    #> #' \tabular{rrrrr}{
    #> #'   \strong{mpg} \tab \strong{cyl} \tab \strong{disp} \tab \strong{hp} \tab \strong{drat} \cr
    #> #'   21.0 \tab 6 \tab 160 \tab 110 \tab 3.90\cr
    #> #'   21.0 \tab 6 \tab 160 \tab 110 \tab 3.90\cr
    #> #'   22.8 \tab 4 \tab 108 \tab  93 \tab 3.85\cr
    #> #'   21.4 \tab 6 \tab 258 \tab 110 \tab 3.08\cr
    #> #'   18.7 \tab 8 \tab 360 \tab 175 \tab 3.15
    #> #' }
    roxygen2/inst/doc/extending.R0000644000176200001440000001141714115763564015701 0ustar liggesusers## ---- include = FALSE--------------------------------------------------------- knitr::opts_chunk$set(comment = "#>", collapse = TRUE) ## ----setup-------------------------------------------------------------------- library(roxygen2) ## ----------------------------------------------------------------------------- roxy_tag("name", "Hadley") str(roxy_tag("name", "Hadley")) ## ----------------------------------------------------------------------------- text <- " #' This is a title #' #' This is the description. #' #' @param x,y A number #' @export f <- function(x, y) x + y " # parse_text() returns a list of blocks, so I extract the first block <- parse_text(text)[[1]] block ## ----------------------------------------------------------------------------- #' @tip The mean of a logical vector is the proportion of `TRUE` values. #' @tip You can compute means of dates and date-times! ## ----------------------------------------------------------------------------- roxy_tag_parse.roxy_tag_tip <- function(x) { tag_markdown(x) } ## ---- include = FALSE--------------------------------------------------------- # Needed for vignette registerS3method("roxy_tag_parse", "roxy_tag_tip", roxy_tag_parse.roxy_tag_tip) ## ----------------------------------------------------------------------------- text <- " #' Title #' #' @tip The mean of a logical vector is the proportion of `TRUE` values. #' @tip You can compute means of dates and date-times! #' @md f <- function(x, y) { # ... } " block <- parse_text(text)[[1]] block str(block$tags[[2]]) ## ----------------------------------------------------------------------------- roxy_tag_rd.roxy_tag_tip <- function(x, base_path, env) { rd_section("tip", x$val) } ## ---- include = FALSE--------------------------------------------------------- # Needed for vignette registerS3method("roxy_tag_rd", "roxy_tag_tip", roxy_tag_rd.roxy_tag_tip) ## ----------------------------------------------------------------------------- format.rd_section_tip <- function(x, ...) { paste0( "\\section{Tips and tricks}{\n", "\\itemize{\n", paste0(" \\item ", x$value, "\n", collapse = ""), "}\n", "}\n" ) } ## ---- include = FALSE--------------------------------------------------------- # Needed for vignette registerS3method("format", "rd_section_tip", format.rd_section_tip) ## ----------------------------------------------------------------------------- topic <- roc_proc_text(rd_roclet(), text)[[1]] topic$get_section("tip") ## ----------------------------------------------------------------------------- roxy_tag_parse.roxy_tag_memo <- function(x) { if (!grepl("^\\[.*\\].*$", x$raw)) { roxy_tag_warning(x, "Invalid memo format") return() } parsed <- stringi::stri_match(str = x$raw, regex = "\\[(.*)\\](.*)")[1, ] x$val <- list( header = parsed[[2]], message = parsed[[3]] ) x } ## ---- include = FALSE--------------------------------------------------------- # Needed for vignette registerS3method("roxy_tag_parse", "roxy_tag_memo", roxy_tag_parse.roxy_tag_memo) ## ----------------------------------------------------------------------------- text <- " #' @memo [TBI] Remember to implement this! #' @memo [API] Check best API f <- function(x, y) { # ... } " block <- parse_text(text)[[1]] block str(block$tags[[1]]) ## ----------------------------------------------------------------------------- memo_roclet <- function() { roclet("memo") } ## ----------------------------------------------------------------------------- roclet_process.roclet_memo <- function(x, blocks, env, base_path) { results <- list() for (block in blocks) { tags <- block_get_tags(block, "memo") for (tag in tags) { msg <- paste0("[", tag$file, ":", tag$line, "] ", tag$val$message) results[[tag$val$header]] <- c(results[[tag$val$header]], msg) } } results } ## ----------------------------------------------------------------------------- roclet_output.roclet_memo <- function(x, results, base_path, ...) { for (header in names(results)) { messages <- results[[header]] cat(paste0(header, ": ", "\n")) cat(paste0(" * ", messages, "\n", collapse = "")) } invisible(NULL) } ## ---- include = FALSE--------------------------------------------------------- # Needed for vignette registerS3method("roclet_process", "roclet_memo", roclet_process.roclet_memo) registerS3method("roclet_output", "roclet_memo", roclet_output.roclet_memo) ## ----------------------------------------------------------------------------- results <- roc_proc_text(memo_roclet(), " #' @memo [TBI] Remember to implement this! #' @memo [API] Check best API f <- function(x, y) { # ... } #' @memo [API] Consider passing z option g <- function(x, y) { # ... } ") roclet_output(memo_roclet(), results)