├── .Rbuildignore ├── .gitattributes ├── .gitignore ├── .travis.yml ├── DESCRIPTION ├── NAMESPACE ├── NEWS.md ├── R ├── RcppExports.R ├── collate.R ├── enc.R ├── field.R ├── markdown-escaping.R ├── markdown.R ├── namespace.R ├── object-defaults.R ├── object-format.R ├── object-from-call.R ├── object-name.R ├── object-package.R ├── object-rc.R ├── object-s3.R ├── object-usage.R ├── object.R ├── parse.R ├── rd-describe-in.R ├── rd-family.R ├── rd-inherit.R ├── rd-params.R ├── rd-template.R ├── rd.R ├── roclet.R ├── roxygen.R ├── roxygenize.R ├── safety.R ├── select-args.R ├── source.R ├── tag.R ├── topic.R ├── topics.R ├── topo-sort.R ├── util-locale.R ├── utils-rd.R ├── utils.R └── vignette.R ├── README.md ├── appveyor.yml ├── codecov.yml ├── cran-comments.md ├── man-roxygen └── template.R ├── man ├── double_escape_md.Rd ├── is_s3_generic.Rd ├── load_options.Rd ├── markdown-internals.Rd ├── markdown-test.Rd ├── namespace_roclet.Rd ├── object.Rd ├── object_format.Rd ├── rd_roclet.Rd ├── roc_proc_text.Rd ├── roclet.Rd ├── roclet_find.Rd ├── roxy_tag.Rd ├── roxygen2-package.Rd ├── roxygenize.Rd ├── source_package.Rd ├── update_collate.Rd └── vignette_roclet.Rd ├── revdep ├── .gitignore ├── README.md ├── check.R ├── checks.rds ├── problems.md └── timing.md ├── roxygen.Rproj ├── src ├── .gitignore ├── RcppExports.cpp ├── isComplete.cpp ├── leadingSpaces.cpp ├── parser2.cpp └── wrapString.cpp ├── tests ├── testthat.R └── testthat │ ├── Rd-example-1.R │ ├── Rd-example-2.R │ ├── Rd-example-3.R │ ├── Rd-example-4.R │ ├── Rd-example-5.R │ ├── collate │ ├── belt.R │ ├── jacket.R │ ├── pants.R │ ├── shirt.R │ ├── shoes.R │ ├── socks.R │ ├── tie.R │ ├── undershorts.R │ └── watch.R │ ├── description-example.txt │ ├── description-example_2.txt │ ├── empty │ ├── DESCRIPTION │ └── R │ │ └── empty-package.R │ ├── helper-env.R │ ├── helper-pkg.R │ ├── helper-test.R │ ├── made-by-roxygen │ ├── empty.Rd │ ├── with-header.Rd │ └── without-header.Rd │ ├── man-roxygen │ ├── UCase.R │ ├── lcase.r │ ├── reg.ex.R │ └── values.R │ ├── roxygen-block-1.R │ ├── roxygen-block-2.R │ ├── roxygen-example-1.R │ ├── test-Rbuildignore.R │ ├── test-Rd-inherit.R │ ├── test-collate.R │ ├── test-namespace.R │ ├── test-nice-name.R │ ├── test-nonASCII.R │ ├── test-object-format.R │ ├── test-object-rc.R │ ├── test-object-s3.R │ ├── test-object-s4.R │ ├── test-object.R │ ├── test-parse-block.R │ ├── test-parse.R │ ├── test-rd-alias.R │ ├── test-rd-backref.R │ ├── test-rd-data.R │ ├── test-rd-describein.R │ ├── test-rd-doctype.R │ ├── test-rd-examples.R │ ├── test-rd-family.R │ ├── test-rd-field.R │ ├── test-rd-introduction.R │ ├── test-rd-keyword.R │ ├── test-rd-markdown-escaping.R │ ├── test-rd-markdown-links.R │ ├── test-rd-markdown-on-off.R │ ├── test-rd-markdown.R │ ├── test-rd-name.R │ ├── test-rd-package.R │ ├── test-rd-param.R │ ├── test-rd-raw.R │ ├── test-rd-section.R │ ├── test-rd-slot.R │ ├── test-rd-template.R │ ├── test-rd-usage.R │ ├── test-rd.R │ ├── test-rdComplete.R │ ├── test-reexport.R │ ├── test-select_args.R │ ├── test-topic.R │ ├── test-utils.R │ ├── testCollateNoIncludes │ ├── DESCRIPTION │ ├── NAMESPACE │ └── R │ │ ├── a.r │ │ └── b.r │ ├── testCollateOverwrite │ ├── DESCRIPTION │ └── R │ │ ├── a.r │ │ └── b.r │ ├── testEagerData │ ├── DESCRIPTION │ ├── R │ │ └── a.r │ └── data │ │ └── a.rda │ ├── testLazyData │ ├── DESCRIPTION │ ├── NAMESPACE │ ├── R │ │ └── a.r │ └── data │ │ └── a.rda │ ├── testNonASCII │ ├── DESCRIPTION │ └── R │ │ └── a.r │ └── testRbuildignore │ ├── DESCRIPTION │ └── R │ ├── a.R │ └── ignore_me.R └── vignettes ├── collate.R ├── collate.Rmd ├── collate.html ├── collate.md ├── formatting.R ├── formatting.Rmd ├── formatting.html ├── formatting.md ├── markdown.R ├── markdown.Rmd ├── markdown.html ├── markdown.md ├── namespace.R ├── namespace.Rmd ├── namespace.html ├── namespace.md ├── rd.R ├── rd.Rmd ├── rd.html ├── rd.md ├── rdkeywords.R ├── rdkeywords.Rmd ├── rdkeywords.html ├── rdkeywords.md ├── releases └── roxygen2-6.0.0.Rmd ├── roxygen2.R ├── roxygen2.Rmd ├── roxygen2.html └── roxygen2.md /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^man-roxygen$ 2 | ^.*\.Rproj$ 3 | ^\.Rproj\.user$ 4 | ^\.travis\.yml$ 5 | ^cran-comments\.md$ 6 | ^roxygen.pro$ 7 | ^roxygen.pro.user$ 8 | ^revdep$ 9 | ^codecov\.yml$ 10 | ^appveyor\.yml$ 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /NEWS.md merge=union 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | .Rproj.user 3 | /.Rhistory 4 | 5 | ## Qt Creator 6 | *.pro 7 | *.pro.user 8 | inst/doc 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: r 2 | sudo: false 3 | cache: packages 4 | 5 | r: 6 | - oldrel 7 | - release 8 | - devel 9 | 10 | after_success: 11 | - Rscript -e 'covr::codecov()' 12 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: roxygen2 2 | Title: In-Line Documentation for R 3 | Description: Generate your Rd documentation, 'NAMESPACE' file, and collation 4 | field using specially formatted comments. Writing documentation in-line 5 | with code makes it easier to keep your documentation up-to-date as your 6 | requirements change. 'Roxygen2' is inspired by the 'Doxygen' system for C++. 7 | Version: 6.0.1.9000 8 | License: GPL (>= 2) 9 | Authors@R: c( 10 | person("Hadley", "Wickham",, "hadley@rstudio.com", c("aut", "cre", "cph")), 11 | person("Peter", "Danenberg",, "pcd@roxygen.org", c("aut", "cph")), 12 | person("Manuel", "Eugster", role = c("aut", "cph")), 13 | person("RStudio", role = "cph") 14 | ) 15 | Depends: 16 | R (>= 3.0.2) 17 | Imports: 18 | stringr (>= 0.5), 19 | stringi, 20 | brew, 21 | digest, 22 | methods, 23 | Rcpp (>= 0.11.0), 24 | R6 (>= 2.1.2), 25 | desc, 26 | commonmark, 27 | xml2, 28 | utils 29 | Suggests: 30 | testthat (>= 0.8.0), 31 | knitr, 32 | devtools, 33 | rmarkdown, 34 | covr 35 | VignetteBuilder: knitr 36 | LinkingTo: Rcpp 37 | Roxygen: list(markdown = TRUE) 38 | RoxygenNote: 6.0.1 39 | URL: https://github.com/klutometis/roxygen 40 | BugReports: https://github.com/klutometis/roxygen/issues 41 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(c,rd) 4 | S3method(default_export,"NULL") 5 | S3method(default_export,default) 6 | S3method(default_export,rcclass) 7 | S3method(default_export,s3method) 8 | S3method(default_export,s4class) 9 | S3method(default_export,s4generic) 10 | S3method(default_export,s4method) 11 | S3method(format,roxy_field) 12 | S3method(format,roxy_field_alias) 13 | S3method(format,roxy_field_author) 14 | S3method(format,roxy_field_backref) 15 | S3method(format,roxy_field_concept) 16 | S3method(format,roxy_field_description) 17 | S3method(format,roxy_field_details) 18 | S3method(format,roxy_field_docType) 19 | S3method(format,roxy_field_encoding) 20 | S3method(format,roxy_field_examples) 21 | S3method(format,roxy_field_family) 22 | S3method(format,roxy_field_field) 23 | S3method(format,roxy_field_formals) 24 | S3method(format,roxy_field_format) 25 | S3method(format,roxy_field_inherit) 26 | S3method(format,roxy_field_inherit_dot_params) 27 | S3method(format,roxy_field_inherit_section) 28 | S3method(format,roxy_field_keyword) 29 | S3method(format,roxy_field_minidesc) 30 | S3method(format,roxy_field_name) 31 | S3method(format,roxy_field_note) 32 | S3method(format,roxy_field_param) 33 | S3method(format,roxy_field_rawRd) 34 | S3method(format,roxy_field_rcmethods) 35 | S3method(format,roxy_field_reexport) 36 | S3method(format,roxy_field_references) 37 | S3method(format,roxy_field_section) 38 | S3method(format,roxy_field_seealso) 39 | S3method(format,roxy_field_slot) 40 | S3method(format,roxy_field_source) 41 | S3method(format,roxy_field_title) 42 | S3method(format,roxy_field_usage) 43 | S3method(format,roxy_field_value) 44 | S3method(merge,roxy_field) 45 | S3method(merge,roxy_field_inherit) 46 | S3method(merge,roxy_field_inherit_dot_params) 47 | S3method(merge,roxy_field_inherit_section) 48 | S3method(merge,roxy_field_minidesc) 49 | S3method(merge,roxy_field_reexport) 50 | S3method(merge,roxy_field_section) 51 | S3method(obj_type,MethodDefinition) 52 | S3method(obj_type,classRepresentation) 53 | S3method(obj_type,default) 54 | S3method(obj_type,genericFunction) 55 | S3method(obj_type,package) 56 | S3method(obj_type,refClassRepresentation) 57 | S3method(obj_type,refMethodDef) 58 | S3method(obj_type,s3generic) 59 | S3method(obj_type,s3method) 60 | S3method(object_defaults,data) 61 | S3method(object_defaults,default) 62 | S3method(object_defaults,import) 63 | S3method(object_defaults,package) 64 | S3method(object_defaults,rcclass) 65 | S3method(object_defaults,s4class) 66 | S3method(object_defaults,s4method) 67 | S3method(object_format,default) 68 | S3method(print,object) 69 | S3method(print,rd) 70 | S3method(print,roxy_field) 71 | S3method(print,roxy_tag) 72 | S3method(roclet_clean,roclet_namespace) 73 | S3method(roclet_clean,roclet_rd) 74 | S3method(roclet_output,roclet_namespace) 75 | S3method(roclet_output,roclet_rd) 76 | S3method(roclet_output,roclet_vignette) 77 | S3method(roclet_process,roclet_namespace) 78 | S3method(roclet_process,roclet_rd) 79 | S3method(roclet_process,roclet_vignette) 80 | S3method(roclet_tags,roclet_namespace) 81 | S3method(roclet_tags,roclet_rd) 82 | S3method(roclet_tags,roclet_vignette) 83 | export(is_s3_generic) 84 | export(is_s3_method) 85 | export(load_options) 86 | export(namespace_roclet) 87 | export(object) 88 | export(object_format) 89 | export(rd_roclet) 90 | export(roc_proc_text) 91 | export(roclet) 92 | export(roclet_clean) 93 | export(roclet_find) 94 | export(roclet_output) 95 | export(roclet_process) 96 | export(roclet_tags) 97 | export(roxy_tag) 98 | export(roxy_tag_warning) 99 | export(roxygenise) 100 | export(roxygenize) 101 | export(tag_code) 102 | export(tag_examples) 103 | export(tag_inherit) 104 | export(tag_markdown) 105 | export(tag_markdown_restricted) 106 | export(tag_name) 107 | export(tag_name_description) 108 | export(tag_toggle) 109 | export(tag_two_part) 110 | export(tag_value) 111 | export(tag_words) 112 | export(tag_words_line) 113 | export(update_collate) 114 | export(vignette_roclet) 115 | import(stringr) 116 | importFrom(R6,R6Class) 117 | importFrom(Rcpp,sourceCpp) 118 | importFrom(commonmark,markdown_xml) 119 | importFrom(methods,is) 120 | importFrom(stats,setNames) 121 | importFrom(utils,URLdecode) 122 | importFrom(utils,URLencode) 123 | importFrom(xml2,read_xml) 124 | importFrom(xml2,xml_attr) 125 | importFrom(xml2,xml_children) 126 | importFrom(xml2,xml_contents) 127 | importFrom(xml2,xml_name) 128 | importFrom(xml2,xml_text) 129 | importFrom(xml2,xml_type) 130 | useDynLib(roxygen2) 131 | -------------------------------------------------------------------------------- /R/RcppExports.R: -------------------------------------------------------------------------------- 1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | findEndOfTag <- function(string, is_code = FALSE) { 5 | .Call('roxygen2_findEndOfTag', PACKAGE = 'roxygen2', string, is_code) 6 | } 7 | 8 | rdComplete <- function(string, is_code = FALSE) { 9 | .Call('roxygen2_rdComplete', PACKAGE = 'roxygen2', string, is_code) 10 | } 11 | 12 | leadingSpaces <- function(lines) { 13 | .Call('roxygen2_leadingSpaces', PACKAGE = 'roxygen2', lines) 14 | } 15 | 16 | tokenise_block <- function(lines, file = "", offset = 0L) { 17 | .Call('roxygen2_tokenise_block', PACKAGE = 'roxygen2', lines, file, offset) 18 | } 19 | 20 | find_includes <- function(path) { 21 | .Call('roxygen2_find_includes', PACKAGE = 'roxygen2', path) 22 | } 23 | 24 | splitByWhitespace <- function(string) { 25 | .Call('roxygen2_splitByWhitespace', PACKAGE = 'roxygen2', string) 26 | } 27 | 28 | wrapString <- function(string, width = 80L, indent = 2L) { 29 | .Call('roxygen2_wrapString', PACKAGE = 'roxygen2', string, width, indent) 30 | } 31 | 32 | -------------------------------------------------------------------------------- /R/collate.R: -------------------------------------------------------------------------------- 1 | #' Update Collate field in DESCRIPTION. 2 | #' 3 | #' Topologically sort R files and record in Collate field. The topological 4 | #' sort is based on the `@include` tag, which should specify the filenames 5 | #' (space separated) that should be loaded before the current file. These are 6 | #' typically necessary if you're using S4 or RC classes (because super classes 7 | #' must be defined before subclasses). 8 | #' 9 | #' If there are no `@include` tags, roxygen2 will leave collate as is. 10 | #' This makes it easier to use roxygen2 with an existing collate directive, 11 | #' but if you remove all your `@include` tags, you'll need to also 12 | #' manually delete the collate field. 13 | #' 14 | #' This is not a roclet because roclets need the values of objects in a package, 15 | #' and those values can not be generated unless you've sourced the files, 16 | #' and you can't source the files unless you know the correct order. 17 | #' 18 | #' @param base_path Path to package directory. 19 | #' @examples 20 | #' #' `example-a.R', `example-b.R' and `example-c.R' reside 21 | #' #' in the `example' directory, with dependencies 22 | #' #' a -> {b, c}. This is `example-a.R'. 23 | #' #' @@include example-b.R 24 | #' #' @@include example-c.R 25 | #' NULL 26 | #' 27 | #' \dontrun{ 28 | #' update_collate("my_package") 29 | #' } 30 | #' @export 31 | update_collate <- function(base_path) { 32 | new <- generate_collate(file.path(base_path, "R")) 33 | if (is.null(new)) return() 34 | 35 | desc_path <- file.path(base_path, "DESCRIPTION") 36 | old <- desc::desc_get_collate(file = desc_path) 37 | 38 | if (!identical(old, new)) { 39 | cat('Updating collate directive in ', desc_path, "\n") 40 | desc::desc_set_collate(new, file = desc_path) 41 | } 42 | 43 | invisible() 44 | } 45 | 46 | generate_collate <- function(base_path) { 47 | paths <- sort_c(dir(base_path, pattern = "[.][Rr]$", full.names = TRUE)) 48 | includes <- lapply(paths, find_includes) 49 | names(includes) <- paths 50 | 51 | n <- sum(vapply(includes, length, integer(1))) 52 | if (n == 0) return() 53 | 54 | topo <- TopoSort$new() 55 | for (path in paths) { 56 | file <- base_path(path, base_path) 57 | 58 | topo$add(file) 59 | for (include in includes[[path]]) { 60 | topo$add_ancestor(file, include) 61 | } 62 | } 63 | 64 | topo$sort() 65 | } 66 | 67 | base_path <- function(path, base) { 68 | path <- normalizePath(path, winslash = "/") 69 | base <- normalizePath(base, winslash = "/") 70 | 71 | str_replace(path, fixed(paste0(base, "/")), "") 72 | } 73 | -------------------------------------------------------------------------------- /R/enc.R: -------------------------------------------------------------------------------- 1 | read_lines_enc <- function(path, file_encoding = "UTF-8", n = -1L, ok = TRUE, skipNul = FALSE) { 2 | con <- file(path, encoding = file_encoding) 3 | on.exit(close(con), add = TRUE) 4 | 5 | lines <- readLines(con, warn = FALSE, n = n, ok = ok, skipNul = skipNul) 6 | Encoding(lines) <- "UTF-8" 7 | lines 8 | } 9 | -------------------------------------------------------------------------------- /R/object-defaults.R: -------------------------------------------------------------------------------- 1 | # Combine a block with defaults generated from the object 2 | add_defaults <- function(block) { 3 | defaults <- object_defaults(block$object) 4 | 5 | for (tag in names(defaults)) { 6 | if (tag %in% names(block)) next 7 | 8 | block[[tag]] <- defaults[[tag]] 9 | } 10 | 11 | block 12 | } 13 | 14 | object_defaults <- function(x) UseMethod("object_defaults") 15 | 16 | #' @export 17 | object_defaults.default <- function(x) list() 18 | 19 | #' @export 20 | object_defaults.data <- function(x) { 21 | str_out <- rd(object_format(x$value)) 22 | 23 | list( 24 | docType = "data", 25 | format = str_out, 26 | keywords = "datasets" 27 | ) 28 | } 29 | 30 | #' @export 31 | object_defaults.import <- function(x) { 32 | list( 33 | docType = "import", 34 | name = "reexports", 35 | keywords = "internal", 36 | title = "Objects exported from other packages", 37 | .reexport = roxy_field_reexport(x$value$pkg, x$value$fun) 38 | ) 39 | } 40 | 41 | #' @export 42 | object_defaults.package <- function(x) { 43 | desc <- x$value$desc 44 | 45 | list( 46 | docType = "package", 47 | name = package_suffix(desc$Package), 48 | # "NULL" prevents addition of default aliases, see also #202 49 | aliases = paste("NULL", desc$Package, package_suffix(desc$Package)), 50 | title = paste0(desc$Package, ": ", desc$Title), 51 | description = as.character(desc$Description), 52 | seealso = package_seealso(desc), 53 | author = package_authors(desc) 54 | ) 55 | } 56 | 57 | #' @export 58 | object_defaults.s4class <- function(x) { 59 | list( 60 | docType = "class" 61 | ) 62 | } 63 | 64 | #' @export 65 | object_defaults.rcclass <- function(x) { 66 | list( 67 | docType = "class" 68 | ) 69 | } 70 | 71 | #' @export 72 | object_defaults.s4method <- function(x) { 73 | list( 74 | docType = "methods" 75 | ) 76 | } 77 | -------------------------------------------------------------------------------- /R/object-format.R: -------------------------------------------------------------------------------- 1 | #' Default format for data 2 | #' 3 | #' This function is called to generate the default "Format" section for each 4 | #' data object. The default implementation will return the class and dimension 5 | #' information. 6 | #' 7 | #' @param x A data object 8 | #' @return A `character` value with valid `Rd` syntax, or `NULL`. 9 | #' @export 10 | object_format <- function(x) { 11 | UseMethod("object_format") 12 | } 13 | 14 | #' @export 15 | object_format.default <- function(x) { 16 | paste0("An object of class ", format_classes(x), " ", format_dim(x), ".") 17 | } 18 | 19 | format_classes <- function(x) { 20 | classes <- paste0("\\code{", class(x), "}") 21 | 22 | base_classes <- NULL 23 | if (length(classes) > 1L) { 24 | base_classes <- paste0( 25 | " (inherits from ", 26 | paste(classes[-1L], collapse = ", "), 27 | ")") 28 | } 29 | 30 | paste0(classes[[1L]], base_classes) 31 | } 32 | 33 | format_dim <- function(x) { 34 | if (length(dim(x)) == 2L) { 35 | paste0("with ", nrow(x), " rows and ", ncol(x), " columns") 36 | } else if (length(dim(x)) > 2L) { 37 | paste0("of dimension ", paste(dim(x), collapse = " x ")) 38 | } else { 39 | paste0("of length ", length(x)) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /R/object-from-call.R: -------------------------------------------------------------------------------- 1 | object_from_call <- function(call, env, block, file) { 2 | if (is.null(call)) return() 3 | 4 | # Special case: you can refer to other objects as strings 5 | if (is.character(call)) { 6 | value <- find_data(call, env, file) 7 | value <- standardise_obj(call, value, env, block) 8 | 9 | return(object(value, call)) 10 | } 11 | 12 | if (!is.call(call)) return() 13 | 14 | call <- standardise_call(call, env) 15 | name <- as.character(call[[1]]) 16 | 17 | if (length(name) > 1) return(NULL) 18 | 19 | # Dispatch to registered srcref parsers based on function name 20 | parser <- find_parser(name) 21 | if (is.null(parser)) return(NULL) 22 | 23 | parser(call, env, block) 24 | } 25 | 26 | find_data <- function(name, env, file) { 27 | if (identical(name, "_PACKAGE")) { 28 | return(find_data_for_package(env, file)) 29 | } 30 | 31 | ns <- env_namespace(env) 32 | if (is.null(ns)) { 33 | get(name, envir = env) 34 | } else { 35 | getExportedValue(name, ns = ns) 36 | } 37 | } 38 | 39 | find_data_for_package <- function(env, file) { 40 | pkg_path <- dirname(dirname(file)) 41 | desc <- read.description(file.path(pkg_path, "DESCRIPTION")) 42 | 43 | structure(list(desc = desc), class = "package") 44 | } 45 | 46 | # Find namespace associated with environment 47 | env_namespace <- function(env) { 48 | ns <- NULL 49 | try(ns <- asNamespace(env), silent = TRUE) 50 | if (is.null(ns)) return(NULL) 51 | 52 | ns 53 | } 54 | 55 | find_parser <- function(name) { 56 | if (name %in% c("=", "<-", "<<-")) name <- "assignment" 57 | 58 | parser_name <- paste0("parser_", name) 59 | if (!exists(parser_name)) return(NULL) 60 | 61 | get(parser_name, mode = "function") 62 | } 63 | 64 | standardise_call <- function(call, env = parent.frame()) { 65 | stopifnot(is.call(call)) 66 | 67 | f <- eval(call[[1]], env) 68 | if (is.primitive(f)) return(call) 69 | 70 | match.call(f, call) 71 | } 72 | 73 | parser_assignment <- function(call, env, block) { 74 | name <- as.character(call[[2]]) 75 | 76 | # If it's a compound assignment like x[[2]] <- ignore it 77 | if (length(name) > 1) return() 78 | 79 | # If it doesn't exist (any more), don't document it. 80 | if (!exists(name, env)) return() 81 | 82 | value <- get(name, env) 83 | value <- standardise_obj(name, value, env, block) 84 | 85 | object(value, name) 86 | } 87 | 88 | 89 | parser_setClass <- function(call, env, block) { 90 | name <- as.character(call$Class) 91 | value <- methods::getClass(name, where = env) 92 | 93 | object(value) 94 | } 95 | 96 | parser_setClassUnion <- function(call, env, block) { 97 | name <- as.character(call$name) 98 | value <- methods::getClass(name, where = env) 99 | 100 | object(value) 101 | } 102 | 103 | parser_setRefClass <- function(call, env, block) { 104 | name <- as.character(call$Class) 105 | value <- methods::getClass(name, where = env) 106 | 107 | object(value) 108 | } 109 | 110 | parser_setGeneric <- function(call, env, block) { 111 | name <- as.character(call$name) 112 | value <- methods::getGeneric(name, where = env) 113 | 114 | object(value) 115 | } 116 | 117 | parser_setMethod <- function(call, env, block) { 118 | name <- as.character(call$f) 119 | value <- methods::getMethod(name, eval(call$signature), where = env) 120 | value@.Data <- extract_method_fun(value@.Data) 121 | 122 | object(value) 123 | } 124 | 125 | parser_setReplaceMethod <- function(call, env, block) { 126 | name <- paste0(as.character(call$f), "<-") 127 | value <- methods::getMethod(name, eval(call[[3]]), where = env) 128 | value@.Data <- extract_method_fun(value@.Data) 129 | 130 | object(value) 131 | } 132 | 133 | `parser_::` <- function(call, env, block) { 134 | pkg <- as.character(call[[2]]) 135 | fun <- as.character(call[[3]]) 136 | 137 | object(list(pkg = pkg, fun = fun), alias = fun, type = "import") 138 | } 139 | 140 | parser_setMethodS3 <- function(call, env, block) { 141 | # R.methodsS3::setMethodS3(name, class, ...) 142 | method <- as.character(call[[2]]) 143 | class <- as.character(call[[3]]) 144 | name <- paste(method, class, sep=".") 145 | value <- standardise_obj(get(name, env), value, env, block) 146 | object(value, name) 147 | } 148 | 149 | parser_setConstructorS3 <- function(call, env, block) { 150 | # R.oo::setConstructorS3(name, ...) 151 | name <- as.character(call[[2]]) 152 | value <- standardise_obj(get(name, env), value, env, block) 153 | object(value, name) 154 | } 155 | -------------------------------------------------------------------------------- /R/object-name.R: -------------------------------------------------------------------------------- 1 | # Name -------------------------------------------------------------------- 2 | 3 | object_name <- function(x) UseMethod("object_name") 4 | object_name.s4class <- function(x) x$value@className 5 | object_name.s4generic <- function(x) x$value@generic 6 | object_name.s4method <- function(x) x$value@generic 7 | object_name.rcclass <- function(x) x$value@className 8 | object_name.rcmethod <- function(x) x$value@name 9 | object_name.s3generic <- function(x) stop("Unsupported type", call. = FALSE) 10 | object_name.s3method <- function(x) attr(x$value, "s3method") 11 | object_name.function <- function(x) x$alias 12 | object_name.default <- function(x) NULL 13 | 14 | # Topic name -------------------------------------------------------------- 15 | 16 | object_topic <- function(x) UseMethod("object_topic") 17 | 18 | object_topic.s4method <- function(x) { 19 | sig <- paste0(x$value@defined, collapse = ",") 20 | paste0(x$value@generic, ",", sig, "-method") 21 | } 22 | 23 | object_topic.s4class <- function(x) { 24 | paste0(x$value@className, "-class") 25 | } 26 | 27 | object_topic.rcclass <- function(x) { 28 | paste0(x$value@className, "-class") 29 | } 30 | 31 | object_topic.rcmethod <- function(x) { 32 | x@name 33 | } 34 | 35 | object_topic.default <- function(x) { 36 | if (length(x$alias) == 1) return(x$alias) 37 | object_name(x) 38 | } 39 | -------------------------------------------------------------------------------- /R/object-package.R: -------------------------------------------------------------------------------- 1 | package_seealso <- function(desc) { 2 | if (!is.null(desc$URL)) { 3 | links <- paste0("\\url{", strsplit(desc$URL, ",\\s+")[[1]], "}") 4 | } else { 5 | links <- character() 6 | } 7 | if (!is.null(desc$BugReports)) { 8 | links <- c(links, paste0("Report bugs at \\url{", desc$BugReports, "}")) 9 | } 10 | 11 | itemize("Useful links:", links) 12 | } 13 | 14 | package_authors <- function(desc) { 15 | authors <- tryCatch(eval(parse(text = desc$`Authors@R`)), 16 | error = function(e) { 17 | warning(e) 18 | NULL 19 | } 20 | ) 21 | if (is.null(authors)) 22 | return() 23 | 24 | desc <- vapply(unclass(authors), author_desc, character(1)) 25 | type <- vapply(unclass(authors), author_type, character(1)) 26 | by_type <- split(desc, type) 27 | 28 | paste( 29 | c( 30 | paste0("\\strong{Maintainer}: ", by_type$cre[[1]], "\n"), 31 | itemize("Authors:", by_type$aut), 32 | itemize("Other contributors:", by_type$other) 33 | ), 34 | collapse = "\n" 35 | ) 36 | } 37 | 38 | author_desc <- function(x) { 39 | desc <- x$given 40 | 41 | if (!is.null(x$family)) { 42 | desc <- paste0(desc, " ", x$family) 43 | } 44 | 45 | if (!is.null(x$email)) { 46 | desc <- paste0(desc, " \\email{", x$email, "}") 47 | } 48 | 49 | if (!is.null(x$comment)) { 50 | desc <- paste0(desc, " (", x$comment, ")") 51 | } 52 | 53 | extra_roles <- setdiff(x$role, c("cre", "aut")) 54 | if (length(extra_roles) > 0) { 55 | desc <- paste0( 56 | desc, " [", paste0(role_lookup[extra_roles], collapse = ", "), "]" 57 | ) 58 | } 59 | 60 | desc 61 | } 62 | 63 | author_type <- function(x) { 64 | if ("cre" %in% x$role) { 65 | "cre" 66 | } else if ("aut" %in% x$role) { 67 | "aut" 68 | } else { 69 | "other" 70 | } 71 | } 72 | 73 | role_lookup <- c( 74 | "aut" = "author", 75 | "com" = "compiler", 76 | "ctb" = "contributor", 77 | "cph" = "copyright holder", 78 | "cre" = "maintainer", 79 | "ctr" = "contractor", 80 | "dtc" = "data contributor", 81 | "fnd" = "funder", 82 | "ths" = "thesis advisor", 83 | "trl" = "translator" 84 | ) 85 | 86 | itemize <- function(header, x) { 87 | if (length(x) == 0) 88 | return() 89 | 90 | paste0( 91 | header, "\n", 92 | "\\itemize{\n", 93 | paste0(" \\item ", x, "\n", collapse = ""), 94 | "}\n" 95 | ) 96 | } 97 | -------------------------------------------------------------------------------- /R/object-rc.R: -------------------------------------------------------------------------------- 1 | # Extract all methods from an RC definition, returning a list of "objects". 2 | rc_methods <- function(obj) { 3 | stopifnot(methods::is(obj, "refClassRepresentation")) 4 | 5 | parents <- obj@refSuperClasses 6 | parent_methods <- unlist(lapply(parents, function(x) { 7 | methods::getRefClass(x)$methods() 8 | })) 9 | method_names <- setdiff(ls(envir = obj@refMethods), parent_methods) 10 | methods <- mget(method_names, envir = obj@refMethods) 11 | 12 | lapply(methods, object) 13 | } 14 | 15 | add_rc_metadata <- function(val, name, class) { 16 | class(val) <- c("rcmethod", "function") 17 | attr(val, "rcclass") <- class 18 | attr(val, "rcmethod") <- name 19 | 20 | val 21 | } 22 | 23 | get_method <- function(obj, method_name) { 24 | eval(call("$", quote(obj), as.name(method_name))) 25 | } 26 | 27 | # Modified from methods:::.refMethodDoc - a function has a doc string 28 | # if it's a call to {, with more than 1 element, and the first element is 29 | # a character vector. 30 | docstring <- function(f) { 31 | stopifnot(is.function(f)) 32 | if (is.primitive(f)) return(NULL) 33 | 34 | b <- body(f) 35 | if (length(b) <= 2 || !identical(b[[1]], quote(`{`))) return(NULL) 36 | 37 | first <- b[[2]] 38 | if (!is.character(first)) return(NULL) 39 | if (first == "") return(NULL) 40 | 41 | trim_docstring(first) 42 | } 43 | 44 | # Implementation converted from 45 | # http://www.python.org/dev/peps/pep-0257/#handling-docstring-indentation 46 | trim_docstring <- function(docstring) { 47 | if (docstring == "") return("") 48 | 49 | # Convert tabs to spaces (using four spaces for tabs) 50 | # and split into a vector of lines: 51 | lines <- strsplit(gsub("\t", " ", docstring), "\n")[[1]] 52 | if (length(lines) == 1) return(strip(lines)) 53 | 54 | # Determine minimum indentation (first line doesn't count): 55 | indent <- min(leadingSpaces(lines[-1])) 56 | 57 | # Remove indentation (first line is special): 58 | trimmed <- c( 59 | strip(lines[1]), 60 | substr(lines[-1], indent + 1, 1000L) 61 | ) 62 | 63 | # Return a single string: 64 | string <- paste0(trimmed, collapse = "\n") 65 | 66 | # Strip off trailing and leading blank lines: 67 | gsub("^\n+|\n+$", "", string) 68 | } 69 | 70 | strip <- function(x) gsub("^ +| + $", "", x) 71 | -------------------------------------------------------------------------------- /R/object-s3.R: -------------------------------------------------------------------------------- 1 | #' Determine if a function is an S3 generic or S3 method. 2 | #' 3 | #' @description 4 | #' `is_s3_generic` compares name to `.knownS3Generics` and 5 | #' `.S3PrimitiveGenerics`, then looks at the function body to see if it 6 | #' calls [UseMethod()]. 7 | #' 8 | #' `is_s3_method` builds names of all possible generics for that function 9 | #' and then checks if any of them actually is a generic. 10 | #' 11 | #' @param name Name of function. 12 | #' @param env Base environment in which to look for function defintion. 13 | #' @export 14 | is_s3_generic <- function(name, env = parent.frame()) { 15 | if (name == "") return(FALSE) 16 | if (!exists(name, envir = env)) return(FALSE) 17 | 18 | f <- get(name, envir = env) 19 | if (!is.function(f)) return(FALSE) 20 | if (inherits(f, "groupGenericFunction")) return(TRUE) 21 | 22 | ns_name <- tryCatch(getNamespaceName(environment(f)), error = function(e) "") 23 | if (identical(unname(.knownS3Generics[name]), ns_name)) 24 | return(TRUE) 25 | 26 | if (is.primitive(f)) { 27 | known_generics <- c(names(.knownS3Generics), 28 | internal_f("tools", ".get_internal_S3_generics")()) 29 | return(name %in% known_generics) 30 | } 31 | 32 | calls_use_method(body(f)) 33 | } 34 | 35 | calls_use_method <- function(x) { 36 | # Base cases 37 | if (missing(x)) return(FALSE) 38 | if (!is.call(x)) return(FALSE) 39 | 40 | if (identical(x[[1]], quote(UseMethod))) return(TRUE) 41 | if (length(x) == 1) return(FALSE) 42 | # Recursive case: arguments to call 43 | for (arg in as.list(x[-1])) { 44 | if (calls_use_method(arg)) return(TRUE) 45 | } 46 | 47 | FALSE 48 | } 49 | 50 | #' @rdname is_s3_generic 51 | #' @export 52 | is_s3_method <- function(name, env = parent.frame()) { 53 | !is.null(find_generic(name, env)) 54 | } 55 | 56 | is.s3method <- function(x) inherits(x, "s3method") 57 | is.s3generic <- function(x) inherits(x, "s3generic") 58 | is.s3 <- function(x) inherits(x, c("s3method", "s3generic")) 59 | 60 | find_generic <- function(name, env = parent.frame()) { 61 | pieces <- str_split(name, fixed("."))[[1]] 62 | n <- length(pieces) 63 | 64 | # No . in name, so can't be method 65 | if (n == 1) return(NULL) 66 | 67 | for(i in seq_len(n - 1)) { 68 | generic <- paste0(pieces[seq_len(i)], collapse = ".") 69 | class <- paste0(pieces[(i + 1):n], collapse = ".") 70 | 71 | if (is_s3_generic(generic, env)) return(c(generic, class)) 72 | } 73 | NULL 74 | } 75 | 76 | # @param override Either NULL to use default, or a character vector of length 2 77 | add_s3_metadata <- function(val, name, env, override = NULL) { 78 | if (!is.function(val)) return(val) 79 | 80 | if (!is.null(override)) { 81 | return(s3_method(val, override, env)) 82 | } 83 | 84 | if (is_s3_generic(name, env)) { 85 | class(val) <- c("s3generic", "function") 86 | return(val) 87 | } 88 | 89 | method <- find_generic(name, env) 90 | if (is.null(method)) return(val) 91 | 92 | s3_method(val, method, env) 93 | } 94 | 95 | s3_method <- function(f, method, env) { 96 | stopifnot(length(method) == 2, is.character(method)) 97 | 98 | class(f) <- c("s3method", "function") 99 | attr(f, "s3method") <- method 100 | attr(f, "s3env") <- env 101 | 102 | f 103 | } 104 | 105 | s3_method_info <- function(x) { 106 | stopifnot(is.s3(x)) 107 | attr(x, "s3method") 108 | } 109 | -------------------------------------------------------------------------------- /R/object-usage.R: -------------------------------------------------------------------------------- 1 | object_usage <- function(x) { 2 | UseMethod("object_usage") 3 | } 4 | 5 | object_usage.default <- function(x) NULL 6 | 7 | object_usage.NULL <- function(x) NULL 8 | 9 | object_usage.data <- function(x) x$alias 10 | 11 | object_usage.function <- function(x) { 12 | function_usage(x$alias, formals(x$value), identity) 13 | } 14 | 15 | object_usage.s3generic <- object_usage.function 16 | 17 | object_usage.s3method <- function(x) { 18 | method <- attr(x$value, "s3method") 19 | s3method <- function(name) { 20 | build_rd("\\method{", name, "}{", method[2], "}") 21 | } 22 | function_usage(method[1], formals(x$value), s3method) 23 | } 24 | 25 | object_usage.s4generic <- function(x) { 26 | function_usage(x$value@generic, formals(x$value), identity) 27 | } 28 | 29 | object_usage.s4method <- function(x) { 30 | s4method <- function(name) { 31 | classes <- as.character(x$value@defined) 32 | needs_backtick <- !is.syntactic(classes) 33 | classes[needs_backtick] <- paste0("`", classes[needs_backtick], "`") 34 | 35 | build_rd("\\S4method{", name, "}{", paste0(classes, collapse = ","), "}") 36 | } 37 | function_usage(x$value@generic, formals(x$value), s4method) 38 | } 39 | 40 | object_usage.s4class <- function(x) NULL 41 | 42 | object_usage.rcclass <- function(x) NULL 43 | 44 | 45 | # Function usage ---------------------------------------------------------- 46 | 47 | # Usage: 48 | # replacement, infix, regular 49 | # function, s3 method, s4 method, data 50 | 51 | function_usage <- function(name, formals, format_name = identity) { 52 | arglist <- args_string(usage_args(formals)) 53 | if (is_replacement_fun(name) && !is_infix_fun(name)) { 54 | name <- str_replace(name, fixed("<-"), "") 55 | formals$value <- NULL 56 | 57 | arglist <- args_string(usage_args(formals)) 58 | build_rd(format_name(name), "(", arglist, ")\u{A0}<-\u{A0}value") 59 | } else if (is_infix_fun(name) && identical(format_name, identity)) { 60 | # If infix, and regular function, munge format 61 | arg_names <- names(formals) 62 | 63 | build_rd(arg_names[1], " ", format_name(name), " ", arg_names[2]) 64 | } else { 65 | # Quote non-syntactic names if no special formatting 66 | if (identical(format_name, identity)) { 67 | name <- quote_if_needed(name) 68 | } 69 | 70 | build_rd(format_name(name), "(", arglist, ")") 71 | } 72 | } 73 | 74 | is_replacement_fun <- function(name) { 75 | str_detect(name, fixed("<-")) 76 | } 77 | is_infix_fun <- function(name) { 78 | str_detect(name, "^%.*%$") 79 | } 80 | 81 | usage_args <- function(args) { 82 | is.missing.arg <- function(arg) { 83 | is.symbol(arg) && deparse(arg) == "" 84 | } 85 | arg_to_text <- function(arg) { 86 | if (is.missing.arg(arg)) return("") 87 | text <- deparse(arg, backtick = TRUE, width.cutoff = 500L) 88 | text <- paste0(text, collapse = "\n") 89 | Encoding(text) <- "UTF-8" 90 | 91 | text 92 | } 93 | vapply(args, arg_to_text, character(1)) 94 | } 95 | 96 | args_string <- function(x) { 97 | missing_arg <- x == "" 98 | sep <- ifelse(!missing_arg, "\u{A0}=\u{A0}", "") 99 | 100 | arg_names <- names(x) 101 | needs_backtick <- !is.syntactic(arg_names) 102 | arg_names[needs_backtick] <- paste0("`", arg_names[needs_backtick], "`") 103 | 104 | paste0(arg_names, sep, x, collapse = ", ") 105 | } 106 | -------------------------------------------------------------------------------- /R/object.R: -------------------------------------------------------------------------------- 1 | #' Constructors for S3 object to represent R objects. 2 | #' 3 | #' These objects are usually created by the parsers, but it is also 4 | #' useful to generate them by hand for testing. 5 | #' 6 | #' @param value The object itself. 7 | #' @param alias Alias for object being documented, in case you create a 8 | #' generator function with different name. 9 | #' @export 10 | #' @keywords internal 11 | object <- function(value, alias = NULL, type = obj_type(value)) { 12 | structure( 13 | list( 14 | alias = alias, 15 | value = value, 16 | methods = if (type == "rcclass") rc_methods(value) 17 | ), 18 | class = c(type, "object") 19 | ) 20 | } 21 | 22 | #' @export 23 | print.object <- function(x, ...) { 24 | cat("<", class(x)[1], "> ", x$name, 25 | if (!is.null(x$alias)) paste0(" (", x$alias, ")"), "\n", 26 | sep = "" 27 | ) 28 | } 29 | 30 | # Take object created by assignment and standardise 31 | standardise_obj <- function(name, value, env = emptyenv(), block = list()) { 32 | if (is_generator(value)) { 33 | # S4 and RC generators need to be converted to their classes 34 | methods::getClass(as.character(value@className), where = env) 35 | } else if (inherits(value, "MethodDefinition")) { 36 | # S4 methods need munging to get real function def 37 | value@.Data <- extract_method_fun(value@.Data) 38 | value 39 | } else if (is.function(value)) { 40 | # Potential S3 methods/generics need metadata added 41 | method <- unlist(block$method, use.names = FALSE) 42 | add_s3_metadata(value, name, env, method) 43 | } else { 44 | value 45 | } 46 | } 47 | 48 | is_generator <- function(x) { 49 | methods::is(x, "refObjectGenerator") || methods::is(x, "classGeneratorFunction") 50 | } 51 | 52 | # When a generic has ... and a method adds new arguments, the S4 method 53 | # wraps the definition inside another function which has the same arguments 54 | # as the generic. This function figures out if that's the case, and extracts 55 | # the original function if so. 56 | # 57 | # It's based on expression processing based on the structure of the 58 | # constructed method which looks like: 59 | # 60 | # function (x, ...) { 61 | # .local <- function (x, ..., y = 7) {} 62 | # .local(x, ...) 63 | # } 64 | extract_method_fun <- function(x) { 65 | fun <- x@.Data 66 | 67 | method_body <- body(fun) 68 | if (!is.call(method_body)) return(fun) 69 | if (!identical(method_body[[1]], quote(`{`))) return(fun) 70 | 71 | first_line <- method_body[[2]] 72 | if (!is.call(first_line)) return(fun) 73 | if (!identical(first_line[[1]], quote(`<-`))) return(fun) 74 | if (!identical(first_line[[2]], quote(`.local`))) return(fun) 75 | 76 | first_line[[3]] 77 | } 78 | 79 | # Consistent naming scheme for R object classes -------------------------------- 80 | # (s3/s4/rc x generic/class/method, function, data) 81 | 82 | obj_type <- function(x) UseMethod("obj_type") 83 | 84 | #' @export 85 | obj_type.s3generic <- function(x) "s3generic" 86 | #' @export 87 | obj_type.s3method <- function(x) "s3method" 88 | 89 | #' @export 90 | obj_type.classRepresentation <- function(x) "s4class" 91 | #' @export 92 | obj_type.genericFunction <- function(x) "s4generic" 93 | #' @export 94 | obj_type.MethodDefinition <- function(x) "s4method" 95 | 96 | #' @export 97 | obj_type.refClassRepresentation <- function(x) "rcclass" 98 | #' @export 99 | obj_type.refMethodDef <- function(x) "rcmethod" 100 | 101 | #' @export 102 | obj_type.package <- function(x) "package" 103 | #' @export 104 | obj_type.default <- function(x) { 105 | if (is.function(x)) { 106 | "function" 107 | } else { 108 | "data" 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /R/rd-describe-in.R: -------------------------------------------------------------------------------- 1 | topic_add_describe_in <- function(topic, block, env) { 2 | tags <- block_tags(block, "describeIn") 3 | if (length(tags) == 0) 4 | return(NULL) 5 | 6 | if (length(tags) > 1) { 7 | block_warning(block, "May only use one @describeIn per block") 8 | return() 9 | } 10 | if (is.null(block$object)) { 11 | block_warning(block, "@describeIn must be used with an object") 12 | return() 13 | } 14 | if (any(names(block) == "name")) { 15 | block_warning(block, "@describeIn can not be used with @name") 16 | return() 17 | } 18 | if (any(names(block) == "rdname")) { 19 | block_warning(block, "@describeIn can not be used with @rdname") 20 | return() 21 | } 22 | 23 | dest <- find_object(tags$describeIn$name, env) 24 | label <- build_label(block$object, dest, block) 25 | if (is.null(label)) 26 | return() 27 | 28 | topic$add(roxy_field_minidesc( 29 | label$type, 30 | label$label, 31 | tags$describeIn$description 32 | )) 33 | object_topic(dest) 34 | } 35 | 36 | # Imperfect: 37 | # * will fail with S3 methods that need manual disambiguation (rare) 38 | # * can't use if @name overridden, but then you could just the use alias 39 | find_object <- function(name, env) { 40 | if (methods::isClass(name, where = env)) { 41 | object(methods::getClass(name, where = env)) 42 | } else if (exists(name, envir = env)) { 43 | obj <- get(name, envir = env) 44 | obj <- standardise_obj(name, obj, env = env) 45 | object(obj, name) 46 | } else { 47 | object(NULL, name) 48 | } 49 | } 50 | 51 | build_label <- function(src, dest, block) { 52 | src_type <- class(src)[1] 53 | dest_type <- class(dest)[1] 54 | 55 | if (dest_type == "s4class" && src_type == "s4method") { 56 | # Label S4 methods in class with their generic 57 | type <- "class" 58 | label <- as.character(src$value@generic) 59 | } else if (dest_type == "s4generic" && src_type == "s4method") { 60 | # Label S4 methods in generic with their signature 61 | type <- "generic" 62 | sig <- src$value@defined 63 | if (length(sig) == 1) { 64 | label <- as.character(sig) 65 | } else { 66 | label <- paste0(names(sig), " = ", sig, collapse = ",") 67 | } 68 | } else if (dest_type == "function" && src_type == "s3method") { 69 | # Assuming you document S3 methods in the class constructor 70 | type <- "class" 71 | label <- attr(src$value, "s3method")[1] 72 | } else if (dest_type == "s3generic" && src_type == "s3method") { 73 | # Label S3 methods in generic with their class 74 | type <- "generic" 75 | label <- attr(src$value, "s3method")[2] 76 | } else if (dest_type %in% c("function", "data") && src_type == "function") { 77 | # Multiple functions in one Rd labelled with function names 78 | type <- "function" 79 | label <- object_name(src) 80 | } else { 81 | block_warning(block, "Don't know how to describe ", src_type, " in ", dest_type) 82 | return(NULL) 83 | } 84 | 85 | list(type = type, label = label) 86 | } 87 | -------------------------------------------------------------------------------- /R/rd-family.R: -------------------------------------------------------------------------------- 1 | topics_process_family <- function(topics) { 2 | family_index <- invert(topics$simple_values("family")) 3 | aliases <- topics$simple_values("alias") 4 | 5 | for (topic_name in names(topics$topics)) { 6 | topic <- topics$get(topic_name) 7 | families <- topic$get_field("family")$values 8 | 9 | for (family in families) { 10 | related <- family_index[[family]] 11 | 12 | others <- setdiff(related, topic_name) 13 | if (length(others) < 1) 14 | next 15 | 16 | by_file <- vapply(aliases[others], function(x) { 17 | paste0("\\code{\\link{", escape(x[1]), "}}") 18 | }, FUN.VALUE = character(1)) 19 | links <- paste(sort_c(by_file), collapse = ", ") 20 | 21 | seealso <- paste("Other ", family, ": ", sep = "") 22 | out <- strwrap(links, initial = seealso, width = 60, exdent = 2) 23 | 24 | topic$add_simple_field("seealso", paste(out, collapse = "\n")) 25 | } 26 | } 27 | 28 | invisible() 29 | } 30 | -------------------------------------------------------------------------------- /R/rd-params.R: -------------------------------------------------------------------------------- 1 | # Postprocessing to reset ordering of parameter documentation 2 | topics_fix_params_order <- function(topics) { 3 | for (topic in topics$topics) { 4 | # Compute correct ordering of parameter documentation 5 | # Check what's needed... 6 | needed <- topic$get_field("formals")$values 7 | 8 | # (Workaround for dupes that can occur but perhaps shouldn't, 9 | # cf. https://github.com/klutometis/roxygen/commit/83d125dce50a072534988787d49ffe206d19b232#commitcomment-6742169) 10 | needed <- unique(needed) 11 | 12 | # ...and what's documented (here we look only at the first parameter 13 | # in a multi-parameter documentation) 14 | documented <- get_documented_params(topic, only_first = TRUE) 15 | 16 | # We operate on indexes to make sure that no documentation is lost during 17 | # the reordering 18 | documented_indexes <- seq_along(documented) 19 | 20 | # We compute the indexes in the current documentation in the required order 21 | # and append everything that's missing in the order found 22 | required_order <- match(needed, documented) 23 | required_order <- required_order[!is.na(required_order)] 24 | required_order <- c(required_order, setdiff(documented_indexes, required_order)) 25 | 26 | # Overwrite all param fields to fix order 27 | param <- topic$get_field("param")$values[required_order] 28 | topic$add_simple_field("param", param, overwrite = TRUE) 29 | } 30 | 31 | invisible() 32 | } 33 | -------------------------------------------------------------------------------- /R/rd-template.R: -------------------------------------------------------------------------------- 1 | template_find <- function(base_path, template_name) { 2 | path <- file.path(base_path, "man-roxygen", paste0(template_name, ".", c("R", "r"))) 3 | path_exists <- file.exists(path) 4 | 5 | if (!any(path_exists)) { 6 | stop("Can not find template ", template_name, call. = FALSE) 7 | } 8 | 9 | path[path_exists][1] 10 | } 11 | 12 | template_eval <- function(template_path, vars) { 13 | utils::capture.output(brew::brew(template_path, envir = vars)) 14 | } 15 | 16 | process_templates <- function(block, base_path, global_options = list()) { 17 | template_locs <- names(block) == "template" 18 | template_tags <- block[template_locs] 19 | if (length(template_tags) == 0) return(block) 20 | 21 | templates <- unlist(template_tags, use.names = FALSE) 22 | paths <- vapply(templates, template_find, base_path = base_path, 23 | FUN.VALUE = character(1), USE.NAMES = FALSE) 24 | 25 | var_tags <- block[names(block) == "templateVar"] 26 | vars <- lapply(var_tags, "[[", "description") 27 | names(vars) <- vapply(var_tags, "[[", "name", FUN.VALUE = character(1)) 28 | vars <- lapply(vars, utils::type.convert, as.is = TRUE) 29 | 30 | results <- lapply(paths, template_eval, vars = list2env(vars)) 31 | 32 | # Insert templates back in the location where they came from 33 | block_pieces <- lapply(block, list) 34 | block_pieces[template_locs] <- lapply(results, parse_block, 35 | file = "TEMPLATE", registry = roclet_tags.roclet_rd(list()), offset = 0L, 36 | global_options = global_options) 37 | names(block_pieces)[template_locs] <- "" 38 | 39 | unlist(block_pieces, recursive = FALSE) 40 | } 41 | -------------------------------------------------------------------------------- /R/roclet.R: -------------------------------------------------------------------------------- 1 | #' Build a new roclet. 2 | #' 3 | #' To create a new roclet, you will need to create a constructor function 4 | #' that wraps `roclet`, and then implement methods for 5 | #' `roclet_tags`, `roclet_process`, `roclet_output`, and `roclet_clean`. 6 | #' 7 | #' @keywords internal 8 | #' @name roclet 9 | NULL 10 | 11 | #' @export 12 | #' @rdname roclet 13 | roclet <- function(subclass, ...) { 14 | structure(list(...), class = c(paste0("roclet_", subclass), "roclet")) 15 | } 16 | 17 | #' @export 18 | #' @rdname roclet 19 | roclet_output <- function(x, results, base_path, ...) { 20 | UseMethod("roclet_output", x) 21 | } 22 | 23 | #' @export 24 | #' @rdname roclet 25 | roclet_tags <- function(x) { 26 | UseMethod("roclet_tags") 27 | } 28 | 29 | #' @export 30 | #' @rdname roclet 31 | roclet_process <- function(x, parsed, base_path, global_options = list()) { 32 | UseMethod("roclet_process") 33 | } 34 | 35 | #' @export 36 | #' @rdname roclet 37 | roclet_clean <- function(x, base_path) { 38 | UseMethod("roclet_clean") 39 | } 40 | 41 | #' Create a roclet from a string. 42 | #' 43 | #' This provides a flexible way of specifying a roclet in a string. 44 | #' 45 | #' @param x Arbitrary R code evaluated in roxygen2 package. 46 | #' @export 47 | #' @examples 48 | #' # rd, namespace, and vignette work for backward compatibility 49 | #' roclet_find("rd") 50 | #' 51 | #' # But generally you should specify the name of a function that 52 | #' # returns a roclet 53 | #' roclet_find("rd_roclet") 54 | #' 55 | #' # If it lives in another package, you'll need to use :: 56 | #' roclet_find("roxygen2::rd_roclet") 57 | #' 58 | #' # If it takes parameters (which no roclet does currently), you'll need 59 | #' # to call the function 60 | #' roclet_find("roxygen2::rd_roclet()") 61 | roclet_find <- function(x) { 62 | env <- new.env(parent = getNamespace("roxygen2")) 63 | env$rd <- rd_roclet 64 | env$namespace <- namespace_roclet 65 | env$vignette <- vignette_roclet 66 | 67 | expr <- parse(text = x) 68 | res <- eval(expr, env) 69 | 70 | if (is.function(res)) { 71 | res <- res() 72 | } 73 | 74 | if (!is.roclet(res)) { 75 | stop("Must return a roclet", call. = FALSE) 76 | } 77 | 78 | res 79 | } 80 | 81 | is.roclet <- function(x) inherits(x, "roclet") 82 | 83 | #' Process roclet on string and capture results. 84 | #' 85 | #' Useful for testing. 86 | #' 87 | #' @param roclet Name of roclet to use for processing. 88 | #' @param input Source string 89 | #' @param registry Named list of tag parsers 90 | #' @param global_options List of global options 91 | #' @export 92 | #' @keywords internal 93 | roc_proc_text <- function(roclet, input, registry = default_tags(), 94 | global_options = list()) { 95 | stopifnot(is.roclet(roclet)) 96 | 97 | parsed <- parse_text(input, registry = registry, global_options) 98 | roclet_process(roclet, parsed, base_path = ".", global_options) 99 | } 100 | 101 | default_tags <- function() { 102 | c( 103 | roclet_tags.roclet_namespace(list()), 104 | roclet_tags.roclet_rd(list()) 105 | ) 106 | } 107 | -------------------------------------------------------------------------------- /R/roxygen.R: -------------------------------------------------------------------------------- 1 | #' @details 2 | #' See `vignette("roxygen2", package = "roxygen2")` for an overview 3 | #' of the package, `vignette("rd", package = "roxygen2")` for generating 4 | #' documentation, and `vignette("namespace", package = "roxygen2")` for 5 | #' generating the namespace specification. 6 | #' 7 | #' If you have existing Rd files, check out the `Rd2roxygen` package 8 | #' for a convenient way of converting Rd files to roxygen comments. 9 | #' 10 | #' @useDynLib roxygen2 11 | #' @importFrom Rcpp sourceCpp 12 | #' @importFrom R6 R6Class 13 | "_PACKAGE" 14 | 15 | -------------------------------------------------------------------------------- /R/roxygenize.R: -------------------------------------------------------------------------------- 1 | #' Process a package with the Rd, namespace and collate roclets. 2 | #' 3 | #' This is the workhorse function that uses roclets, the built-in document 4 | #' tranformation functions, to build all documentation for a package. See 5 | #' the documentation for the individual roclets, [rd_roclet()], 6 | #' [namespace_roclet()], and for [update_collate()], 7 | #' for more details. 8 | #' 9 | #' Note that roxygen2 is a dynamic documentation system: it works using 10 | #' by inspecting loaded objects in the package. This means that you must 11 | #' be able to load the package in order to document it. 12 | #' [source_package()] provides a simple simulation of package 13 | #' loading that works if you only have R files in your package. For more 14 | #' complicated packages, I recommend using `devtools::document` which 15 | #' does a much better job at simulating package install and load. 16 | #' 17 | #' @param package.dir Location of package top level directory. Default is 18 | #' working directory. 19 | #' @param roclets Character vector of roclet names to use with package. 20 | #' This defaults to `NULL`, which will use the `roclets` fields in 21 | #' the list provided in the `Roxygen` DESCRIPTION field. If none are 22 | #' specified, defaults to `c("collate", "namespace", "rd")`. 23 | #' @param load_code A function used to load all the R code in the package 24 | #' directory. It is called with the path to the package, and it should return 25 | #' an environment containing all the sourced code. 26 | #' @param clean If `TRUE`, roxygen will delete all files previously 27 | #' created by roxygen before running each roclet. 28 | #' @return `NULL` 29 | #' @export 30 | #' @importFrom stats setNames 31 | roxygenize <- function(package.dir = ".", 32 | roclets = NULL, 33 | load_code = source_package, 34 | clean = FALSE) { 35 | 36 | is_first <- first_time(package.dir) 37 | if (is_first) { 38 | message("First time using roxygen2. Upgrading automatically...") 39 | } 40 | 41 | base_path <- normalizePath(package.dir) 42 | man_path <- file.path(base_path, "man") 43 | dir.create(man_path, recursive = TRUE, showWarnings = FALSE) 44 | update_roxygen_version(base_path) 45 | 46 | options <- load_options(base_path) 47 | roclets <- roclets %||% options$roclets 48 | 49 | # Special case collate: it doesn't need to execute code, and must be run 50 | # first to ensure that code can be executed 51 | if ("collate" %in% roclets) { 52 | update_collate(base_path) 53 | roclets <- setdiff(roclets, "collate") 54 | } 55 | 56 | if (length(roclets) == 0) 57 | return(invisible()) 58 | 59 | roclets <- lapply(roclets, roclet_find) 60 | 61 | # Generate registry of all roclet tags 62 | tags <- c(lapply(roclets, roclet_tags), list(list(include = tag_value))) 63 | registry <- unlist(tags, recursive = FALSE) 64 | 65 | parsed <- parse_package(base_path, load_code, registry, options) 66 | 67 | roc_out <- function(roc) { 68 | if (clean) { 69 | roclet_clean(roc, base_path) 70 | } 71 | results <- roclet_process(roc, parsed, base_path) 72 | roclet_output(roc, results, base_path, is_first = is_first) 73 | } 74 | invisible(unlist(lapply(roclets, roc_out))) 75 | } 76 | 77 | #' @rdname roxygenize 78 | #' @export 79 | roxygenise <- roxygenize 80 | 81 | #' Load options from DESCRIPTION. 82 | #' 83 | #' @param base_path Path to package. 84 | #' @export 85 | #' @keywords internal 86 | load_options <- function(base_path = ".") { 87 | desc_path <- file.path(base_path, "DESCRIPTION") 88 | desc_opts <- read.dcf(desc_path, fields = "Roxygen")[[1, 1]] 89 | 90 | if (is.na(desc_opts)) { 91 | opts <- list() 92 | } else { 93 | opts <- eval(parse(text = desc_opts)) 94 | } 95 | 96 | defaults <- list( 97 | wrap = FALSE, 98 | roclets = c("collate", "namespace", "rd"), 99 | markdown = markdown_global_default 100 | ) 101 | 102 | unknown_opts <- setdiff(names(opts), names(defaults)) 103 | if (length(unknown_opts) > 0) { 104 | warning("Unknown Roxygen options ", paste(unknown_opts, collapse = ", "), 105 | ".\nSupported options: ", paste(names(defaults), collapse = ", ")) 106 | } 107 | 108 | utils::modifyList(defaults, opts) 109 | } 110 | -------------------------------------------------------------------------------- /R/safety.R: -------------------------------------------------------------------------------- 1 | first_time <- function(path) { 2 | generated <- dir(file.path(path, "man"), full.names = TRUE) 3 | generated <- generated[!file.info(generated)$isdir] 4 | 5 | namespace <- file.path(path, "NAMESPACE") 6 | if (file.exists(namespace)) { 7 | generated <- c(generated, namespace) 8 | } 9 | 10 | roxy <- vapply(generated, made_by_roxygen, logical(1)) 11 | all(!roxy) 12 | } 13 | 14 | made_by_roxygen <- function(path) { 15 | if (!file.exists(path)) return(TRUE) 16 | 17 | first <- readLines(path, n = 1) 18 | check_made_by(first) 19 | } 20 | 21 | add_made_by_roxygen <- function(path, comment) { 22 | if (!file.exists(path)) stop("Can't find ", path, call. = FALSE) 23 | 24 | lines <- readLines(path, warn = FALSE) 25 | if (check_made_by(lines[1])) return() 26 | 27 | writeLines(c(made_by(comment), lines), path) 28 | } 29 | 30 | check_made_by <- function(first) { 31 | if (length(first) == 0L) return(FALSE) 32 | grepl("^. Generated by roxygen2", first) 33 | } 34 | 35 | made_by <- function(comment) { 36 | paste0(comment, " Generated by roxygen2: do not edit by hand\n") 37 | } 38 | 39 | update_roxygen_version <- function(base_path) { 40 | desc_path <- file.path(base_path, "DESCRIPTION") 41 | 42 | cur <- as.character(utils::packageVersion("roxygen2")) 43 | prev <- desc::desc_get("RoxygenNote", file = desc_path)[[1]] 44 | 45 | if (!is.na(cur) && !is.na(prev) && package_version(cur) < package_version(prev)) { 46 | warning("Version of roxygen2 last used with this package is ", prev, ". ", 47 | " You only have version ", cur, call. = FALSE) 48 | } else if (!identical(cur, prev)) { 49 | message("Updating roxygen version in ", desc_path) 50 | desc::desc_set(RoxygenNote = cur, file = desc_path) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /R/select-args.R: -------------------------------------------------------------------------------- 1 | select_args_text <- function(fun, select = "") { 2 | pieces <- strsplit(select, " +")[[1]] 3 | 4 | tryCatch( 5 | { 6 | parsed <- lapply(pieces, function(x) parse(text = x)[[1]]) 7 | }, 8 | error = function(e) { 9 | stop("Failed to parse: '", select, "'", call. = FALSE) 10 | } 11 | ) 12 | 13 | select_args(fun, parsed) 14 | } 15 | 16 | # Figure out which arguments that the user wants given a function and 17 | # unevaluated list 18 | select_args <- function(fun, select = list()) { 19 | stopifnot(is.function(fun)) 20 | stopifnot(is.list(select)) 21 | 22 | args <- names(formals(fun)) 23 | args <- args[args != "..."] 24 | 25 | if (length(select) == 0) { 26 | return(args) 27 | } 28 | 29 | # Construct environment that allow minimal select-style semantics 30 | arg_idx <- as.list(setNames(seq_along(args), args)) 31 | arg_env <- list2env(arg_idx, parent = emptyenv()) 32 | arg_env$`:` <- `:` 33 | arg_env$`-` <- `-` 34 | arg_env$`(` <- `(` 35 | 36 | indices <- lapply(select, eval, envir = arg_env) 37 | for (i in seq_along(select)) { 38 | select_check(indices[[i]], select[[i]]) 39 | } 40 | 41 | # If first is negative, start with all vars 42 | # If first is positive, start with no vars 43 | select <- rep(select_sign(indices[[1]]) < 0, length(args)) 44 | 45 | for (idx in indices) { 46 | select[abs(idx)] <- select_sign(idx) > 0 47 | } 48 | 49 | args[select] 50 | } 51 | 52 | select_check <- function(x, call) { 53 | if (is.numeric(x) && (all(x > 0) || all(x < 0))) 54 | return() 55 | 56 | stop( 57 | "Arguments must evaluate to all positive or negative numbers.\n", 58 | "Problem: ", paste(deparse(call), collapse = ""), 59 | call. = FALSE 60 | ) 61 | } 62 | 63 | select_sign <- function(x) { 64 | if (all(x > 0)) { 65 | 1 66 | } else if (all(x < 0)) { 67 | -1 68 | } else { 69 | NA 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /R/source.R: -------------------------------------------------------------------------------- 1 | #' Source all files in a package. 2 | #' 3 | #' This is a simple attempt to load code in a package used by 4 | #' [roxygenize]. It will work with simple packages, but fail if 5 | #' there are compiled files, data files, etc. In that case, it's better to 6 | #' use [devtools::document]. 7 | #' 8 | #' @param path Path to a package. 9 | #' @return An environment, into which all R files in the directory were 10 | #' sourced. 11 | #' @keywords internal 12 | source_package <- function(path) { 13 | r_path <- file.path(path, "R") 14 | if (!file.exists(r_path)) stop("Can't find R/ directory", call. = FALSE) 15 | 16 | old_dir <- setwd(r_path) 17 | on.exit(setwd(old_dir)) 18 | 19 | env <- new.env(parent = globalenv()) 20 | methods::setPackageName("roxygen_devtest", env) 21 | 22 | load_pkg_dependencies(path) 23 | 24 | desc <- read_pkg_description(path) 25 | paths <- package_files(path) 26 | lapply(paths, sys_source, envir = env, fileEncoding = desc$Encoding %||% "UTF-8") 27 | 28 | env 29 | } 30 | 31 | sys_source <- function(file, envir = baseenv(), fileEncoding = "UTF-8") { 32 | exprs <- parse(text = read_lines_enc(file, file_encoding = fileEncoding)) 33 | for (expr in exprs) { 34 | eval(expr, envir = envir) 35 | } 36 | invisible() 37 | } 38 | 39 | # Assume that the package has already been loaded by other means 40 | # (e.g. build and reload) 41 | loaded_package <- function(path) { 42 | desc <- file.path(path, "DESCRIPTION") 43 | stopifnot(file.exists(desc)) 44 | 45 | package <- read.dcf(desc, fields = "Package")[[1, 1]] 46 | asNamespace(package) 47 | } 48 | 49 | 50 | 51 | load_pkg_dependencies <- function(path) { 52 | desc <- read_pkg_description(path) 53 | 54 | pkgs <- paste(c(desc$Depends, desc$Imports), collapse = ", ") 55 | if (pkgs == "") return() 56 | 57 | pkgs <- str_replace_all(pkgs, "\\(.*?\\)", "") 58 | pkgs <- str_split(pkgs, ",")[[1]] 59 | pkgs <- str_trim(pkgs) 60 | lapply(pkgs[pkgs != "R"], require, character.only = TRUE) 61 | } 62 | 63 | package_files <- function(path) { 64 | desc <- read_pkg_description(path) 65 | 66 | all <- normalizePath(r_files(path)) 67 | 68 | collate <- scan(text = desc$Collate %||% "", what = "", sep = " ", 69 | quiet = TRUE) 70 | 71 | collate <- normalizePath(file.path(path, 'R', collate)) 72 | 73 | rfiles <- c(collate, setdiff(all, collate)) 74 | ignore_files(rfiles, path) 75 | } 76 | 77 | read_pkg_description <- function(path) { 78 | desc_path <- file.path(path, "DESCRIPTION") 79 | if (!file.exists(desc_path)) stop("Can't find DESCRIPTION") 80 | 81 | read.description(desc_path) 82 | } 83 | -------------------------------------------------------------------------------- /R/topic.R: -------------------------------------------------------------------------------- 1 | # An RoxyTopic is an ordered collection of unique roxy_fields 2 | RoxyTopic <- R6::R6Class("RoxyTopic", public = list( 3 | fields = list(), 4 | filename = "", 5 | 6 | format = function(...) { 7 | # This has to happen here to get a better order when combining topics 8 | order <- c("backref", "docType", "encoding", "name", "alias", "title", 9 | "format", "source", "usage", "param", "value", "description", 10 | "details", "minidesc", "field", "slot", "rcmethods", "note", 11 | "section", "examples", "references", "seealso", "author", 12 | "concept", "keyword", "rawRd") 13 | fields <- move_names_to_front(self$fields, order) 14 | 15 | formatted <- lapply(fields, format, ...) 16 | paste0( 17 | made_by("%"), 18 | paste0(unlist(formatted), collapse = "\n") 19 | ) 20 | }, 21 | 22 | is_valid = function() { 23 | # Needs both title and name fields to generate valid Rd 24 | all(self$has_field(c("title", "name"))) 25 | }, 26 | 27 | has_field = function(field_name) { 28 | field_name %in% names(self$fields) 29 | }, 30 | 31 | get_field = function(field_name) { 32 | self$fields[[field_name]] 33 | }, 34 | 35 | inherits_from = function(type) { 36 | if (!self$has_field("inherit")) { 37 | return(character()) 38 | } 39 | 40 | inherit <- self$get_field("inherit") 41 | 42 | inherits_field <- vapply(inherit$fields, function(x) type %in% x, logical(1)) 43 | sources <- inherit$source[inherits_field] 44 | 45 | if ("NULL" %in% sources) 46 | return(character()) 47 | 48 | sources 49 | }, 50 | 51 | inherits_section_from = function() { 52 | if (!self$has_field("inherit_section")) { 53 | return(character()) 54 | } 55 | 56 | self$get_field("inherit_section")$source 57 | }, 58 | 59 | # Ensures that each type of name (as given by its name), only appears 60 | # once in self$fields 61 | add_field = function(field, overwrite = FALSE) { 62 | if (is.null(field)) 63 | return() 64 | 65 | stopifnot(is_roxy_field(field)) 66 | field_name <- field$field 67 | if (self$has_field(field_name) && !overwrite) { 68 | field <- merge(self$get_field(field_name), field) 69 | } 70 | 71 | self$fields[[field_name]] <- field 72 | 73 | invisible() 74 | }, 75 | 76 | add_simple_field = function(name, values, overwrite = FALSE) { 77 | self$add_field(roxy_field_simple(name, values), overwrite = overwrite) 78 | invisible() 79 | }, 80 | 81 | add = function(x, overwrite = FALSE) { 82 | if (inherits(x, "RoxyTopic")) { 83 | self$add(x$fields, overwrite = overwrite) 84 | } else if (inherits(x, "roxy_field")) { 85 | self$add_field(x, overwrite = overwrite) 86 | } else if (is.list(x)) { 87 | for (field in x) { 88 | self$add_field(field, overwrite = overwrite) 89 | } 90 | } else if (is.null(x)) { 91 | # skip 92 | } else { 93 | stop("Don't know how to add object of type ", class(x)[1]) 94 | } 95 | invisible() 96 | } 97 | 98 | 99 | )) 100 | 101 | move_names_to_front <- function(x, to_front) { 102 | nms <- names(x) 103 | x[union(intersect(to_front, nms), nms)] 104 | } 105 | 106 | get_tag <- function(topic, field_name) topic$get_field(field_name) 107 | -------------------------------------------------------------------------------- /R/topics.R: -------------------------------------------------------------------------------- 1 | # Manage a list of topics, indexed by file name. 2 | # Adding a topic with an existing file name merges it with the existing topic 3 | RoxyTopics <- R6::R6Class("RoxyTopics", public = list( 4 | topics = list(), 5 | 6 | add = function(topic) { 7 | if (is.null(topic)) 8 | return() 9 | stopifnot(inherits(topic, "RoxyTopic")) 10 | 11 | filename <- topic$filename 12 | if (filename %in% names(self$topics)) { 13 | self$topics[[filename]]$add(topic) 14 | } else { 15 | self$topics[[filename]] <- topic 16 | } 17 | 18 | invisible() 19 | }, 20 | 21 | # Drop any topics that don't have a title 22 | drop_invalid = function() { 23 | for (topic in names(self$topics)) { 24 | if (!self$topics[[topic]]$is_valid()) { 25 | warning(topic, " is missing name/title. Skipping", call. = FALSE) 26 | self$topics[[topic]] <- NULL 27 | } 28 | } 29 | 30 | invisible() 31 | }, 32 | 33 | get = function(filename) { 34 | self$topics[[filename]] 35 | }, 36 | 37 | # Given a topic name, find its file name. 38 | find_filename = function(name) { 39 | for (i in seq_along(self$topics)) { 40 | if (name %in% self$topics[[i]]$get_field("name")$values) { 41 | return(names(self$topics)[[i]]) 42 | } 43 | } 44 | NA_character_ 45 | }, 46 | 47 | # Topologically sort the topics. 48 | # 49 | # @param deps A function. Is passed RoxyTopic, and should return a character 50 | # vector of topic names 51 | topo_order = function(dependencies) { 52 | topo <- TopoSort$new() 53 | 54 | for (i in seq_along(self$topics)) { 55 | name <- names(self$topics)[[i]] 56 | topo$add(name) 57 | 58 | dep_topics <- dependencies(self$topics[[i]]) 59 | for (dep_topic in dep_topics) { 60 | dep_rd <- self$find_filename(dep_topic) 61 | if (!is.na(dep_rd)) 62 | topo$add_ancestor(name, dep_rd) 63 | } 64 | } 65 | 66 | topo$sort() 67 | }, 68 | 69 | # Call fun in topological order defined by dep. 70 | topo_apply = function(dep, fun, ...) { 71 | topics_topo <- self$topo_order(dep) 72 | for (topic_name in topics_topo) { 73 | topic <- self$get(topic_name) 74 | fun(topic, self, ...) 75 | } 76 | 77 | invisible() 78 | }, 79 | 80 | apply = function(fun, ...) { 81 | for (topic in self$topics) { 82 | fun(topic, self, ...) 83 | } 84 | invisible() 85 | }, 86 | 87 | # Extract values for simple fields 88 | simple_values = function(field) { 89 | fields <- lapply(self$topics, function(rd) rd$get_field(field)) 90 | lapply(compact(fields), "[[", "values") 91 | } 92 | 93 | )) 94 | -------------------------------------------------------------------------------- /R/topo-sort.R: -------------------------------------------------------------------------------- 1 | TopoSort <- R6::R6Class("TopoSort", public = list( 2 | vertices = list(), 3 | 4 | add = function(name) { 5 | if (is.null(self$vertices[[name]])) { 6 | self$vertices[[name]] <- Vertex$new(name) 7 | } 8 | invisible(self$vertices[[name]]) 9 | }, 10 | 11 | add_ancestor = function(predecessor_name, ancestor_name) { 12 | predecessor <- self$add(predecessor_name) 13 | ancestor <- self$add(ancestor_name) 14 | 15 | predecessor$add_ancestor(ancestor) 16 | }, 17 | 18 | sort = function() { 19 | sorted <- list() 20 | 21 | visit <- function(predecessor) { 22 | predecessor$discovered <- TRUE 23 | for (ancestor in predecessor$ancestors) { 24 | if (!ancestor$discovered) { 25 | visit(ancestor) 26 | } 27 | } 28 | sorted <<- append(sorted, predecessor) 29 | } 30 | 31 | for (vertex in self$vertices) { 32 | if (!vertex$discovered) { 33 | visit(vertex) 34 | } 35 | } 36 | vapply(sorted, function(x) x$name, character(1)) 37 | } 38 | )) 39 | 40 | Vertex <- R6::R6Class("Vertex", public = list( 41 | name = NA_character_, 42 | discovered = FALSE, 43 | ancestors = list(), 44 | 45 | initialize = function(name) { 46 | self$name <- name 47 | }, 48 | 49 | has_ancestor = function(ancestor) { 50 | for (vertex in self$ancestors) { 51 | if (identical(ancestor, vertex)) { 52 | return(TRUE) 53 | } 54 | } 55 | FALSE 56 | }, 57 | 58 | add_ancestor = function(ancestor) { 59 | if (!self$has_ancestor(ancestor)) { 60 | self$ancestors <- append(ancestor, self$ancestors) 61 | } 62 | } 63 | 64 | )) 65 | -------------------------------------------------------------------------------- /R/util-locale.R: -------------------------------------------------------------------------------- 1 | set_collate <- function(locale) { 2 | cur <- Sys.getlocale(category = "LC_COLLATE") 3 | Sys.setlocale(category = "LC_COLLATE", locale = locale) 4 | cur 5 | } 6 | 7 | with_collate <- function(locale, code) { 8 | old <- set_collate(locale) 9 | on.exit(set_collate(old)) 10 | 11 | force(code) 12 | } 13 | 14 | sort_c <- function(x) with_collate("C", sort(x)) 15 | -------------------------------------------------------------------------------- /R/utils-rd.R: -------------------------------------------------------------------------------- 1 | # Output ------------------------------------------------------------------ 2 | 3 | # A simple object to represent rd escaped text. 4 | rd <- function(x) { 5 | structure(x, class = "rd") 6 | } 7 | 8 | #' @export 9 | c.rd <- function(...) { 10 | rd(NextMethod()) 11 | } 12 | 13 | #' @export 14 | print.rd <- function(x, ...) { 15 | out <- paste0(" ", x, collapse = "\n") 16 | cat(out) 17 | } 18 | 19 | escape <- function(x) UseMethod("escape") 20 | escape.rd <- function(x) x 21 | escape.character <- function(x) { 22 | # wrap_string uses \u{A0}, the unicode non-breaking space, which 23 | # is not necessarily valid in windows locales. useBytes is a quick 24 | # hack to fix the problem. 25 | x1 <- gsub("\\", "\\\\", x, fixed = TRUE, useBytes = TRUE) 26 | x2 <- gsub("%", "\\%", x1, fixed = TRUE, useBytes = TRUE) 27 | 28 | rd(x2) 29 | } 30 | 31 | # Works like escape, but unescapes special rd example commands 32 | escape_examples <- function(x) { 33 | gsub("\\\\dont", "\\dont", escape(x)) 34 | } 35 | 36 | # Works like paste, but automatically escapes all input variables, 37 | # but not literal strings 38 | build_rd <- function(..., collapse = NULL, sep = "") { 39 | args <- dots(...) 40 | env <- parent.frame() 41 | 42 | escaped <- lapply(args, function(arg) { 43 | if (is.character(arg)) return(arg) 44 | 45 | escape(eval(arg, env)) 46 | }) 47 | 48 | string <- do.call("paste", c(escaped, list(collapse = collapse, sep = sep))) 49 | rd(string) 50 | } 51 | 52 | dots <- function(...) { 53 | eval(substitute(alist(...))) 54 | } 55 | 56 | # Translate a field and values into an Rd macro. 57 | # Multiple values get their own braces. 58 | rd_macro <- function(field, ..., space = FALSE) { 59 | if (space) { 60 | values <- paste0("\n", paste0(..., collapse = "\n"), "\n") 61 | } else { 62 | values <- str_trim(c(...)) 63 | } 64 | 65 | paste0("\\", field, paste0("{", values, "}", collapse = "")) 66 | } 67 | 68 | 69 | # Input ------------------------------------------------------------------- 70 | 71 | get_rd <- function(topic, package = NULL) { 72 | help_call <- substitute(help(t, p), list(t = topic, p = package)) 73 | top <- eval(help_call) 74 | if (length(top) == 0) return(NULL) 75 | 76 | internal_f("utils", ".getHelpFile")(top) 77 | } 78 | 79 | get_tags <- function(rd, tag) { 80 | Filter(function(x) identical(attr(x, "Rd_tag"), tag), rd) 81 | } 82 | 83 | rd2text <- function(x) { 84 | chr <- as.character(structure(x, class = "Rd")) 85 | str <- paste(chr, collapse = "") 86 | 87 | # re-escape comments 88 | gsub("%", "\\%", str, fixed = TRUE) 89 | } 90 | 91 | -------------------------------------------------------------------------------- /R/vignette.R: -------------------------------------------------------------------------------- 1 | #' Re-build outdated vignettes. 2 | #' 3 | #' This rebuilds outdated vignettes with [tools::buildVignette]. 4 | #' By default, it will rebuild all vignettes if the source file is newer than 5 | #' the output pdf or html. (This means it will automatically re-build the 6 | #' vignette if you change the vignette source, but _not_ when you 7 | #' change the R code). If you want finer control, add a Makefile to 8 | #' `vignettes/` and roxygen2 will use that instead. 9 | #' 10 | #' To prevent RStudio from re-building the vignettes again when checking 11 | #' your package, add `--no-build-vignettes` to the "Build Source Package" 12 | #' field in your project options. 13 | #' 14 | #' @family roclets 15 | #' @export 16 | vignette_roclet <- function() { 17 | roclet("vignette") 18 | } 19 | 20 | #' @export 21 | roclet_process.roclet_vignette <- function(x, parsed, base_path, 22 | global_options = list()) { 23 | } 24 | 25 | #' @export 26 | roclet_tags.roclet_vignette <- function(x) { 27 | list() 28 | } 29 | 30 | #' @export 31 | roclet_output.roclet_vignette <- function(x, results, base_path, ...) { 32 | vign_update_all(base_path) 33 | } 34 | 35 | # Determine if a vignette is out-of-date; i.e. it has no related files, or 36 | # any of the related files are older than the vignette. 37 | vign_outdated <- function(vign) { 38 | vign <- normalizePath(vign, mustWork = TRUE) 39 | name <- tools::file_path_sans_ext(basename(vign)) 40 | 41 | # Currently, the final product of a vignette can only be pdf or html 42 | related <- dir(dirname(vign), pattern = paste0(name, "\\.(pdf|html)$"), 43 | full.names = TRUE) 44 | related <- setdiff(related, vign) 45 | 46 | length(related) == 0 || mtime(vign) > mtime(related) 47 | } 48 | 49 | vign_update <- function(vign) { 50 | if (!vign_outdated(vign)) return(FALSE) 51 | 52 | message("Rebuilding ", basename(vign)) 53 | output <- tools::buildVignette(vign, dirname(vign), tangle = FALSE, 54 | clean = FALSE) 55 | 56 | TRUE 57 | } 58 | 59 | vign_update_all <- function(pkg_path) { 60 | vig_path <- file.path(pkg_path, "vignettes") 61 | if (!file.exists(vig_path)) return() 62 | 63 | if (file.exists(file.path(vig_path, "Makefile"))) { 64 | message("Updating vignettes with make") 65 | 66 | make <- Sys.getenv("MAKE", "make") 67 | old <- setwd(vig_path) 68 | on.exit(setwd(old), add = TRUE) 69 | 70 | system(make) 71 | } else { 72 | message("Updating vignettes") 73 | 74 | vigs <- tools::pkgVignettes(dir = pkg_path) 75 | invisible(vapply(vigs$docs, vign_update, logical(1))) 76 | } 77 | } 78 | 79 | mtime <- function(x) { 80 | max(file.info(x)$mtime) 81 | } 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # roxygen2 2 | 3 | [![Build Status](https://travis-ci.org/klutometis/roxygen.png)](https://travis-ci.org/klutometis/roxygen) 4 | [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/klutometis/roxygen?branch=master&svg=true)](https://ci.appveyor.com/project/klutometis/roxygen) 5 | [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/roxygen2)](https://cran.r-project.org/package=roxygen2) 6 | [![Coverage Status](https://img.shields.io/codecov/c/github/klutometis/roxygen/master.svg)](https://codecov.io/github/klutometis/roxygen?branch=master) 7 | 8 | > all' hileth', Hephaiste; didou d'areten te kai olbon.* 9 | > --Homer, 7th century BCE 10 | 11 | # Why use roxygen2? 12 | 13 | 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 from the `stringr` package: 14 | 15 | ```R 16 | #' The length of a string (in characters). 17 | #' 18 | #' @param string input character vector 19 | #' @return numeric vector giving number of characters in each element of the 20 | #' character vector. Missing strings have missing length. 21 | #' @seealso \code{\link{nchar}} which this function wraps 22 | #' @export 23 | #' @examples 24 | #' str_length(letters) 25 | #' str_length(c("i", "like", "programming", NA)) 26 | str_length <- function(string) { 27 | string <- check_string(string) 28 | 29 | nc <- nchar(string, allowNA = TRUE) 30 | is.na(nc) <- is.na(string) 31 | nc 32 | } 33 | ``` 34 | 35 | When you `roxygenise()` (or `devtools::document()`) your package these comments will be automatically transformed to the Rd file you need to pass `R CMD check`: 36 | 37 | ``` 38 | \name{str_length} 39 | \alias{str_length} 40 | \title{The length of a string (in characters).} 41 | \usage{str_length(string)} 42 | \arguments{ 43 | \item{string}{input character vector} 44 | } 45 | \description{ 46 | The length of a string (in characters). 47 | } 48 | \seealso{\code{\link{nchar}} which this function wraps} 49 | \value{ 50 | numeric vector giving number of characters in each element of the 51 | character vector. Missings string have missing length. 52 | } 53 | \examples{ 54 | str_length(letters) 55 | str_length(c("i", "like", "programming", NA)) 56 | } 57 | ``` 58 | 59 | # Installation 60 | 61 | To get the current released version from CRAN: 62 | 63 | ```R 64 | install.packages("roxygen2") 65 | ``` 66 | 67 | To get the current development version from github: 68 | 69 | ```R 70 | # install.packages("devtools") 71 | devtools::install_github("klutometis/roxygen") 72 | ``` 73 | 74 | # Running 75 | 76 | Roxygen does a live analysis of your source code: it loads all the code in your package, so it can create documentation using values in an R environment, not just source code. However, simulating package loading is rather tricky to do in general, so there are two ways to do it with roxygen: 77 | 78 | * `roxygen2::roxygenise()` just sources all files in the `R/` directory 79 | 80 | * `devtools::document()` sources all files in the `R/` directory, compiles 81 | source code in the `src/` directory, loads data in the `data/` directory 82 | and generally does an accurate job of simulating package loading. 83 | 84 | If you have a simple package, you can use `roxygenise()`, but for anything more complicated, I recommend that you use `document()`. 85 | 86 | # Roclets 87 | 88 | `roxygen2` comes with four roclets, tools for parsing your source code and producing files useful for documenting your package: 89 | 90 | * `collate_roclet`: allows you to add `@include` directives to ensure that 91 | files are loaded in the order they are needed 92 | 93 | * `namespace_roclet`: creates your `NAMESPACE` automatically. 95% of the time 94 | all you need to do is label functions, methods and classes that you want to 95 | export with the `@export` tag 96 | 97 | * `rd_roclet`: produces Rd files by inspecting both function definitions and 98 | roxygen2 comments in the source code 99 | 100 | * `vignette_roclet`: builds vignettes using `tools::buildVignette()`. 101 | 102 | By default, `roxygenise` will run the first three, but you can choose which ones to run using the `roclet` parameter, or field `Roxygen` in your `DESCRIPTION`: 103 | 104 | ``` 105 | Roxygen: list(roclets = c("rd", "collate")) 106 | ``` 107 | 108 | ----------- 109 | * Hail, Hephaistos! Grant skill and weal. 110 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # DO NOT CHANGE the "init" and "install" sections below 2 | 3 | # Download script file from GitHub 4 | init: 5 | ps: | 6 | $ErrorActionPreference = "Stop" 7 | Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1" 8 | Import-Module '..\appveyor-tool.ps1' 9 | 10 | install: 11 | ps: Bootstrap 12 | 13 | cache: 14 | - C:\RLibrary 15 | 16 | # Adapt as necessary starting from here 17 | 18 | build_script: 19 | - travis-tool.sh install_deps 20 | 21 | test_script: 22 | - travis-tool.sh run_tests 23 | 24 | on_failure: 25 | - 7z a failure.zip *.Rcheck\* 26 | - appveyor PushArtifact failure.zip 27 | 28 | artifacts: 29 | - path: '*.Rcheck\**\*.log' 30 | name: Logs 31 | 32 | - path: '*.Rcheck\**\*.out' 33 | name: Logs 34 | 35 | - path: '*.Rcheck\**\*.fail' 36 | name: Logs 37 | 38 | - path: '*.Rcheck\**\*.Rout' 39 | name: Logs 40 | 41 | - path: '\*_*.tar.gz' 42 | name: Bits 43 | 44 | - path: '\*_*.zip' 45 | name: Bits 46 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | This is a patch release to fix a major bug that affects a small percentage of users 2 | 3 | --- 4 | 5 | ## Test environments 6 | * local OS X install, R 3.2.3 7 | * ubuntu 12.04 (on travis-ci), R 3.2.3 8 | * win-builder (devel and release) 9 | 10 | ## R CMD check results 11 | There were no ERRORs, WARNINGs or NOTEs. 12 | 13 | ## Downstream dependencies 14 | 15 | I have run R CMD check on all 7 reverse dependencies of roxygen2 16 | I did not check packages that only suggest roxygen2, as it's generally a 17 | build-time, rather a run-time dependency. 18 | 19 | Results summary at https://github.com/klutometis/roxygen/tree/master/revdep 20 | 21 | I failed to install redland, but otherwise there were no new problems. 22 | -------------------------------------------------------------------------------- /man-roxygen/template.R: -------------------------------------------------------------------------------- 1 | #' @section Template tags: 2 | #' 3 | #' Templates make it possible to substantially reduce documentation 4 | #' duplication. A template is an \file{R} file in the \code{man-roxygen/} 5 | #' directory. It is processed with \code{\link[brew]{brew}} and then inserted 6 | #' into the roxygen block. You can run any R code with brew; you can 7 | #' insert template variables with \code{<\%= varname \%>}. 8 | #' 9 | #' \describe{ 10 | #' 11 | #' \item{\code{@@template templateName}}{Insert named template in current 12 | #' location.} 13 | #' 14 | #' \item{\code{@@templateVar varname value}}{Set up variables for template 15 | #' use.} 16 | #' 17 | #' } 18 | #' 19 | #' Limitations: 20 | #' 21 | #' \itemize{ 22 | #' \item Templates are not parsed recursively, so you can not include templates 23 | #' from within other templates. 24 | #' 25 | #' \item Templates must be composed of complete tags - because all roxygen tags 26 | #' are current block tags, they can not be used for inline insertions. 27 | #' } 28 | -------------------------------------------------------------------------------- /man/double_escape_md.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/markdown-escaping.R 3 | \name{double_escape_md} 4 | \alias{double_escape_md} 5 | \title{Escape \% and \$ and \_ once more, because commonmark 6 | removes the escaping. We do this everywhere currently.} 7 | \usage{ 8 | double_escape_md(text) 9 | } 10 | \arguments{ 11 | \item{text}{Input text.} 12 | } 13 | \value{ 14 | Double-escaped text. 15 | } 16 | \description{ 17 | Escape \% and \$ and \_ once more, because commonmark 18 | removes the escaping. We do this everywhere currently. 19 | } 20 | -------------------------------------------------------------------------------- /man/is_s3_generic.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/object-s3.R 3 | \name{is_s3_generic} 4 | \alias{is_s3_generic} 5 | \alias{is_s3_method} 6 | \title{Determine if a function is an S3 generic or S3 method.} 7 | \usage{ 8 | is_s3_generic(name, env = parent.frame()) 9 | 10 | is_s3_method(name, env = parent.frame()) 11 | } 12 | \arguments{ 13 | \item{name}{Name of function.} 14 | 15 | \item{env}{Base environment in which to look for function defintion.} 16 | } 17 | \description{ 18 | \code{is_s3_generic} compares name to \code{.knownS3Generics} and 19 | \code{.S3PrimitiveGenerics}, then looks at the function body to see if it 20 | calls \code{\link[=UseMethod]{UseMethod()}}. 21 | 22 | \code{is_s3_method} builds names of all possible generics for that function 23 | and then checks if any of them actually is a generic. 24 | } 25 | -------------------------------------------------------------------------------- /man/load_options.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roxygenize.R 3 | \name{load_options} 4 | \alias{load_options} 5 | \title{Load options from DESCRIPTION.} 6 | \usage{ 7 | load_options(base_path = ".") 8 | } 9 | \arguments{ 10 | \item{base_path}{Path to package.} 11 | } 12 | \description{ 13 | Load options from DESCRIPTION. 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /man/markdown-internals.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/markdown-escaping.R 3 | \name{escape_rd_for_md} 4 | \alias{escape_rd_for_md} 5 | \alias{unescape_rd_for_md} 6 | \title{Escape Rd markup, to avoid interpreting it as markdown} 7 | \usage{ 8 | escape_rd_for_md(text) 9 | 10 | unescape_rd_for_md(rd_text, esc_text) 11 | } 12 | \arguments{ 13 | \item{text}{Input text. Potentially contains Rd and/or 14 | markdown markup.} 15 | 16 | \item{rd_text}{The markdown parsed and interpreted text.} 17 | 18 | \item{esc_text}{The original escaped text from 19 | \code{escape_rd_for_md()}.} 20 | } 21 | \value{ 22 | For \code{escape_rd_for_md}: 23 | A \dQuote{safe} version of the input text, where 24 | each fragile Rd tag is replaced by a placeholder. The 25 | original text is added as an attribute for each placeholder. 26 | 27 | For \code{unescape_rd_for_md}: Rd text. 28 | } 29 | \description{ 30 | This is needed, if we want to stay compatible with 31 | existing markup, even if markdown mode is switched on. 32 | Fragile Rd tags (tags that may contain markup that 33 | can be picked up by the markdown parser), are replaced 34 | by placeholders. After the markdown to Rd conversion 35 | is done, the original text is put back in place of the 36 | placeholders. 37 | 38 | It puts back the protected fragile Rd commands into 39 | the text after the markdown parsing. 40 | } 41 | \details{ 42 | The list of protected Rd tags is in \code{escaped_for_md}. 43 | 44 | Some Rd macros are treated specially: 45 | \itemize{ 46 | \item For \code{if}, markdown is only allowed in the second argument. 47 | \item For \code{ifelse} markdown is allowed in the second and third arguments. 48 | } 49 | 50 | See also \code{roclet-rd.R} for the list of tags that 51 | uses the markdown-enabled parser. Some tags, e.g. 52 | \code{@aliases}, \code{@backref}, etc. only use the 53 | standard Roxygen parser. 54 | } 55 | \keyword{internal} 56 | -------------------------------------------------------------------------------- /man/markdown-test.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/markdown.R 3 | \name{markdown-test} 4 | \alias{markdown-test} 5 | \title{Dummy page to test roxygen's markdown formatting} 6 | \description{ 7 | Links are very tricky, so I'll put in some links here: 8 | Link to a function: \code{\link[=roxygenize]{roxygenize()}}. 9 | Link to an object: \link{roxygenize} (we just treat it like an object here. 10 | } 11 | \details{ 12 | Link to another package, function: \code{\link[devtools:document]{devtools::document()}}. 13 | Link to another package, non-function: \link[devtools:document]{devtools::document}. 14 | 15 | Link with link text: \link[=roxygenize]{this great function} or 16 | \link[=roxygenize]{that great function}. 17 | 18 | In another package: \link[devtools:document]{and this one}. 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/namespace_roclet.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/namespace.R 3 | \name{namespace_roclet} 4 | \alias{namespace_roclet} 5 | \alias{export} 6 | \alias{exportClass} 7 | \alias{exportMethod} 8 | \alias{S3method} 9 | \alias{import} 10 | \alias{importFrom} 11 | \alias{importClassesFrom} 12 | \alias{importMethodsFrom} 13 | \alias{rawNamespace} 14 | \alias{useDynLib} 15 | \title{Roclet: make NAMESPACE.} 16 | \usage{ 17 | namespace_roclet() 18 | } 19 | \description{ 20 | This roclet automates the production of a \code{NAMESPACE} file, 21 | see Writing R Extensions. 22 | (\url{https://cran.r-project.org/doc/manuals/R-exts.pdf}) for details. 23 | } 24 | \seealso{ 25 | \code{vignette("namespace", package = "roxygen2")} 26 | 27 | Other roclets: \code{\link{rd_roclet}}, 28 | \code{\link{vignette_roclet}} 29 | } 30 | -------------------------------------------------------------------------------- /man/object.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/object.R 3 | \name{object} 4 | \alias{object} 5 | \title{Constructors for S3 object to represent R objects.} 6 | \usage{ 7 | object(value, alias = NULL, type = obj_type(value)) 8 | } 9 | \arguments{ 10 | \item{value}{The object itself.} 11 | 12 | \item{alias}{Alias for object being documented, in case you create a 13 | generator function with different name.} 14 | } 15 | \description{ 16 | These objects are usually created by the parsers, but it is also 17 | useful to generate them by hand for testing. 18 | } 19 | \keyword{internal} 20 | -------------------------------------------------------------------------------- /man/object_format.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/object-format.R 3 | \name{object_format} 4 | \alias{object_format} 5 | \title{Default format for data} 6 | \usage{ 7 | object_format(x) 8 | } 9 | \arguments{ 10 | \item{x}{A data object} 11 | } 12 | \value{ 13 | A \code{character} value with valid \code{Rd} syntax, or \code{NULL}. 14 | } 15 | \description{ 16 | This function is called to generate the default "Format" section for each 17 | data object. The default implementation will return the class and dimension 18 | information. 19 | } 20 | -------------------------------------------------------------------------------- /man/rd_roclet.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rd.R 3 | \name{rd_roclet} 4 | \alias{rd_roclet} 5 | \title{Roclet: make Rd files.} 6 | \usage{ 7 | rd_roclet() 8 | } 9 | \description{ 10 | This roclet is the workhorse of \pkg{roxygen}, producing the Rd files that 11 | document that functions in your package. 12 | } 13 | \seealso{ 14 | \code{vignette("rd", package = "roxygen2")} 15 | 16 | Other roclets: \code{\link{namespace_roclet}}, 17 | \code{\link{vignette_roclet}} 18 | } 19 | -------------------------------------------------------------------------------- /man/roc_proc_text.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{roc_proc_text} 4 | \alias{roc_proc_text} 5 | \title{Process roclet on string and capture results.} 6 | \usage{ 7 | roc_proc_text(roclet, input, registry = default_tags(), 8 | global_options = list()) 9 | } 10 | \arguments{ 11 | \item{roclet}{Name of roclet to use for processing.} 12 | 13 | \item{input}{Source string} 14 | 15 | \item{registry}{Named list of tag parsers} 16 | 17 | \item{global_options}{List of global options} 18 | } 19 | \description{ 20 | Useful for testing. 21 | } 22 | \keyword{internal} 23 | -------------------------------------------------------------------------------- /man/roclet.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{roclet} 4 | \alias{roclet} 5 | \alias{roclet} 6 | \alias{roclet_output} 7 | \alias{roclet_tags} 8 | \alias{roclet_process} 9 | \alias{roclet_clean} 10 | \title{Build a new roclet.} 11 | \usage{ 12 | roclet(subclass, ...) 13 | 14 | roclet_output(x, results, base_path, ...) 15 | 16 | roclet_tags(x) 17 | 18 | roclet_process(x, parsed, base_path, global_options = list()) 19 | 20 | roclet_clean(x, base_path) 21 | } 22 | \description{ 23 | To create a new roclet, you will need to create a constructor function 24 | that wraps \code{roclet}, and then implement methods for 25 | \code{roclet_tags}, \code{roclet_process}, \code{roclet_output}, and \code{roclet_clean}. 26 | } 27 | \keyword{internal} 28 | -------------------------------------------------------------------------------- /man/roclet_find.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roclet.R 3 | \name{roclet_find} 4 | \alias{roclet_find} 5 | \title{Create a roclet from a string.} 6 | \usage{ 7 | roclet_find(x) 8 | } 9 | \arguments{ 10 | \item{x}{Arbitrary R code evaluated in roxygen2 package.} 11 | } 12 | \description{ 13 | This provides a flexible way of specifying a roclet in a string. 14 | } 15 | \examples{ 16 | # rd, namespace, and vignette work for backward compatibility 17 | roclet_find("rd") 18 | 19 | # But generally you should specify the name of a function that 20 | # returns a roclet 21 | roclet_find("rd_roclet") 22 | 23 | # If it lives in another package, you'll need to use :: 24 | roclet_find("roxygen2::rd_roclet") 25 | 26 | # If it takes parameters (which no roclet does currently), you'll need 27 | # to call the function 28 | roclet_find("roxygen2::rd_roclet()") 29 | } 30 | -------------------------------------------------------------------------------- /man/roxy_tag.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tag.R 3 | \name{roxy_tag} 4 | \alias{roxy_tag} 5 | \alias{roxy_tag_warning} 6 | \alias{tag_value} 7 | \alias{tag_inherit} 8 | \alias{tag_name} 9 | \alias{tag_two_part} 10 | \alias{tag_name_description} 11 | \alias{tag_words} 12 | \alias{tag_words_line} 13 | \alias{tag_toggle} 14 | \alias{tag_code} 15 | \alias{tag_examples} 16 | \alias{tag_markdown} 17 | \alias{tag_markdown_restricted} 18 | \title{Parsing tags.} 19 | \usage{ 20 | roxy_tag(tag, val, file = "", line = 0) 21 | 22 | roxy_tag_warning(x, ...) 23 | 24 | tag_value(x) 25 | 26 | tag_inherit(x) 27 | 28 | tag_name(x) 29 | 30 | tag_two_part(first, second, required = TRUE) 31 | 32 | tag_name_description(x) 33 | 34 | tag_words(min = 0, max = Inf) 35 | 36 | tag_words_line(x) 37 | 38 | tag_toggle(x) 39 | 40 | tag_code(x) 41 | 42 | tag_examples(x) 43 | 44 | tag_markdown(x) 45 | 46 | tag_markdown_restricted(x) 47 | } 48 | \arguments{ 49 | \item{tag}{Tag name} 50 | 51 | \item{val}{Tag value. When read from the file, this will be a string, 52 | but after parsing can be a more complicated structure (typically 53 | a character vector, but sometimes a list).} 54 | 55 | \item{file, line}{Location of the tag} 56 | 57 | \item{first, second}{Name of first and second parts of two part tags} 58 | 59 | \item{required}{Is the second part required (TRUE) or can it be blank 60 | (FALSE)?} 61 | 62 | \item{min, max}{Minimum and maximum number of words} 63 | } 64 | \description{ 65 | \code{roxy_tag} constructs a tag object, and \code{roxy_tag_warning} makes 66 | an informative warning using the location information stored in the tag. 67 | The remainder of the tag functions parse the tag value, convert a string 68 | into a richer R object, or providing informative warnings and returning 69 | valid if the value is invalid. 70 | } 71 | \details{ 72 | Two exceptions to the rule are \code{tag_words} and \code{tag_two_part}, which are 73 | tag parsing generator functions. 74 | } 75 | \keyword{internal} 76 | -------------------------------------------------------------------------------- /man/roxygen2-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roxygen.R 3 | \docType{package} 4 | \name{roxygen2-package} 5 | \alias{roxygen2} 6 | \alias{roxygen2-package} 7 | \title{roxygen2: In-Line Documentation for R} 8 | \description{ 9 | Generate your Rd documentation, 'NAMESPACE' file, and collation 10 | field using specially formatted comments. Writing documentation in-line 11 | with code makes it easier to keep your documentation up-to-date as your 12 | requirements change. 'Roxygen2' is inspired by the 'Doxygen' system for C++. 13 | } 14 | \details{ 15 | See \code{vignette("roxygen2", package = "roxygen2")} for an overview 16 | of the package, \code{vignette("rd", package = "roxygen2")} for generating 17 | documentation, and \code{vignette("namespace", package = "roxygen2")} for 18 | generating the namespace specification. 19 | 20 | If you have existing Rd files, check out the \code{Rd2roxygen} package 21 | for a convenient way of converting Rd files to roxygen comments. 22 | } 23 | \seealso{ 24 | Useful links: 25 | \itemize{ 26 | \item \url{https://github.com/klutometis/roxygen} 27 | \item Report bugs at \url{https://github.com/klutometis/roxygen/issues} 28 | } 29 | 30 | } 31 | \author{ 32 | \strong{Maintainer}: Hadley Wickham \email{hadley@rstudio.com} [copyright holder] 33 | 34 | Authors: 35 | \itemize{ 36 | \item Peter Danenberg \email{pcd@roxygen.org} [copyright holder] 37 | \item Manuel Eugster [copyright holder] 38 | } 39 | 40 | Other contributors: 41 | \itemize{ 42 | \item RStudio [copyright holder] 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /man/roxygenize.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/roxygenize.R 3 | \name{roxygenize} 4 | \alias{roxygenize} 5 | \alias{roxygenise} 6 | \title{Process a package with the Rd, namespace and collate roclets.} 7 | \usage{ 8 | roxygenize(package.dir = ".", roclets = NULL, load_code = source_package, 9 | clean = FALSE) 10 | 11 | roxygenise(package.dir = ".", roclets = NULL, load_code = source_package, 12 | clean = FALSE) 13 | } 14 | \arguments{ 15 | \item{package.dir}{Location of package top level directory. Default is 16 | working directory.} 17 | 18 | \item{roclets}{Character vector of roclet names to use with package. 19 | This defaults to \code{NULL}, which will use the \code{roclets} fields in 20 | the list provided in the \code{Roxygen} DESCRIPTION field. If none are 21 | specified, defaults to \code{c("collate", "namespace", "rd")}.} 22 | 23 | \item{load_code}{A function used to load all the R code in the package 24 | directory. It is called with the path to the package, and it should return 25 | an environment containing all the sourced code.} 26 | 27 | \item{clean}{If \code{TRUE}, roxygen will delete all files previously 28 | created by roxygen before running each roclet.} 29 | } 30 | \value{ 31 | \code{NULL} 32 | } 33 | \description{ 34 | This is the workhorse function that uses roclets, the built-in document 35 | tranformation functions, to build all documentation for a package. See 36 | the documentation for the individual roclets, \code{\link[=rd_roclet]{rd_roclet()}}, 37 | \code{\link[=namespace_roclet]{namespace_roclet()}}, and for \code{\link[=update_collate]{update_collate()}}, 38 | for more details. 39 | } 40 | \details{ 41 | Note that roxygen2 is a dynamic documentation system: it works using 42 | by inspecting loaded objects in the package. This means that you must 43 | be able to load the package in order to document it. 44 | \code{\link[=source_package]{source_package()}} provides a simple simulation of package 45 | loading that works if you only have R files in your package. For more 46 | complicated packages, I recommend using \code{devtools::document} which 47 | does a much better job at simulating package install and load. 48 | } 49 | -------------------------------------------------------------------------------- /man/source_package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/source.R 3 | \name{source_package} 4 | \alias{source_package} 5 | \title{Source all files in a package.} 6 | \usage{ 7 | source_package(path) 8 | } 9 | \arguments{ 10 | \item{path}{Path to a package.} 11 | } 12 | \value{ 13 | An environment, into which all R files in the directory were 14 | sourced. 15 | } 16 | \description{ 17 | This is a simple attempt to load code in a package used by 18 | \link{roxygenize}. It will work with simple packages, but fail if 19 | there are compiled files, data files, etc. In that case, it's better to 20 | use \link[devtools:document]{devtools::document}. 21 | } 22 | \keyword{internal} 23 | -------------------------------------------------------------------------------- /man/update_collate.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/collate.R 3 | \name{update_collate} 4 | \alias{update_collate} 5 | \title{Update Collate field in DESCRIPTION.} 6 | \usage{ 7 | update_collate(base_path) 8 | } 9 | \arguments{ 10 | \item{base_path}{Path to package directory.} 11 | } 12 | \description{ 13 | Topologically sort R files and record in Collate field. The topological 14 | sort is based on the \code{@include} tag, which should specify the filenames 15 | (space separated) that should be loaded before the current file. These are 16 | typically necessary if you're using S4 or RC classes (because super classes 17 | must be defined before subclasses). 18 | } 19 | \details{ 20 | If there are no \code{@include} tags, roxygen2 will leave collate as is. 21 | This makes it easier to use roxygen2 with an existing collate directive, 22 | but if you remove all your \code{@include} tags, you'll need to also 23 | manually delete the collate field. 24 | 25 | This is not a roclet because roclets need the values of objects in a package, 26 | and those values can not be generated unless you've sourced the files, 27 | and you can't source the files unless you know the correct order. 28 | } 29 | \examples{ 30 | #' `example-a.R', `example-b.R' and `example-c.R' reside 31 | #' in the `example' directory, with dependencies 32 | #' a -> {b, c}. This is `example-a.R'. 33 | #' @include example-b.R 34 | #' @include example-c.R 35 | NULL 36 | 37 | \dontrun{ 38 | update_collate("my_package") 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /man/vignette_roclet.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/vignette.R 3 | \name{vignette_roclet} 4 | \alias{vignette_roclet} 5 | \title{Re-build outdated vignettes.} 6 | \usage{ 7 | vignette_roclet() 8 | } 9 | \description{ 10 | This rebuilds outdated vignettes with \link[tools:buildVignette]{tools::buildVignette}. 11 | By default, it will rebuild all vignettes if the source file is newer than 12 | the output pdf or html. (This means it will automatically re-build the 13 | vignette if you change the vignette source, but \emph{not} when you 14 | change the R code). If you want finer control, add a Makefile to 15 | \code{vignettes/} and roxygen2 will use that instead. 16 | } 17 | \details{ 18 | To prevent RStudio from re-building the vignettes again when checking 19 | your package, add \code{--no-build-vignettes} to the "Build Source Package" 20 | field in your project options. 21 | } 22 | \seealso{ 23 | Other roclets: \code{\link{namespace_roclet}}, 24 | \code{\link{rd_roclet}} 25 | } 26 | -------------------------------------------------------------------------------- /revdep/.gitignore: -------------------------------------------------------------------------------- 1 | **/ 2 | -------------------------------------------------------------------------------- /revdep/README.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | ## Platform 4 | 5 | |setting |value | 6 | |:--------|:----------------------------| 7 | |version |R version 3.3.2 (2016-10-31) | 8 | |system |x86_64, darwin13.4.0 | 9 | |ui |RStudio (1.0.136) | 10 | |language |(EN) | 11 | |collate |en_US.UTF-8 | 12 | |tz |America/Chicago | 13 | |date |2017-01-30 | 14 | 15 | ## Packages 16 | 17 | |package |* |version |date |source | 18 | |:----------|:--|:----------|:----------|:------------------------------| 19 | |brew | |1.0-6 |2011-04-13 |cran (@1.0-6) | 20 | |commonmark | |1.1 |2016-12-13 |CRAN (R 3.3.2) | 21 | |covr | |2.2.2 |2017-01-05 |cran (@2.2.2) | 22 | |desc | |1.1.0 |2017-01-27 |cran (@1.1.0) | 23 | |devtools |* |1.12.0 |2016-06-24 |cran (@1.12.0) | 24 | |digest | |0.6.12 |2017-01-27 |cran (@0.6.12) | 25 | |knitr | |1.15.8 |2017-01-30 |Github (yihui/knitr@b936c1e) | 26 | |R6 | |2.2.0 |2016-10-05 |cran (@2.2.0) | 27 | |Rcpp | |0.12.9.1 |2017-01-30 |Github (RcppCore/Rcpp@5a99a86) | 28 | |rmarkdown | |1.3 |2016-12-21 |cran (@1.3) | 29 | |roxygen2 | |5.0.1.9000 |2017-01-30 |local (klutometis/roxygen@NA) | 30 | |stringi | |1.1.2 |2016-10-01 |cran (@1.1.2) | 31 | |stringr | |1.1.0 |2016-08-19 |local (tidyverse/stringr@NA) | 32 | |testthat |* |1.0.2 |2016-04-23 |cran (@1.0.2) | 33 | |xml2 | |1.1.1 |2017-01-24 |cran (@1.1.1) | 34 | 35 | # Check results 36 | 7 packages 37 | 38 | ## aoos (0.4.0) 39 | Maintainer: Sebastian Warnholz 40 | Bug reports: https://github.com/wahani/aoos/issues 41 | 42 | 0 errors | 0 warnings | 0 notes 43 | 44 | ## googleAuthR (0.4.0) 45 | Maintainer: Mark Edmondson 46 | Bug reports: https://github.com/MarkEdmondson1234/googleAuthR/issues 47 | 48 | 0 errors | 0 warnings | 0 notes 49 | 50 | ## miscFuncs (1.2-10) 51 | Maintainer: Benjamin M. Taylor 52 | 53 | 0 errors | 0 warnings | 0 notes 54 | 55 | ## Rd2roxygen (1.6.1) 56 | Maintainer: Yihui Xie 57 | Bug reports: https://github.com/yihui/Rd2roxygen/issues 58 | 59 | 0 errors | 0 warnings | 0 notes 60 | 61 | ## redland (1.0.17-9) 62 | Maintainer: Matthew B. Jones 63 | Bug reports: https://github.com/ropensci/redland-bindings/issues 64 | 65 | 1 error | 0 warnings | 0 notes 66 | 67 | ``` 68 | checking whether package ‘redland’ can be installed ... ERROR 69 | Installation failed. 70 | See ‘/Users/hadley/Documents/devtools/roxygen/revdep/checks/redland.Rcheck/00install.out’ for details. 71 | ``` 72 | 73 | ## sqlutils (1.2) 74 | Maintainer: Jason Bryer 75 | Bug reports: https://github.com/jbryer/sqlutils/issues 76 | 77 | 0 errors | 0 warnings | 4 notes 78 | 79 | ``` 80 | checking package dependencies ... NOTE 81 | Package which this enhances but not available for checking: ‘RODBC’ 82 | 83 | checking DESCRIPTION meta-information ... NOTE 84 | Malformed Title field: should not end in a period. 85 | 86 | checking dependencies in R code ... NOTE 87 | 'library' or 'require' calls in package code: 88 | ‘RJDBC’ ‘RMySQL’ ‘RODBC’ ‘RPostgreSQL’ ‘RSQLite’ ‘tcltk’ 89 | Please use :: or requireNamespace() instead. 90 | See section 'Suggested packages' in the 'Writing R Extensions' manual. 91 | 92 | checking R code for possible problems ... NOTE 93 | cacheQuery: no visible global function definition for ‘read.csv’ 94 | cacheQuery: no visible global function definition for ‘write.csv’ 95 | Undefined global functions or variables: 96 | read.csv write.csv 97 | Consider adding 98 | importFrom("utils", "read.csv", "write.csv") 99 | to your NAMESPACE file. 100 | ``` 101 | 102 | ## zoon (0.6) 103 | Maintainer: Tom August 104 | Bug reports: https://github.com/zoonproject/zoon/issues 105 | 106 | 0 errors | 0 warnings | 0 notes 107 | 108 | -------------------------------------------------------------------------------- /revdep/check.R: -------------------------------------------------------------------------------- 1 | library("devtools") 2 | 3 | revdep_check(dependencies = c("Depends", "Imports")) 4 | revdep_check_save_summary() 5 | revdep_check_print_problems() 6 | -------------------------------------------------------------------------------- /revdep/checks.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yihui/roxygen2/14eae413099f00b3ac630c5fa7ec1e62db6c659d/revdep/checks.rds -------------------------------------------------------------------------------- /revdep/problems.md: -------------------------------------------------------------------------------- 1 | # Setup 2 | 3 | ## Platform 4 | 5 | |setting |value | 6 | |:--------|:----------------------------| 7 | |version |R version 3.3.2 (2016-10-31) | 8 | |system |x86_64, darwin13.4.0 | 9 | |ui |RStudio (1.0.136) | 10 | |language |(EN) | 11 | |collate |en_US.UTF-8 | 12 | |tz |America/Chicago | 13 | |date |2017-01-30 | 14 | 15 | ## Packages 16 | 17 | |package |* |version |date |source | 18 | |:----------|:--|:----------|:----------|:------------------------------| 19 | |brew | |1.0-6 |2011-04-13 |cran (@1.0-6) | 20 | |commonmark | |1.1 |2016-12-13 |CRAN (R 3.3.2) | 21 | |covr | |2.2.2 |2017-01-05 |cran (@2.2.2) | 22 | |desc | |1.1.0 |2017-01-27 |cran (@1.1.0) | 23 | |devtools |* |1.12.0 |2016-06-24 |cran (@1.12.0) | 24 | |digest | |0.6.12 |2017-01-27 |cran (@0.6.12) | 25 | |knitr | |1.15.8 |2017-01-30 |Github (yihui/knitr@b936c1e) | 26 | |R6 | |2.2.0 |2016-10-05 |cran (@2.2.0) | 27 | |Rcpp | |0.12.9.1 |2017-01-30 |Github (RcppCore/Rcpp@5a99a86) | 28 | |rmarkdown | |1.3 |2016-12-21 |cran (@1.3) | 29 | |roxygen2 | |5.0.1.9000 |2017-01-30 |local (klutometis/roxygen@NA) | 30 | |stringi | |1.1.2 |2016-10-01 |cran (@1.1.2) | 31 | |stringr | |1.1.0 |2016-08-19 |local (tidyverse/stringr@NA) | 32 | |testthat |* |1.0.2 |2016-04-23 |cran (@1.0.2) | 33 | |xml2 | |1.1.1 |2017-01-24 |cran (@1.1.1) | 34 | 35 | # Check results 36 | 1 packages with problems 37 | 38 | ## redland (1.0.17-9) 39 | Maintainer: Matthew B. Jones 40 | Bug reports: https://github.com/ropensci/redland-bindings/issues 41 | 42 | 1 error | 0 warnings | 0 notes 43 | 44 | ``` 45 | checking whether package ‘redland’ can be installed ... ERROR 46 | Installation failed. 47 | See ‘/Users/hadley/Documents/devtools/roxygen/revdep/checks/redland.Rcheck/00install.out’ for details. 48 | ``` 49 | 50 | -------------------------------------------------------------------------------- /revdep/timing.md: -------------------------------------------------------------------------------- 1 | # Check times 2 | 3 | | |package |version | check_time| 4 | |:--|:-----------|:--------|----------:| 5 | |7 |zoon |0.6 | 90.8| 6 | |2 |googleAuthR |0.4.0 | 32.1| 7 | |6 |sqlutils |1.2 | 26.8| 8 | |3 |miscFuncs |1.2-10 | 25| 9 | |4 |Rd2roxygen |1.6.1 | 22.5| 10 | |5 |redland |1.0.17-9 | 12| 11 | |1 |aoos |0.4.0 | 10.1| 12 | 13 | 14 | -------------------------------------------------------------------------------- /roxygen.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageBuildArgs: --no-build-vignettes 22 | PackageRoxygenize: rd,collate,namespace,vignette 23 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.dll 4 | -------------------------------------------------------------------------------- /src/RcppExports.cpp: -------------------------------------------------------------------------------- 1 | // Generated by using Rcpp::compileAttributes() -> do not edit by hand 2 | // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 3 | 4 | #include 5 | 6 | using namespace Rcpp; 7 | 8 | // findEndOfTag 9 | int findEndOfTag(std::string string, bool is_code); 10 | RcppExport SEXP roxygen2_findEndOfTag(SEXP stringSEXP, SEXP is_codeSEXP) { 11 | BEGIN_RCPP 12 | Rcpp::RObject rcpp_result_gen; 13 | Rcpp::RNGScope rcpp_rngScope_gen; 14 | Rcpp::traits::input_parameter< std::string >::type string(stringSEXP); 15 | Rcpp::traits::input_parameter< bool >::type is_code(is_codeSEXP); 16 | rcpp_result_gen = Rcpp::wrap(findEndOfTag(string, is_code)); 17 | return rcpp_result_gen; 18 | END_RCPP 19 | } 20 | // rdComplete 21 | bool rdComplete(std::string string, bool is_code); 22 | RcppExport SEXP roxygen2_rdComplete(SEXP stringSEXP, SEXP is_codeSEXP) { 23 | BEGIN_RCPP 24 | Rcpp::RObject rcpp_result_gen; 25 | Rcpp::RNGScope rcpp_rngScope_gen; 26 | Rcpp::traits::input_parameter< std::string >::type string(stringSEXP); 27 | Rcpp::traits::input_parameter< bool >::type is_code(is_codeSEXP); 28 | rcpp_result_gen = Rcpp::wrap(rdComplete(string, is_code)); 29 | return rcpp_result_gen; 30 | END_RCPP 31 | } 32 | // leadingSpaces 33 | IntegerVector leadingSpaces(CharacterVector lines); 34 | RcppExport SEXP roxygen2_leadingSpaces(SEXP linesSEXP) { 35 | BEGIN_RCPP 36 | Rcpp::RObject rcpp_result_gen; 37 | Rcpp::RNGScope rcpp_rngScope_gen; 38 | Rcpp::traits::input_parameter< CharacterVector >::type lines(linesSEXP); 39 | rcpp_result_gen = Rcpp::wrap(leadingSpaces(lines)); 40 | return rcpp_result_gen; 41 | END_RCPP 42 | } 43 | // tokenise_block 44 | List tokenise_block(CharacterVector lines, std::string file, int offset); 45 | RcppExport SEXP roxygen2_tokenise_block(SEXP linesSEXP, SEXP fileSEXP, SEXP offsetSEXP) { 46 | BEGIN_RCPP 47 | Rcpp::RObject rcpp_result_gen; 48 | Rcpp::RNGScope rcpp_rngScope_gen; 49 | Rcpp::traits::input_parameter< CharacterVector >::type lines(linesSEXP); 50 | Rcpp::traits::input_parameter< std::string >::type file(fileSEXP); 51 | Rcpp::traits::input_parameter< int >::type offset(offsetSEXP); 52 | rcpp_result_gen = Rcpp::wrap(tokenise_block(lines, file, offset)); 53 | return rcpp_result_gen; 54 | END_RCPP 55 | } 56 | // find_includes 57 | CharacterVector find_includes(std::string path); 58 | RcppExport SEXP roxygen2_find_includes(SEXP pathSEXP) { 59 | BEGIN_RCPP 60 | Rcpp::RObject rcpp_result_gen; 61 | Rcpp::RNGScope rcpp_rngScope_gen; 62 | Rcpp::traits::input_parameter< std::string >::type path(pathSEXP); 63 | rcpp_result_gen = Rcpp::wrap(find_includes(path)); 64 | return rcpp_result_gen; 65 | END_RCPP 66 | } 67 | // splitByWhitespace 68 | std::vector splitByWhitespace(std::string string); 69 | RcppExport SEXP roxygen2_splitByWhitespace(SEXP stringSEXP) { 70 | BEGIN_RCPP 71 | Rcpp::RObject rcpp_result_gen; 72 | Rcpp::RNGScope rcpp_rngScope_gen; 73 | Rcpp::traits::input_parameter< std::string >::type string(stringSEXP); 74 | rcpp_result_gen = Rcpp::wrap(splitByWhitespace(string)); 75 | return rcpp_result_gen; 76 | END_RCPP 77 | } 78 | // wrapString 79 | std::string wrapString(std::string string, int width, int indent); 80 | RcppExport SEXP roxygen2_wrapString(SEXP stringSEXP, SEXP widthSEXP, SEXP indentSEXP) { 81 | BEGIN_RCPP 82 | Rcpp::RObject rcpp_result_gen; 83 | Rcpp::RNGScope rcpp_rngScope_gen; 84 | Rcpp::traits::input_parameter< std::string >::type string(stringSEXP); 85 | Rcpp::traits::input_parameter< int >::type width(widthSEXP); 86 | Rcpp::traits::input_parameter< int >::type indent(indentSEXP); 87 | rcpp_result_gen = Rcpp::wrap(wrapString(string, width, indent)); 88 | return rcpp_result_gen; 89 | END_RCPP 90 | } 91 | -------------------------------------------------------------------------------- /src/isComplete.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace Rcpp; 3 | 4 | // From http://developer.r-project.org/parseRd.pdf: The characters \, %, {, 5 | // and } have special meaning in almost all parts of an Rd file. In code, 6 | // strings must also match, except in comments. 7 | 8 | // The two functions are very similar, so we use a common 9 | // implementation and select the functionality via the 10 | // mode argument: 11 | // mode == 0: rdComplete 12 | // mode == 1: findEndOfTag 13 | 14 | int roxygen_parse_tag(std::string string, bool is_code = false, 15 | int mode = 0) { 16 | int n = string.length(); 17 | 18 | char in_string = '\0'; 19 | bool in_escape = false; 20 | bool in_r_comment = false; 21 | bool in_latex_comment = false; 22 | int braces = 0, r_braces = 0; 23 | 24 | for(int i = 0; i < n; i++) { 25 | char cur = string[i]; 26 | 27 | if (in_escape) { 28 | // Swallow escaped characters 29 | in_escape = false; 30 | } else if (in_string != '\0') { 31 | // Look for end of string 32 | if (cur == in_string) { 33 | in_string = false; 34 | } else if (cur == '\\') { 35 | in_escape = true; 36 | } 37 | } else if (in_r_comment) { 38 | // Inside R comments, braces must match. 39 | // R comments are terminated by newline or } not matched by { 40 | if (cur == '\n') { 41 | in_r_comment = false; 42 | r_braces = 0; 43 | } else if (cur == '{') { 44 | braces++; 45 | r_braces++; 46 | } else if (cur == '}') { 47 | braces--; 48 | r_braces--; 49 | if (r_braces == 0) 50 | in_r_comment = false; 51 | } 52 | } else if (in_latex_comment) { 53 | if (cur == '\n') { 54 | in_latex_comment = false; 55 | } 56 | } else { 57 | switch(cur) { 58 | case '{': braces++; break; 59 | case '}': braces--; break; 60 | case '\\': in_escape = true; break; 61 | case '#': if (is_code) in_r_comment = true; break; 62 | case '%': in_latex_comment = true; break; 63 | case '\'': if (is_code) in_string = '\''; break; 64 | case '"': if (is_code) in_string = '"'; break; 65 | } 66 | } 67 | 68 | if (mode == 1) { 69 | bool complete = braces == 0 && !in_escape && !in_string; 70 | if (complete && i + 1 < n && string[i + 1] != '{') { 71 | return i; 72 | } 73 | } 74 | 75 | } 76 | 77 | bool complete = braces == 0 && !in_escape && !in_string; 78 | 79 | if (mode == 0) { 80 | if (complete) return 1; else return 0; 81 | 82 | } else { 83 | if (complete) return n - 1; else return -1; 84 | } 85 | } 86 | 87 | // [[Rcpp::export]] 88 | int findEndOfTag(std::string string, bool is_code = false) { 89 | return roxygen_parse_tag(string, is_code, 1); 90 | } 91 | 92 | // [[Rcpp::export]] 93 | bool rdComplete(std::string string, bool is_code = false) { 94 | return roxygen_parse_tag(string, is_code, 0) == 1 ? true : false; 95 | } 96 | -------------------------------------------------------------------------------- /src/leadingSpaces.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace Rcpp; 3 | 4 | int leadingSpacesOne(std::string line) { 5 | int n = line.size(); 6 | for(int i = 0; i < n; ++i) { 7 | char cur = line[i]; 8 | 9 | if (cur != ' ') return(i); 10 | } 11 | 12 | return n; 13 | } 14 | 15 | // [[Rcpp::export]] 16 | IntegerVector leadingSpaces(CharacterVector lines) { 17 | int n = lines.size(); 18 | IntegerVector out(n); 19 | 20 | for(int i = 0; i < n; ++i) { 21 | String cur = lines[i]; 22 | out[i] = leadingSpacesOne(cur); 23 | } 24 | return out; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/wrapString.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace Rcpp; 3 | 4 | // [[Rcpp::export]] 5 | std::vector splitByWhitespace(std::string string) { 6 | std::vector out; 7 | 8 | std::string acc = ""; 9 | char in_string = '\0'; 10 | int in_escape = 0; 11 | 12 | std::string::const_iterator cur = string.begin(), end = string.end(); 13 | 14 | while(cur != end) { 15 | if (in_string != '\0') { 16 | acc += *cur; 17 | 18 | if (in_escape) { 19 | in_escape--; 20 | } else if (*cur == '\\' && cur + 1 != end && *(cur + 1) == '\\') { 21 | in_escape = 2; 22 | } else if (*cur == in_string) { 23 | // String terminates 24 | in_string = '\0'; 25 | } 26 | 27 | } else if (*cur == ' ' || *cur == '\t' || *cur == '\n') { 28 | out.push_back(acc); 29 | acc = ""; 30 | } else if (*cur == '"' || *cur == '\'') { 31 | in_string = *cur; 32 | acc += *cur; 33 | } else { 34 | acc += *cur; 35 | } 36 | 37 | cur++; 38 | } 39 | 40 | out.push_back(acc); 41 | 42 | return out; 43 | } 44 | 45 | // [[Rcpp::export]] 46 | std::string wrapString(std::string string, int width = 80, int indent = 2) { 47 | std::vector pieces = splitByWhitespace(string); 48 | int n = pieces.size(); 49 | int cur_width = 0; 50 | 51 | std::string out; 52 | 53 | for (int i = 0; i < n; ++i) { 54 | int piece_width = pieces[i].size(); 55 | 56 | if (piece_width + cur_width < width) { 57 | cur_width += piece_width; 58 | if (i != 0) { 59 | out += " "; 60 | cur_width++; 61 | } 62 | } else { 63 | cur_width = piece_width + indent; 64 | out += "\n" + std::string(indent, ' ') ; 65 | } 66 | out += pieces[i]; 67 | } 68 | 69 | return out; 70 | } 71 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(roxygen2) 3 | 4 | test_check("roxygen2") 5 | -------------------------------------------------------------------------------- /tests/testthat/Rd-example-1.R: -------------------------------------------------------------------------------- 1 | example <- 'example1' 2 | -------------------------------------------------------------------------------- /tests/testthat/Rd-example-2.R: -------------------------------------------------------------------------------- 1 | example <- 'example2' 2 | -------------------------------------------------------------------------------- /tests/testthat/Rd-example-3.R: -------------------------------------------------------------------------------- 1 | x1 <- 1 2 | x2 <- 2 3 | -------------------------------------------------------------------------------- /tests/testthat/Rd-example-4.R: -------------------------------------------------------------------------------- 1 | x %*% y # \x 2 | -------------------------------------------------------------------------------- /tests/testthat/Rd-example-5.R: -------------------------------------------------------------------------------- 1 | \dontrun{x <- 1} 2 | -------------------------------------------------------------------------------- /tests/testthat/collate/belt.R: -------------------------------------------------------------------------------- 1 | # The space before @ is missing on purpose (#342). 2 | #'@include pants.R 3 | #'@include shirt.R 4 | NULL 5 | -------------------------------------------------------------------------------- /tests/testthat/collate/jacket.R: -------------------------------------------------------------------------------- 1 | #' @include tie.R 2 | #' @include belt.R 3 | NULL 4 | -------------------------------------------------------------------------------- /tests/testthat/collate/pants.R: -------------------------------------------------------------------------------- 1 | #' @include undershorts.R 2 | NULL 3 | -------------------------------------------------------------------------------- /tests/testthat/collate/shirt.R: -------------------------------------------------------------------------------- 1 | NULL 2 | -------------------------------------------------------------------------------- /tests/testthat/collate/shoes.R: -------------------------------------------------------------------------------- 1 | #' @include socks.R 2 | #' @include undershorts.R 3 | #' @include pants.R 4 | NULL 5 | -------------------------------------------------------------------------------- /tests/testthat/collate/socks.R: -------------------------------------------------------------------------------- 1 | NULL 2 | -------------------------------------------------------------------------------- /tests/testthat/collate/tie.R: -------------------------------------------------------------------------------- 1 | #' @include shirt.R 2 | NULL 3 | -------------------------------------------------------------------------------- /tests/testthat/collate/undershorts.R: -------------------------------------------------------------------------------- 1 | NULL 2 | -------------------------------------------------------------------------------- /tests/testthat/collate/watch.R: -------------------------------------------------------------------------------- 1 | NULL 2 | 3 | x <- 2 4 | -------------------------------------------------------------------------------- /tests/testthat/description-example.txt: -------------------------------------------------------------------------------- 1 | Package: foobar 2 | Version: 1.0 3 | License: GPL (>= 2) 4 | 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. 5 | Title: A fake package for testing purposes 6 | Author: Alan Turing , 7 | Alonzo Church , 8 | Charles Babbage , 9 | Ada Lovelace , 10 | Grace Murray Hopper 11 | Maintainer: Alan Turing 12 | Imports: 13 | stringr (>= 0.5), 14 | tools, 15 | brew 16 | Suggests: 17 | testthat 18 | Depends: 19 | digest 20 | 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' 21 | -------------------------------------------------------------------------------- /tests/testthat/description-example_2.txt: -------------------------------------------------------------------------------- 1 | Package: foobar 2 | Version: 2.0 3 | License: GPL (>= 2) 4 | 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. 5 | Title: A fake package for testing purposes 6 | Authors@R: c( 7 | person("Alan Turing", role = c("auth", "cre", "cph"), 8 | email = "alan@turing.fake", 9 | comment = c("As this is a fake package, as you may have guessed, authorship" 10 | "information should not be taken seriously either."), 11 | person("Alonzo Church", role = "ctb", 12 | email = "alonzo@church.fake"), 13 | person("Grace Murray Hopper", role = "auth", 14 | email = "grace@murray-hopper.fake")) 15 | Imports: 16 | stringr (>= 0.5), 17 | tools, 18 | brew 19 | Suggests: 20 | testthat 21 | Depends: 22 | digest 23 | 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' 24 | -------------------------------------------------------------------------------- /tests/testthat/empty/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Name: empty 2 | -------------------------------------------------------------------------------- /tests/testthat/empty/R/empty-package.R: -------------------------------------------------------------------------------- 1 | NULL 2 | -------------------------------------------------------------------------------- /tests/testthat/helper-env.R: -------------------------------------------------------------------------------- 1 | pkg_env <- function() { 2 | env <- new.env(parent = globalenv()) 3 | env$.packageName <- "roxygen2" 4 | env 5 | } 6 | -------------------------------------------------------------------------------- /tests/testthat/helper-pkg.R: -------------------------------------------------------------------------------- 1 | temp_copy_pkg <- function(pkg) { 2 | file.copy(normalizePath(pkg), tempdir(), recursive = TRUE) 3 | normalizePath(file.path(tempdir(), basename(pkg))) 4 | } 5 | -------------------------------------------------------------------------------- /tests/testthat/helper-test.R: -------------------------------------------------------------------------------- 1 | expect_equivalent_rd <- function(out1, out2) { 2 | out1$fields$backref <- NULL 3 | out2$fields$backref <- NULL 4 | expect_equal(out1, out2) 5 | } 6 | -------------------------------------------------------------------------------- /tests/testthat/made-by-roxygen/empty.Rd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yihui/roxygen2/14eae413099f00b3ac630c5fa7ec1e62db6c659d/tests/testthat/made-by-roxygen/empty.Rd -------------------------------------------------------------------------------- /tests/testthat/made-by-roxygen/with-header.Rd: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2 (4.0.0): Do not edit by hand 2 | 3 | # Test file 4 | -------------------------------------------------------------------------------- /tests/testthat/made-by-roxygen/without-header.Rd: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Test file 4 | -------------------------------------------------------------------------------- /tests/testthat/man-roxygen/UCase.R: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yihui/roxygen2/14eae413099f00b3ac630c5fa7ec1e62db6c659d/tests/testthat/man-roxygen/UCase.R -------------------------------------------------------------------------------- /tests/testthat/man-roxygen/lcase.r: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yihui/roxygen2/14eae413099f00b3ac630c5fa7ec1e62db6c659d/tests/testthat/man-roxygen/lcase.r -------------------------------------------------------------------------------- /tests/testthat/man-roxygen/reg.ex.R: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yihui/roxygen2/14eae413099f00b3ac630c5fa7ec1e62db6c659d/tests/testthat/man-roxygen/reg.ex.R -------------------------------------------------------------------------------- /tests/testthat/man-roxygen/values.R: -------------------------------------------------------------------------------- 1 | #' <%= x %> 2 | #' @param <%= y %> <%= z %> 3 | -------------------------------------------------------------------------------- /tests/testthat/roxygen-block-1.R: -------------------------------------------------------------------------------- 1 | ##' Title 2 | ##' 3 | ##' Description 4 | ##' 5 | ##' Details 6 | ##' 7 | ##' @param x,y,z Descriptions for x, y, z 8 | ##' @param a Description of a 9 | ##' @param b 10 | ##' Description of b 11 | ##' @section Important: 12 | ##' Don't run with scissors! 13 | ##' @export 14 | -------------------------------------------------------------------------------- /tests/testthat/roxygen-block-2.R: -------------------------------------------------------------------------------- 1 | #' The length of a string (in characters). 2 | #' 3 | #' @param string input character vector 4 | #' @return numeric vector giving number of characters in each element of the 5 | #' character vector. Missing strings have missing length. 6 | #' @seealso \code{\link{nchar}} which this function wraps 7 | #' @export 8 | #' @examples 9 | #' str_length(letters) 10 | #' str_length(c("i", "like", "programming", NA)) 11 | -------------------------------------------------------------------------------- /tests/testthat/roxygen-example-1.R: -------------------------------------------------------------------------------- 1 | ##' Title 2 | ##' 3 | ##' Description 4 | ##' 5 | ##' Details 6 | ##' 7 | ##' @param x,y,z Descriptions for x, y, z 8 | ##' @param a Description of a 9 | ##' @param b 10 | ##' Description of b 11 | ##' @section Important: 12 | ##' Don't run with scissors! 13 | ##' @export 14 | NULL 15 | 16 | ##' Title 17 | ##' 18 | ##' Description 19 | ##' 20 | ##' Details 21 | ##' 22 | ##' @param x,y,z Descriptions for x, y, z 23 | ##' @param a Description of a 24 | ##' @param b 25 | ##' Description of b 26 | ##' @section Important: 27 | ##' Don't run with scissors! 28 | ##' @export 29 | NULL 30 | -------------------------------------------------------------------------------- /tests/testthat/test-Rbuildignore.R: -------------------------------------------------------------------------------- 1 | context("Rbuildignore") 2 | 3 | test_that("roxygen ignores files with matching pattern in .Rbuildignore", { 4 | test_pkg <- temp_copy_pkg(test_path("testRbuildignore")) 5 | on.exit(unlink(test_pkg, recursive = TRUE)) 6 | 7 | expect_equal(basename(package_files(test_pkg)), c("a.R", "ignore_me.R")) 8 | 9 | #writeLines("^R/ignore_me.R$", file.path(test_pkg, ".Rbuildignore")) 10 | writeChar("^R/ignore_me.R$\n", file.path(test_pkg, ".Rbuildignore"), eos = NULL) 11 | expect_equal(basename(package_files(test_pkg)), "a.R") 12 | }) 13 | 14 | test_that("roxygen works with empty lines in .Rbuildignore", { 15 | test_pkg <- temp_copy_pkg(test_path("testRbuildignore")) 16 | on.exit(unlink(test_pkg, recursive = TRUE)) 17 | 18 | writeChar("^R/ignore_me.R$\n\n.nonexistentfile", file.path(test_pkg, ".Rbuildignore"), eos = NULL) 19 | expect_equal(basename(package_files(test_pkg)), "a.R") 20 | }) 21 | -------------------------------------------------------------------------------- /tests/testthat/test-collate.R: -------------------------------------------------------------------------------- 1 | context("Collate") 2 | 3 | test_that("collation as expected", { 4 | results <- generate_collate("collate") 5 | names <- str_replace(basename(results), "\\..*$", "") 6 | 7 | before <- function(a, b) { 8 | all(which(names %in% a) < which(names %in% b)) 9 | } 10 | 11 | expect_true(before("undershorts", "pants")) 12 | expect_true(before(c("tie", "belt"), "jacket")) 13 | expect_true(before(c("socks", "undershorts", "pants"), "shoes")) 14 | 15 | expected <- c('shirt.R', 'undershorts.R','pants.R', 'belt.R', 'tie.R', 16 | 'jacket.R', 'socks.R', 'shoes.R', 'watch.R') 17 | 18 | expect_equal(results, expected) 19 | }) 20 | 21 | test_that("Collate field unchanged when no @includes", { 22 | test_pkg <- temp_copy_pkg('testCollateNoIncludes') 23 | on.exit(unlink(test_pkg, recursive = TRUE)) 24 | 25 | old_desc <- read.description(file.path(test_pkg, "DESCRIPTION")) 26 | update_collate(test_pkg) 27 | new_desc <- read.description(file.path(test_pkg, "DESCRIPTION")) 28 | 29 | expect_equal(names(old_desc), names(new_desc)) 30 | expect_identical(old_desc$Collate,new_desc$Collate) 31 | 32 | }) 33 | 34 | test_that("DESCRIPTION file is re-written only if collate changes", { 35 | pkg_path <- "testCollateOverwrite" 36 | desc_path <- file.path(pkg_path, 'DESCRIPTION') 37 | 38 | # make backup copy of incomplete DESCRIPTION file (restored on exit) 39 | file.copy(desc_path, tmp <- tempfile()) 40 | on.exit( file.copy(tmp, desc_path, overwrite = TRUE), add = TRUE) 41 | 42 | # load package: this should update the DESCRIPTION file (warning) 43 | expect_output(update_collate(pkg_path), "Updating collate directive", info = "update_collate on incomplete package: DESCRIPTION file is updated") 44 | 45 | # should not update anymore 46 | expect_true(!length(capture.output(update_collate(pkg_path))), info = "update_collate on complete package: DESCRIPTION file is NOT updated") 47 | 48 | }) 49 | 50 | 51 | -------------------------------------------------------------------------------- /tests/testthat/test-nice-name.R: -------------------------------------------------------------------------------- 1 | context("nice_name()") 2 | 3 | test_that("nice_name leaves ok chars unchanged", { 4 | expect_equal(nice_name("abc"), "abc") 5 | expect_equal(nice_name("a_b-c.R"), "a_b-c.R") 6 | }) 7 | 8 | test_that("nice_name protects against invalid characters", { 9 | expect_equal(nice_name("a<-"), "a-set") 10 | expect_equal(nice_name("[.a"), "sub-.a") 11 | }) 12 | 13 | -------------------------------------------------------------------------------- /tests/testthat/test-nonASCII.R: -------------------------------------------------------------------------------- 1 | context("nonASCII") 2 | 3 | test_that("can generate nonASCII document", { 4 | test_pkg <- temp_copy_pkg('testNonASCII') 5 | on.exit(unlink(test_pkg, recursive = TRUE), add = TRUE) 6 | 7 | expect_output(roxygenise(test_pkg, roclets = "rd"), "printChineseMsg[.]Rd") 8 | expect_true(file.exists(file.path(test_pkg, "man", "printChineseMsg.Rd"))) 9 | 10 | cnChar <- read_lines_enc(file.path(test_pkg, "man", "printChineseMsg.Rd")) 11 | 12 | # Because the parse in testthat::test don't specify encoding to UTF-8 as well, 13 | # so we have to use unicode escapes. 14 | expect_true(any(grepl("\u6211\u7231\u4e2d\u6587", cnChar))) 15 | expect_true(any(grepl("\u4e2d\u6587\u6ce8\u91ca", cnChar))) 16 | 17 | # No output on second run 18 | expect_output(roxygenise(test_pkg, roclets = "rd"), NA) 19 | }) 20 | -------------------------------------------------------------------------------- /tests/testthat/test-object-format.R: -------------------------------------------------------------------------------- 1 | context("object_format") 2 | 3 | test_that("format defaults for list", { 4 | out <- roc_proc_text(rd_roclet(), " 5 | #' Title 6 | x <- list(a = 1, b = 2)")[[1]] 7 | 8 | expect_equal(get_tag(out, "format")$values, 9 | rd("An object of class \\code{list} of length 2.") 10 | ) 11 | }) 12 | 13 | test_that("format defaults for matrices", { 14 | out <- roc_proc_text(rd_roclet(), " 15 | #' Title 16 | x <- diag(10)")[[1]] 17 | 18 | expect_equal(get_tag(out, "format")$values, 19 | rd("An object of class \\code{matrix} with 10 rows and 10 columns.") 20 | ) 21 | }) 22 | 23 | test_that("format defaults for data frames", { 24 | out <- roc_proc_text(rd_roclet(), " 25 | #' Title 26 | x <- data.frame(a = 1, b = 2)")[[1]] 27 | 28 | expect_equal(get_tag(out, "format")$values, 29 | rd("An object of class \\code{data.frame} with 1 rows and 2 columns.") 30 | ) 31 | }) 32 | 33 | test_that("format defaults for arrays", { 34 | out <- roc_proc_text(rd_roclet(), " 35 | #' Title 36 | x <- array(1:27, dim = c(3, 3, 3))")[[1]] 37 | 38 | expect_equal(get_tag(out, "format")$values, 39 | rd("An object of class \\code{array} of dimension 3 x 3 x 3.") 40 | ) 41 | }) 42 | 43 | test_that("format defaults for xtabs", { 44 | out <- roc_proc_text(rd_roclet(), " 45 | #' Title 46 | x <- xtabs(~cyl+am+gear, mtcars)")[[1]] 47 | 48 | expect_equal(get_tag(out, "format")$values, 49 | rd("An object of class \\code{xtabs} (inherits from \\code{table}) of dimension 3 x 2 x 3.") 50 | ) 51 | }) 52 | 53 | test_that("@format overrides defaults", { 54 | out <- roc_proc_text(rd_roclet(), " 55 | #' Title 56 | #' 57 | #' @format abc 58 | #' 59 | x <- list(a = 1, b = 2)")[[1]] 60 | 61 | expect_equal(get_tag(out, "format")$values, "abc") 62 | }) 63 | 64 | test_that("@format NULL suppresses default usage", { 65 | out <- roc_proc_text(rd_roclet(), " 66 | #' Title 67 | #' 68 | #' @format NULL 69 | #' 70 | x <- list(a = 1, b = 2)")[[1]] 71 | 72 | expect_equal(get_tag(out, "format")$values, NULL) 73 | }) 74 | 75 | 76 | test_that("@format not escaped", { 77 | out <- roc_proc_text(rd_roclet(), " 78 | #' Title 79 | #' @format % 80 | #' 81 | x <- list(a = 1, b = 2)")[[1]] 82 | 83 | expect_equal(get_tag(out, "format")$values, "%") 84 | expect_equal(format(get_tag(out, "format")), "\\format{%}") 85 | }) 86 | -------------------------------------------------------------------------------- /tests/testthat/test-object-rc.R: -------------------------------------------------------------------------------- 1 | context("Object: rc") 2 | 3 | # Docstrings ------------------------------------------------------------------- 4 | 5 | test_that("base functions don't have docstrings", { 6 | expect_equal(docstring(`[`), NULL) 7 | expect_equal(docstring(mean), NULL) 8 | }) 9 | 10 | test_that("function return string doesn't have docstring", { 11 | expect_equal(docstring(function() "a"), NULL) 12 | expect_equal(docstring(function() {"a"}), NULL) 13 | }) 14 | 15 | test_that("first string in function is docstring", { 16 | expect_equal(docstring(function() {"a"; 1}), "a") 17 | }) 18 | 19 | test_that("trim_docstring handles indentation correctly", { 20 | expect_equal(trim_docstring("a\n b\n c"), "a\nb\nc") 21 | expect_equal(trim_docstring("a\nb\nc"), "a\nb\nc") 22 | expect_equal(trim_docstring("a\n b\n c"), "a\nb\n c") 23 | expect_equal(trim_docstring(" a\n b\n c"), "a\nb\n c") 24 | }) 25 | 26 | # Method documentation --------------------------------------------------------- 27 | 28 | env <- pkg_env() 29 | 30 | A1 <- setRefClass("A1", methods = list( 31 | f = function() { 32 | "This function has a docstring" 33 | 1 34 | }, 35 | g = function() { 36 | "This function doesn't" 37 | } 38 | ), where = env) 39 | 40 | B1 <- setRefClass("B1", contains = "A1", methods = list( 41 | f1 = function() { 42 | "This function has a docstring" 43 | 1 44 | }, 45 | g1 = function() { 46 | "This function doesn't" 47 | } 48 | ), where = env) 49 | 50 | classA <- getClass("A1", where = env) 51 | classB <- getClass("B1", where = env) 52 | 53 | test_that("rc_methods only lists methods belong to class (not parents)", { 54 | expect_equal(length(rc_methods(classA)), 2) 55 | expect_equal(length(rc_methods(classB)), 2) 56 | }) 57 | 58 | test_that("RC methods included included in own section", { 59 | out <- roc_proc_text(rd_roclet(), " 60 | #' Class ABC 61 | setRefClass('ABC', methods = list( 62 | f = function() { 63 | 'This function has a docstring' 64 | 1 65 | } 66 | )) 67 | ")[[1]] 68 | 69 | methods <- get_tag(out, "rcmethods")$values 70 | expect_equal(names(methods), "f()") 71 | expect_match(methods[[1]], "This function has a docstring") 72 | }) 73 | 74 | removeClass("B1", where = env) 75 | removeClass("A1", where = env) 76 | -------------------------------------------------------------------------------- /tests/testthat/test-object-s3.R: -------------------------------------------------------------------------------- 1 | context("Object: S3 methods/generics") 2 | 3 | test_that("primitive generics detected", { 4 | expect_true(is_s3_generic("[")) 5 | expect_true(is_s3_method("[.data.frame")) 6 | 7 | expect_true(is_s3_generic("mean")) 8 | expect_true(is_s3_method("mean.default")) 9 | 10 | expect_true(is_s3_generic("c")) 11 | expect_true(is_s3_method("c.Date")) 12 | }) 13 | 14 | test_that("non-functions are not generics", { 15 | a <- TRUE 16 | b <- NULL 17 | c <- data.frame() 18 | 19 | expect_false(is_s3_generic("a")) 20 | expect_false(is_s3_generic("b")) 21 | expect_false(is_s3_generic("c")) 22 | }) 23 | 24 | test_that("user defined generics & methods detected", { 25 | my_method <- function(x) UseMethod("mymethod") 26 | my_method.character <- function(x) x 27 | 28 | expect_true(is_s3_generic("my_method")) 29 | expect_true(is_s3_method("my_method.character")) 30 | }) 31 | 32 | 33 | test_that("methods for group generics detected", { 34 | Ops.myclass <- function(x) x 35 | 36 | expect_false(is_s3_generic("Ops.myclass")) 37 | expect_true(is_s3_method("Ops.myclass")) 38 | }) 39 | 40 | 41 | test_that("user defined generics detected even if use non-standard", { 42 | my_method <- function(x) { 43 | x <- 1 44 | if (x > 2) UseMethod("mymethod") 45 | } 46 | 47 | expect_true(is_s3_generic("my_method")) 48 | }) 49 | 50 | test_that("user defined functions override primitives", { 51 | c <- function(x) x + 1 52 | c.test <- function(x) x + 3 53 | 54 | expect_false(is_s3_generic("c")) 55 | expect_false(is_s3_method("c")) 56 | }) 57 | 58 | test_that("@method overrides auto-detection", { 59 | out <- parse_text(" 60 | #' @export 61 | #' @method all.equal data.frame 62 | all.equal.data.frame <- function(...) 1 63 | ")$blocks[[1]] 64 | 65 | expect_equal(s3_method_info(out$object$value), c("all.equal", "data.frame")) 66 | }) 67 | -------------------------------------------------------------------------------- /tests/testthat/test-object-s4.R: -------------------------------------------------------------------------------- 1 | context("Object: S4") 2 | 3 | test_that("class captured from setClass", { 4 | out <- parse_text(" 5 | #' Title 6 | setClass('A1') 7 | ")$blocks[[1]] 8 | 9 | expect_is(out$object, "s4class") 10 | expect_equal(out$object$alias, NULL) 11 | }) 12 | 13 | test_that("class captured from assignment", { 14 | out <- parse_text(" 15 | #' Title 16 | B <- setClass('B1') 17 | ")$blocks[[1]] 18 | 19 | expect_is(out$object, "s4class") 20 | expect_equal(out$object$alias, "B") 21 | }) 22 | 23 | test_that("class captured from setClassUnion", { 24 | out <- parse_text(" 25 | #' Title 26 | setClassUnion('numberish', c('numeric', 'logical')) 27 | ")$blocks[[1]] 28 | 29 | expect_is(out$object, "s4class") 30 | expect_equal(out$object$alias, NULL) 31 | }) 32 | 33 | test_that("class captured from setRefClass", { 34 | out <- parse_text(" 35 | #' Title 36 | setRefClass('A1') 37 | ")$blocks[[1]] 38 | 39 | expect_is(out$object, "rcclass") 40 | expect_equal(out$object$alias, NULL) 41 | }) 42 | 43 | test_that("class captured from assignment of setRefClass", { 44 | out <- parse_text(" 45 | #' Title 46 | B <- setRefClass('B1') 47 | ")$blocks[[1]] 48 | 49 | expect_is(out$object, "rcclass") 50 | expect_equal(out$object$alias, "B") 51 | }) 52 | 53 | test_that("setMethod equivalent to setReplaceMethod", { 54 | out <- parse_text(" 55 | setGeneric('foo<-', function(x, value) standardGeneric('foo<-')) 56 | 57 | #' setMethod 58 | setMethod('foo<-', 'numeric', function(x, value) value * 10) 59 | #' setReplace 60 | setReplaceMethod('foo', 'numeric', function(x, value) value * 10) 61 | ")$blocks 62 | 63 | expect_equal(out[[2]]$object, out[[3]]$object) 64 | }) 65 | -------------------------------------------------------------------------------- /tests/testthat/test-object.R: -------------------------------------------------------------------------------- 1 | context("Object") 2 | 3 | # Generate one object of every type -------------------------------------------- 4 | 5 | env <- pkg_env() 6 | 7 | # S3 8 | h <- function(x) UseMethod("h") 9 | h1 <- add_s3_metadata(h, "h", environment()) 10 | h.A <- function(x) 1 11 | h1.A <- add_s3_metadata(h.A, "h.A", environment()) 12 | 13 | # S4 14 | B <- setClass("B", contains = "list", where = env) 15 | classB <- getClass("B", where = env) 16 | setGeneric("g", function(x, ...) standardGeneric("g"), where = env) 17 | g <- getGeneric("g", where = env) 18 | 19 | setMethod("g", "B", function(x, ...) 1, where = env) 20 | method1 <- getMethod("g", "B", where = env) 21 | 22 | setClass("C", contains = "B", where = env) 23 | setMethod("g", "C", function(x, ..., blah = 7) 1, where = env) 24 | method2 <- getMethod("g", "C", where = env) 25 | 26 | # RC 27 | A <- setRefClass("A", where = env, methods = list(f = function() 1)) 28 | classA <- getClass("A", where = env) 29 | 30 | # Object type ------------------------------------------------------------------ 31 | 32 | test_that("obj_type correctly classifies objects", { 33 | expect_equal(obj_type(h1), "s3generic") 34 | expect_equal(obj_type(h1.A), "s3method") 35 | 36 | expect_equal(obj_type(classB), "s4class") 37 | expect_equal(obj_type(g), "s4generic") 38 | expect_equal(obj_type(method1), "s4method") 39 | expect_equal(obj_type(method2), "s4method") 40 | 41 | expect_equal(obj_type(classA), "rcclass") 42 | }) 43 | 44 | test_that("functions with class are still functions", { 45 | foo <- structure(function() TRUE, class = "foo") 46 | expect_equal(obj_type(foo), "function") 47 | }) 48 | 49 | # Object standardisation ------------------------------------------------------- 50 | 51 | test_that("generators standardised to classes", { 52 | objA <- standardise_obj("A", A, env = env) 53 | objB <- standardise_obj("B", B, env = env) 54 | 55 | expect_is(objA, "classRepresentation") 56 | expect_is(objB, "classRepresentation") 57 | }) 58 | 59 | test_that("methods with extra args get correct formals", { 60 | obj <- standardise_obj("method2", method2, env = env) 61 | args <- formals(obj@.Data) 62 | 63 | expect_equal(names(args), c("x", "...", "blah")) 64 | }) 65 | 66 | test_that("s3 generics and methods labelled with metadata", { 67 | generic <- standardise_obj("h", h, env = environment()) 68 | method <- standardise_obj("h.A", h.A, env = environment()) 69 | 70 | expect_is(generic, "s3generic") 71 | expect_is(method, "s3method") 72 | }) 73 | 74 | # Object creation -------------------------------------------------------------- 75 | 76 | test_that("generators get function name as alias", { 77 | objA <- object(standardise_obj("A", A, env = env), "genA") 78 | expect_equal(objA$alias, "genA") 79 | 80 | objB <- object(standardise_obj("B", B, env = env), "genB") 81 | expect_equal(objB$alias, "genB") 82 | }) 83 | 84 | test_that("refclasses get rc_methods listing", { 85 | objA <- object(standardise_obj("A", A, env = env), "genA") 86 | expect_equal(names(objA$methods), "f") 87 | }) 88 | 89 | removeClass("A", where = env) 90 | removeClass("B", where = env) 91 | removeClass("C", where = env) 92 | -------------------------------------------------------------------------------- /tests/testthat/test-parse-block.R: -------------------------------------------------------------------------------- 1 | context("Parse: block") 2 | 3 | test_that("parses into tag and value", { 4 | x <- tokenise_block("#' @xyz abc") 5 | expect_equal(length(x), 1) 6 | 7 | expect_equal(x[[1]]$tag, "xyz") 8 | expect_equal(x[[1]]$val, "abc") 9 | }) 10 | 11 | test_that("description block gets empty tag", { 12 | x <- tokenise_block("#' abc") 13 | expect_equal(length(x), 1) 14 | 15 | expect_equal(x[[1]]$tag, "") 16 | expect_equal(x[[1]]$val, "abc") 17 | }) 18 | 19 | test_that("multi line tags collapsed into one", { 20 | x <- tokenise_block(c( 21 | "#' @tag abc", 22 | "#' def" 23 | )) 24 | expect_equal(length(x), 1) 25 | expect_equal(x[[1]]$val, "abc\n def") 26 | }) 27 | 28 | test_that("description block gets empty tag when followed by tag", { 29 | x <- tokenise_block(c( 30 | "#' abc", 31 | "#' @xyz abc" 32 | )) 33 | expect_equal(length(x), 2) 34 | 35 | expect_equal(x[[1]]$tag, "") 36 | expect_equal(x[[1]]$val, "abc") 37 | 38 | expect_equal(x[[2]]$tag, "xyz") 39 | expect_equal(x[[2]]$val, "abc") 40 | }) 41 | 42 | test_that("leading whitespace is ignored", { 43 | ref <- tokenise_block("#' abc") 44 | 45 | expect_equal(tokenise_block(" #' abc"), ref) 46 | }) 47 | 48 | test_that("need one or more #", { 49 | ref <- tokenise_block("#' abc") 50 | 51 | expect_equal(tokenise_block("##' abc"), ref) 52 | expect_equal(tokenise_block("###' abc"), ref) 53 | }) 54 | 55 | test_that("@@ becomes @", { 56 | expect_equal(tokenise_block("#' @tag @@")[[1]]$val, "@") 57 | }) 58 | -------------------------------------------------------------------------------- /tests/testthat/test-parse.R: -------------------------------------------------------------------------------- 1 | context("Parse") 2 | 3 | # Inline comments --------------------------------------------------------- 4 | 5 | test_that("Inline comments are supported", { 6 | out <- roc_proc_text(rd_roclet(), " 7 | #' Description 8 | a <- function(x) { 9 | #' @param x an integer 10 | stopifnot(is.integer(x)) 11 | }")[[1]] 12 | expect_equal(get_tag(out, "param")$values, c(x = "an integer")) 13 | }) 14 | 15 | test_that("Inline comments just before the closing brace are allowed", { 16 | out <- roc_proc_text(rd_roclet(), " 17 | #' Description 18 | a <- function(x) { 19 | #' @param x an integer 20 | stopifnot(is.integer(x)) 21 | 22 | #' @seealso somewhere 23 | }")[[1]] 24 | expect_equal(get_tag(out, "seealso")$value, "somewhere") 25 | }) 26 | 27 | test_that("Inline comments do not extend past the closing brace", { 28 | out <- roc_proc_text(rd_roclet(), " 29 | #' Description 30 | a <- function(x) { 31 | #' @param x an integer 32 | stopifnot(is.integer(x)) 33 | }; #' @seealso somewhere")[[1]] 34 | expect_null(get_tag(out, "seealso")) 35 | }) 36 | 37 | 38 | # Intro block ------------------------------------------------------------- 39 | 40 | block_registry <- function() { 41 | block_test <- function(x) { 42 | x$val <- toupper(x$val) 43 | x 44 | } 45 | 46 | list( 47 | title = block_test, 48 | description = block_test, 49 | details = block_test 50 | ) 51 | } 52 | 53 | check <- function(out) { 54 | expect_equal( 55 | get_tag(out, "title"), 56 | roxy_field_simple("title", "TITLE") 57 | ) 58 | expect_equal( 59 | get_tag(out, "description"), 60 | roxy_field_simple("description", "DESCRIPTION") 61 | ) 62 | expect_equal( 63 | get_tag(out, "details"), 64 | roxy_field_simple("details", "DETAILS") 65 | ) 66 | } 67 | 68 | 69 | test_that("block parsers are called for tags from intro", { 70 | 71 | out <- roc_proc_text(rd_roclet(), " 72 | #' Title 73 | #' 74 | #' Description 75 | #' 76 | #' Details 77 | f <- function(foo) 'foo' 78 | ", registry = block_registry())[[1]] 79 | 80 | check(out) 81 | }) 82 | 83 | 84 | test_that("block parsers from intro & @title", { 85 | out <- roc_proc_text(rd_roclet(), " 86 | #' Description 87 | #' 88 | #' Details 89 | #' 90 | #' @title Title 91 | f <- function(foo) 'foo' 92 | ", registry = block_registry())[[1]] 93 | 94 | check(out) 95 | }) 96 | 97 | 98 | test_that("block parsers from intro & @description", { 99 | out <- roc_proc_text(rd_roclet(), " 100 | #' Title 101 | #' 102 | #' Details 103 | #' 104 | #' @description Description 105 | f <- function(foo) 'foo' 106 | ", registry = block_registry())[[1]] 107 | 108 | check(out) 109 | }) 110 | 111 | 112 | test_that("block parsers from intro & @details", { 113 | out <- roc_proc_text(rd_roclet(), " 114 | #' Title 115 | #' 116 | #' Description 117 | #' 118 | #' @details Details 119 | f <- function(foo) 'foo' 120 | ", registry = block_registry())[[1]] 121 | 122 | check(out) 123 | }) 124 | 125 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-alias.R: -------------------------------------------------------------------------------- 1 | context("Rd: alias") 2 | 3 | test_that("aliases split into pieces", { 4 | out <- roc_proc_text(rd_roclet(), " 5 | #' @aliases a b 6 | #' @title a 7 | #' @name a 8 | NULL")[[1]] 9 | 10 | expect_match(get_tag(out, "alias")$values, fixed("a"), all = FALSE) 11 | expect_match(get_tag(out, "alias")$values, fixed("b"), all = FALSE) 12 | }) 13 | 14 | test_that("aliases escaped, not quoted", { 15 | out1 <- roc_proc_text(rd_roclet(), " 16 | #' @name %a% 17 | #' @aliases a 18 | #' @title a 19 | NULL")[[1]] 20 | out2 <- roc_proc_text(rd_roclet(), " 21 | #' @name a 22 | #' @aliases %a% 23 | #' @title a 24 | NULL")[[1]] 25 | alias1 <- format(get_tag(out1, "alias")) 26 | alias2 <- format(get_tag(out2, "alias")) 27 | expect_equal(alias1, c("\\alias{\\%a\\%}", "\\alias{a}")) 28 | expect_equal(alias2, c("\\alias{a}", "\\alias{\\%a\\%}")) 29 | }) 30 | 31 | test_that("can use NULL to suppress default aliases", { 32 | out <- roc_proc_text(rd_roclet(), " 33 | #' @aliases NULL 34 | #' @title a 35 | #' @name a 36 | NULL")[[1]] 37 | 38 | expect_equal(get_tag(out, "alias")$values, character()) 39 | }) 40 | 41 | 42 | test_that("refclass with assignment gets both aliases", { 43 | out <- roc_proc_text(rd_roclet(), " 44 | #' Title 45 | B3 <- setRefClass('B3') 46 | ")[[1]] 47 | 48 | expect_equal(get_tag(out, "alias")$value, c("B3-class", "B3")) 49 | }) 50 | 51 | 52 | test_that("refclass gets -class alias", { 53 | out <- roc_proc_text(rd_roclet(), " 54 | #' Title 55 | setRefClass('B2') 56 | ")[[1]] 57 | 58 | expect_equal(get_tag(out, "alias")$value, "B2-class") 59 | }) 60 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-backref.R: -------------------------------------------------------------------------------- 1 | context("Rd: backref") 2 | test_that("Source reference is included as comment", { 3 | out <- roc_proc_text(rd_roclet(), " 4 | #' @name a 5 | #' @title a 6 | #' @docType package 7 | NULL") 8 | 9 | backref <- format(get_tag(out[[1]], "backref")) 10 | expect_match(backref, "^% Please edit documentation in ") 11 | }) 12 | 13 | test_that("Explicit @backref is included as comment", { 14 | out <- roc_proc_text(rd_roclet(), " 15 | #' @name a 16 | #' @title a 17 | #' @backref back/ref.file 18 | #' @backref root.file 19 | #' @docType package 20 | NULL") 21 | 22 | backref <- format(get_tag(out[[1]], "backref")) 23 | expect_match(backref, "^% Please edit documentation in back/ref[.]file, [.]/root[.]file") 24 | }) 25 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-data.R: -------------------------------------------------------------------------------- 1 | context("Rd: data") 2 | 3 | test_that("can document eager data", { 4 | test_pkg <- temp_copy_pkg('testEagerData') 5 | on.exit(unlink(test_pkg, recursive = TRUE)) 6 | 7 | expect_output(devtools::document(test_pkg), "a[.]Rd") 8 | expect_true(file.exists(file.path(test_pkg, "man", "a.Rd"))) 9 | }) 10 | 11 | test_that("can document lazy data", { 12 | test_pkg <- temp_copy_pkg('testLazyData') 13 | on.exit(unlink(test_pkg, recursive = TRUE)) 14 | 15 | expect_output(devtools::document(test_pkg), "a[.]Rd") 16 | expect_true(file.exists(file.path(test_pkg, "man", "a.Rd"))) 17 | }) 18 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-describein.R: -------------------------------------------------------------------------------- 1 | context("Rd: describeIn") 2 | 3 | test_that("@describeIn generic captures s3 method class", { 4 | out <- roc_proc_text(rd_roclet(), " 5 | #' Title 6 | f <- function(x) UseMethod('f') 7 | 8 | #' @describeIn f Method for a 9 | #' 10 | f.a <- function(x) 1 11 | ")[[1]] 12 | 13 | expect_equal(get_tag(out, "minidesc")$type, "generic") 14 | expect_equal(get_tag(out, "minidesc")$label, "a") 15 | }) 16 | 17 | test_that("@describeIn generic captures s4 method class", { 18 | out <- roc_proc_text(rd_roclet(), " 19 | #' Title 20 | setGeneric('f', function(x) standardGeneric('f')) 21 | 22 | #' @describeIn f Method for a 23 | setMethod(f, signature('a'), function(x) 1) 24 | ")[[1]] 25 | 26 | expect_equal(get_tag(out, "minidesc")$label, "a") 27 | }) 28 | 29 | test_that("@describeIn class captures s3 generic name", { 30 | out <- roc_proc_text(rd_roclet(), " 31 | #' Title 32 | boo <- function() structure(list(), class = 'boo') 33 | 34 | #' @describeIn boo mean method 35 | #' 36 | mean.boo <- function(x) 1 37 | ")[[1]] 38 | 39 | expect_equal(get_tag(out, "minidesc")$label, "mean") 40 | }) 41 | 42 | test_that("@describeIn class captures s4 generic name", { 43 | out <- roc_proc_text(rd_roclet(), " 44 | setGeneric('mean') 45 | 46 | #' Title 47 | setClass('a') 48 | 49 | #' @describeIn a mean method 50 | setMethod('mean', 'a', function(x) 1) 51 | ")[[1]] 52 | 53 | expect_equal(get_tag(out, "minidesc")$label, "mean") 54 | }) 55 | 56 | test_that("Multiple @describeIn generic combined into one", { 57 | out <- roc_proc_text(rd_roclet(), " 58 | #' Title 59 | f <- function(x) UseMethod('f') 60 | 61 | #' @describeIn f A 62 | f.a <- function(x) 1 63 | 64 | #' @describeIn f B 65 | f.b <- function(x) 1 66 | ")[[1]] 67 | 68 | expect_equal(get_tag(out, "minidesc")$type, "generic") 69 | expect_equal(get_tag(out, "minidesc")$label, c("a", "b")) 70 | expect_equal(get_tag(out, "minidesc")$desc, c("A", "B")) 71 | }) 72 | 73 | test_that("@describeIn class captures function name", { 74 | out <- roc_proc_text(rd_roclet(), " 75 | #' Title 76 | f <- function(x) 1 77 | 78 | #' @describeIn f A 79 | f2 <- function(x) 1 80 | ")[[1]] 81 | 82 | expect_equal(get_tag(out, "minidesc")$label, "f2") 83 | }) 84 | 85 | test_that("@describeIn class captures function name with data", { 86 | out <- roc_proc_text(rd_roclet(), " 87 | #' Title 88 | #' @name f 89 | NULL 90 | 91 | #' @describeIn f A 92 | f2 <- function(x) 1 93 | ")[[1]] 94 | 95 | expect_equal(get_tag(out, "minidesc")$label, "f2") 96 | }) 97 | 98 | test_that("function names are escaped", { 99 | out <- roc_proc_text(rd_roclet(), " 100 | #' foo 101 | foo <- 100 102 | 103 | #' @describeIn foo shortcut for foo 104 | `%foo%` <- function(x, y) foo(x, y) 105 | ")[[1]] 106 | expect_match(format(get_tag(out, "minidesc")), "\\\\%foo\\\\%") 107 | }) 108 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-doctype.R: -------------------------------------------------------------------------------- 1 | context("Rd: docType") 2 | 3 | # Package -------------------------------------------------------------------- 4 | 5 | test_that("@docType package automatically adds package alias when needed", { 6 | out <- roc_proc_text(rd_roclet(), " 7 | #' @name a 8 | #' @title a 9 | #' @docType package 10 | NULL 11 | 12 | #' @name a-package 13 | #' @title a 14 | #' @docType package 15 | NULL") 16 | 17 | alias_1 <- get_tag(out[[1]], "alias")$values 18 | expect_equal(alias_1, c("a", "a-package")) 19 | 20 | alias_2 <- get_tag(out[[2]], "alias")$values 21 | expect_equal(alias_2, c("a-package")) 22 | }) 23 | 24 | 25 | # Data -------------------------------------------------------------------- 26 | 27 | test_that("@docType data automatically adds sensible defaults", { 28 | out <- roc_proc_text(rd_roclet(), " 29 | #' Title. 30 | #' 31 | #' @docType data 32 | a <- data.frame(a = 1:10)")[[1]] 33 | 34 | expect_equal(get_tag(out, "usage")$values, "a") 35 | expect_equal(get_tag(out, "keyword")$values, "datasets") 36 | expect_equal(is.null(get_tag(out, "format")$values), FALSE) 37 | }) 38 | 39 | test_that("@docType data automatically added to data objects", { 40 | out <- roc_proc_text(rd_roclet(), " 41 | #' Title. 42 | a <- data.frame(a = 1:10)")[[1]] 43 | 44 | expect_equal(get_tag(out, "docType")$values, "data") 45 | }) 46 | 47 | test_that("@docType data automatically added to data objects created elsewhere", { 48 | out <- roc_proc_text(rd_roclet(), " 49 | a <- data.frame(a = 1:10) 50 | #' Title. 51 | 'a'")[[1]] 52 | 53 | expect_equal(get_tag(out, "docType")$values, "data") 54 | expect_equal(get_tag(out, "usage")$values, "a") 55 | expect_equal(get_tag(out, "keyword")$values, "datasets") 56 | }) 57 | 58 | 59 | # Reference classes ---------------------------------------------------------- 60 | 61 | test_that("@docType class automatically added to reference class objects", { 62 | out <- roc_proc_text(rd_roclet(), " 63 | #' Title. 64 | #' 65 | a <- setRefClass('a')")[[1]] 66 | 67 | expect_equal(get_tag(out, "class")$values, NULL) 68 | }) 69 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-examples.R: -------------------------------------------------------------------------------- 1 | context("Rd: examples") 2 | 3 | test_that("@example loads from specified files", { 4 | out <- roc_proc_text(rd_roclet(), " 5 | #' @name a 6 | #' @title a 7 | #' 8 | #' @example Rd-example-1.R 9 | #' @example Rd-example-2.R 10 | NULL")[[1]] 11 | 12 | examples <- get_tag(out, "examples")$values 13 | expect_match(examples, fixed("example <- 'example1'"), all = FALSE) 14 | expect_match(examples, fixed("example <- 'example2'"), all = FALSE) 15 | }) 16 | 17 | test_that("@examples captures examples", { 18 | out <- roc_proc_text(rd_roclet(), " 19 | #' @name a 20 | #' @title a 21 | #' 22 | #' @examples a <- 2 23 | #' 24 | NULL")[[1]] 25 | 26 | examples <- get_tag(out, "examples")$values 27 | expect_match(examples, fixed("a <- 2"), all = FALSE) 28 | }) 29 | 30 | test_that("@examples and @example combine", { 31 | out <- roc_proc_text(rd_roclet(), " 32 | #' @name a 33 | #' @title a 34 | #' @example Rd-example-1.R 35 | #' @examples a <- 2 36 | NULL")[[1]] 37 | 38 | examples <- get_tag(out, "examples")$values 39 | expect_match(examples, fixed("example <- 'example1'"), all = FALSE) 40 | expect_match(examples, fixed("a <- 2"), all = FALSE) 41 | }) 42 | 43 | test_that("@example does not introduce extra empty lines", { 44 | out <- roc_proc_text(rd_roclet(), " 45 | #' @name a 46 | #' @title a 47 | #' @example Rd-example-3.R 48 | NULL")[[1]] 49 | 50 | examples <- get_tag(out, "examples")$values 51 | expect_identical(length(examples), 2L) 52 | }) 53 | 54 | test_that("@example gives warning if used instead of @examples", { 55 | expect_warning( 56 | out <- roc_proc_text(rd_roclet(), " 57 | #' @name a 58 | #' @title a 59 | #' @example 60 | #' a <- 1 61 | #' a + b 62 | NULL")[[1]], 63 | "@example spans multiple lines" 64 | ) 65 | 66 | expect_null(get_tag(out, "examples")$values, NULL) 67 | }) 68 | 69 | 70 | test_that("indentation in examples preserved", { 71 | out <- roc_proc_text(rd_roclet(), " 72 | #' @name a 73 | #' @title a 74 | #' @examples a <- 75 | #' 2 76 | NULL")[[1]] 77 | 78 | examples <- get_tag(out, "examples")$values 79 | expect_match(examples, fixed("a <-\n 2"), all = FALSE) 80 | }) 81 | 82 | test_that("% and \\ in @example escaped", { 83 | out <- roc_proc_text(rd_roclet(), " 84 | #' @name a 85 | #' @title a 86 | #' @example Rd-example-4.R 87 | NULL")[[1]] 88 | 89 | examples <- get_tag(out, "examples")$values 90 | expect_equal(examples, rd("x \\%*\\% y # \\\\x")) 91 | }) 92 | 93 | test_that("\\dontrun in @example unescaped", { 94 | out <- roc_proc_text(rd_roclet(), " 95 | #' @name a 96 | #' @title a 97 | #' @example Rd-example-5.R 98 | NULL")[[1]] 99 | 100 | examples <- get_tag(out, "examples")$values 101 | expect_equal(examples, rd("\\dontrun{x <- 1}")) 102 | }) 103 | 104 | test_that("% in @examples escaped before matching braces test (#213)", { 105 | out <- roc_proc_text(rd_roclet(), " 106 | #' @name a 107 | #' @title a 108 | #' @examples 109 | #' {a %% b} 110 | NULL")[[1]] 111 | 112 | examples <- get_tag(out, "examples")$values 113 | expect_equal(examples, rd("{a \\%\\% b}")) 114 | }) 115 | 116 | test_that("multiple examples (#470)", { 117 | out <- roc_proc_text(rd_roclet(), " 118 | #' @name a 119 | #' @title a 120 | #' @examples 121 | #' TRUE 122 | #' @examples 123 | #' FALSE 124 | NULL")[[1]] 125 | 126 | examples <- get_tag(out, "examples")$values 127 | expect_equal(examples, rd(c("TRUE", "FALSE"))) 128 | }) 129 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-family.R: -------------------------------------------------------------------------------- 1 | context("Rd: family") 2 | 3 | test_that("long families are wrapped", { 4 | out <- roc_proc_text(rd_roclet(), " 5 | #' Title 6 | #' @family Long family name 7 | #' 8 | long_function_name_________________________1 <- function() {} 9 | 10 | #' Title 11 | #' @family Long family name 12 | long_function_name_________________________2 <- function() {} 13 | 14 | #' Title 15 | #' @family Long family name 16 | #' 17 | long_function_name_________________________3 <- function() {} 18 | 19 | #' Title 20 | #' @family Long family name 21 | long_function_name_________________________4 <- function() {} 22 | ")[[1]] 23 | 24 | seealso <- get_tag(out, "seealso")$values 25 | expect_true(grepl("^Other Long family name:", seealso)) 26 | expect_equal(str_count(seealso, "\n"), 2) 27 | 28 | }) 29 | 30 | test_that("special names escaped in family tag", { 31 | out <- roc_proc_text(rd_roclet(), " 32 | #' Title 33 | #' @family Long family name 34 | f <- function() {} 35 | 36 | #' Title 37 | #' @family Long family name 38 | '%+%' <- function(a, b) {} 39 | ")[[1]] 40 | 41 | seealso <- get_tag(out, "seealso")$values 42 | expect_true(grepl("^Other Long family name:", seealso)) 43 | expect_match(seealso, "\\\\%\\+\\\\%") 44 | 45 | }) 46 | 47 | test_that("family links to name only, not all aliases", { 48 | out <- roc_proc_text(rd_roclet(), " 49 | #' Title 50 | #' @aliases f2 f3 51 | #' 52 | #' @family many aliases 53 | f <- function() {} 54 | 55 | #' Title 56 | #' @aliases g2 g3 57 | #' 58 | #' @family many aliases 59 | g <- function() {} 60 | ")[[1]] 61 | 62 | seealso <- get_tag(out, "seealso")$values 63 | expect_true(grepl("^Other many aliases:", seealso)) 64 | expect_equal(str_count(seealso, fixed("\\code{\\link")), 1) 65 | 66 | }) 67 | 68 | test_that("families listed in same order as input", { 69 | out <- roc_proc_text(rd_roclet(), " 70 | #' foo 71 | #' @family a 72 | foo <- function() {} 73 | 74 | #' foo 75 | #' @family b 76 | #' @family a 77 | bar <- function() {} 78 | 79 | #' foo 80 | #' @family b 81 | baz <- function() {} 82 | ")[[2]] 83 | 84 | seealso <- get_tag(out, "seealso")$values 85 | expect_match(seealso[1], "^Other b") 86 | expect_match(seealso[2], "^Other a") 87 | }) 88 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-field.R: -------------------------------------------------------------------------------- 1 | context("Rd: field") 2 | 3 | test_that("@fields creates a new section and lists fields", { 4 | out <- roc_proc_text(rd_roclet(), " 5 | #' Important class. 6 | #' 7 | #' @field a field a 8 | #' 9 | #' @field b field b 10 | #' 11 | setRefClass('test') 12 | ")[[1]] 13 | expect_equal(get_tag(out, "field")$values, c(a = "field a", b = "field b")) 14 | }) 15 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-introduction.R: -------------------------------------------------------------------------------- 1 | context("Rd: introduction") 2 | 3 | test_that("title and description taken from first line if only one", { 4 | out <- roc_proc_text(rd_roclet(), " 5 | #' description 6 | #' @name a 7 | NULL")[[1]] 8 | expect_equal(get_tag(out, "description")$values, "description") 9 | expect_equal(get_tag(out, "title")$values, "description") 10 | }) 11 | 12 | test_that("title, description and details extracted correctly", { 13 | out <- roc_proc_text(rd_roclet(), " 14 | #' title 15 | #' 16 | #' description 17 | #' 18 | #' details 19 | #' @name a 20 | NULL")[[1]] 21 | expect_equal(get_tag(out, "description")$values, "description") 22 | expect_equal(get_tag(out, "details")$values, "details") 23 | }) 24 | 25 | test_that("title taken from first paragraph", { 26 | out <- roc_proc_text(rd_roclet(), " 27 | #' Description with sentence. 28 | #' 29 | #' That continueth. 30 | #' @name a 31 | NULL")[[1]] 32 | expect_equal(get_tag(out, "title")$values, "Description with sentence.") 33 | expect_equal(get_tag(out, "description")$values, 34 | "That continueth.") 35 | }) 36 | 37 | test_that("@title overrides default title", { 38 | out <- roc_proc_text(rd_roclet(), " 39 | #' Would be title 40 | #' @title Overridden title 41 | #' @name a 42 | NULL")[[1]] 43 | expect_equal(get_tag(out, "title")$values, "Overridden title") 44 | expect_equal(get_tag(out, "description")$values, "Would be title") 45 | }) 46 | 47 | test_that("docs parsed correctly if no blank text", { 48 | out <- roc_proc_text(rd_roclet(), " 49 | #' @title My title 50 | #' @description My description 51 | #' @param x value 52 | a <- function(x) {}")[[1]] 53 | 54 | expect_equal(get_tag(out, "title")$values, "My title") 55 | expect_equal(get_tag(out, "description")$values, "My description") 56 | }) 57 | 58 | test_that("question mark ends sentence", { 59 | out <- roc_proc_text(rd_roclet(), " 60 | #' Is a number odd? 61 | is.odd <- function(a) {}")[[1]] 62 | expect_equal(get_tag(out, "title")$values, "Is a number odd?") 63 | 64 | }) 65 | 66 | test_that("no ending punctuation does not produce ellipsis", { 67 | out <- roc_proc_text(rd_roclet(), " 68 | #' Whether a number is odd 69 | is.odd <- function(a) {}")[[1]] 70 | expect_equal(get_tag(out, "title")$values, "Whether a number is odd") 71 | }) 72 | 73 | test_that("details are merged if needed", { 74 | out <- roc_proc_text(rd_roclet(), " 75 | #' Title 76 | #' 77 | #' Description 78 | #' 79 | #' Details1 80 | #' 81 | #' Details2 82 | #' 83 | #' @details Details3 84 | #' 85 | #' Details4 86 | foo <- function(x) {}")[[1]] 87 | 88 | expect_equal(get_tag(out, "details")$values, 89 | "Details1\n\nDetails2\n\nDetails3\n\nDetails4") 90 | }) 91 | 92 | test_that("whitespace is not detected as details", { 93 | expect_silent( 94 | out <- roc_proc_text( 95 | rd_roclet(), " 96 | #' Title 97 | #' 98 | #' 99 | #' Description 100 | #' 101 | #' 102 | #' 103 | foo <- function(x) {}" 104 | )[[1]] 105 | ) 106 | 107 | expect_null(get_tag(out, "details")) 108 | }) 109 | 110 | 111 | test_that("@description and @details are merged", { 112 | out <- roc_proc_text(rd_roclet(), " 113 | #' Foo 114 | #' 115 | #' This. 116 | #' 117 | #' OBTW. 118 | foo <- function(x = '%') x 119 | 120 | #' @rdname foo 121 | #' @description And that. 122 | #' @details ORLY? 123 | bar <- function(y = '%') y 124 | ")[[1]] 125 | 126 | expect_equal(get_tag(out, "description")$values, c("This.", "And that.")) 127 | expect_equal(get_tag(out, "details")$values, c("OBTW.", "ORLY?")) 128 | }) 129 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-keyword.R: -------------------------------------------------------------------------------- 1 | context("Rd: keyword") 2 | 3 | test_that("keywords split into pieces", { 4 | out <- roc_proc_text(rd_roclet(), " 5 | #' @keywords a b 6 | #' @title a 7 | #' @name a 8 | NULL")[[1]] 9 | 10 | expect_match(get_tag(out, "keyword")$values, fixed("a"), all = FALSE) 11 | expect_match(get_tag(out, "keyword")$values, fixed("b"), all = FALSE) 12 | }) 13 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-markdown-escaping.R: -------------------------------------------------------------------------------- 1 | context("Rd: markdown escaping") 2 | 3 | tag_df <- function(tag, start, end, argend = NULL) { 4 | df <- data.frame( 5 | stringsAsFactors = FALSE, 6 | tag = tag, start = start, end = end 7 | ) 8 | if (!is.null(argend)) df$argend <- argend 9 | df 10 | } 11 | 12 | test_that("find_all_tag_names", { 13 | 14 | text <- "blah blah \\mytag blah blah" 15 | expect_equal( 16 | find_all_tag_names(text), 17 | tag_df("\\mytag", 11, 16) 18 | ) 19 | }) 20 | 21 | test_that("find_all_rd_tags", { 22 | 23 | cases <- list( 24 | ## No tags 25 | list("", character(), numeric(), numeric(), numeric()), 26 | list("nothing to see here", 27 | character(), numeric(), numeric(), numeric()), 28 | list("\nstill\nnothing\n", 29 | character(), numeric(), numeric(), numeric()), 30 | 31 | ## One tag 32 | list("blah blah \\mytag blah blah", "\\mytag", 11, 16, 16), 33 | list("blah blah \\mytag{arg1} blah blah", 34 | "\\mytag", 11, 16, 22), 35 | list("blah blah \\mytag{arg1}{arg2} blah blah", 36 | "\\mytag", 11, 16, 28), 37 | list("blah\\mytag", "\\mytag", 5, 10, 10), 38 | list("blah \\mytag", "\\mytag", 6, 11, 11), 39 | list("blah\\mytag{arg}", "\\mytag", 5, 10, 15), 40 | list("\\mytag hoohoo", "\\mytag", 1, 6, 6), 41 | list("\\mytag", "\\mytag", 1, 6, 6), 42 | list("\\mytag{arg}", "\\mytag", 1, 6, 11), 43 | list("blah \\mytag\nblah blah", "\\mytag", 6, 11, 11), 44 | 45 | ## Multiple tags 46 | list("blah \\tag1 \\tag2{arg} blah", c("\\tag1", "\\tag2"), 47 | c(6, 12), c(10, 16), c(10, 21)), 48 | list("blah \\tag1{ \\tag2{arg} } blah", c("\\tag1", "\\tag2"), 49 | c(6, 13), c(10, 17), c(24, 22)), 50 | list("blah \\tag1{\n\\tag2{arg}\n} blah", c("\\tag1", "\\tag2"), 51 | c(6, 13), c(10, 17), c(24, 22)) 52 | ) 53 | 54 | for (case in cases) { 55 | expect_equal( 56 | find_all_rd_tags(case[[1]]), 57 | do.call(tag_df, case[-1]), 58 | info = case[[1]] 59 | ) 60 | } 61 | 62 | }) 63 | 64 | test_that("find_fragile_rd_tags", { 65 | 66 | fragile <- c("\\frag", "\\frag1", "\\frag2") 67 | 68 | cases <- list( 69 | list("This is \\frag{here}, \\this{arg} not", "\\frag"), 70 | list("Embedded \\frag{ into \\frag1{arg} plus }", "\\frag"), 71 | list( 72 | "blah \\cmd{ \\frag{arg} \\frag{arg} } \\frag2 blah", 73 | c("\\frag", "\\frag", "\\frag2") 74 | ) 75 | ) 76 | 77 | for (case in cases) { 78 | expect_equal( 79 | find_fragile_rd_tags(case[[1]], fragile)$tag, 80 | case[[2]], 81 | info = case[[1]] 82 | ) 83 | } 84 | 85 | }) 86 | 87 | 88 | test_that("str_sub_same", { 89 | 90 | expect_equal( 91 | str_sub_same( 92 | "123456789ab", 93 | data.frame(start = c(1,6), end = c(2,10), argend = c(2,10)), 94 | "xxx" 95 | ), 96 | "xxx-1-345xxx-2-b" 97 | ) 98 | 99 | expect_equal( 100 | str_sub_same( 101 | "123456789ab", 102 | data.frame(start = c(1,8), end = c(7,10), argend = c(7,10)), 103 | "xxx" 104 | ), 105 | "xxx-1-xxx-2-b", 106 | ) 107 | 108 | expect_equal( 109 | str_sub_same( 110 | "123456789ab", 111 | data.frame(start = numeric(), end = numeric(), 112 | argend = numeric()), 113 | "xxx" 114 | ), 115 | "123456789ab" 116 | ) 117 | 118 | }) 119 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-markdown-on-off.R: -------------------------------------------------------------------------------- 1 | context("Rd: turning markdown on/off") 2 | roc <- rd_roclet() 3 | 4 | test_that("turning on/off markdown globally", { 5 | ## off 6 | out1 <- roc_proc_text(roc, global_options = list(markdown = FALSE), " 7 | #' Title 8 | #' 9 | #' Description with some `code` included. `More code.` 10 | foo <- function() {}")[[1]] 11 | expect_equal( 12 | get_tag(out1, "description")$values, 13 | "Description with some `code` included. `More code.`" 14 | ) 15 | 16 | ## on 17 | out1 <- roc_proc_text(roc, global_options = list(markdown = TRUE), " 18 | #' Title 19 | #' 20 | #' Description with some `code` included. `More code.` 21 | foo <- function() {}")[[1]] 22 | expect_equal( 23 | get_tag(out1, "description")$values, 24 | "Description with some \\code{code} included. \\code{More code.}" 25 | ) 26 | }) 27 | 28 | test_that("turning on/off markdown locally", { 29 | ## off / off 30 | out1 <- roc_proc_text(roc, global_options = list(markdown = FALSE), " 31 | #' Title 32 | #' 33 | #' Description with some `code` included. `More code.` 34 | #' @noMd 35 | foo <- function() {}")[[1]] 36 | expect_equal( 37 | get_tag(out1, "description")$values, 38 | "Description with some `code` included. `More code.`" 39 | ) 40 | 41 | ## off / on 42 | out1 <- roc_proc_text(roc, global_options = list(markdown = FALSE), " 43 | #' Title 44 | #' 45 | #' Description with some `code` included. `More code.` 46 | #' @md 47 | foo <- function() {}")[[1]] 48 | expect_equal( 49 | get_tag(out1, "description")$values, 50 | "Description with some \\code{code} included. \\code{More code.}" 51 | ) 52 | 53 | ## on / off 54 | out1 <- roc_proc_text(roc, global_options = list(markdown = TRUE), " 55 | #' Title 56 | #' 57 | #' Description with some `code` included. `More code.` 58 | #' @noMd 59 | foo <- function() {}")[[1]] 60 | expect_equal( 61 | get_tag(out1, "description")$values, 62 | "Description with some `code` included. `More code.`" 63 | ) 64 | 65 | ## on / on 66 | out1 <- roc_proc_text(roc, global_options = list(markdown = TRUE), " 67 | #' Title 68 | #' 69 | #' Description with some `code` included. `More code.` 70 | #' @md 71 | foo <- function() {}")[[1]] 72 | expect_equal( 73 | get_tag(out1, "description")$values, 74 | "Description with some \\code{code} included. \\code{More code.}" 75 | ) 76 | 77 | }) 78 | 79 | test_that("warning for both @md and @noMd", { 80 | 81 | expect_warning( 82 | out1 <- roc_proc_text(roc, " 83 | #' Title 84 | #' 85 | #' Description with some `code` included. `More code.` 86 | #' @md 87 | #' @noMd 88 | foo <- function() {}")[[1]], 89 | "Both @md and @noMd, no markdown parsing" 90 | ) 91 | expect_equal( 92 | get_tag(out1, "description")$values, 93 | "Description with some `code` included. `More code.`" 94 | ) 95 | 96 | expect_warning( 97 | out1 <- roc_proc_text(roc, global_options = list(markdown = FALSE), " 98 | #' Title 99 | #' 100 | #' Description with some `code` included. `More code.` 101 | #' @md 102 | #' @noMd 103 | foo <- function() {}")[[1]], 104 | "Both @md and @noMd, no markdown parsing" 105 | ) 106 | expect_equal( 107 | get_tag(out1, "description")$values, 108 | "Description with some `code` included. `More code.`" 109 | ) 110 | 111 | expect_warning( 112 | out1 <- roc_proc_text(roc, global_options = list(markdown = TRUE), " 113 | #' Title 114 | #' 115 | #' Description with some `code` included. `More code.` 116 | #' @md 117 | #' @noMd 118 | foo <- function() {}")[[1]], 119 | "Both @md and @noMd, no markdown parsing" 120 | ) 121 | expect_equal( 122 | get_tag(out1, "description")$values, 123 | "Description with some `code` included. `More code.`" 124 | ) 125 | 126 | }) 127 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-name.R: -------------------------------------------------------------------------------- 1 | context("Rd: name") 2 | 3 | test_that("name captured from assignment", { 4 | out <- roc_proc_text(rd_roclet(), " 5 | #' Title. 6 | a <- function() {} ")[[1]] 7 | 8 | expect_equal(get_tag(out, "name")$values, "a") 9 | expect_equal(get_tag(out, "alias")$values, "a") 10 | expect_equal(get_tag(out, "title")$values, "Title.") 11 | }) 12 | 13 | test_that("name also captured from assignment by =", { 14 | out <- roc_proc_text(rd_roclet(), " 15 | #' Title. 16 | a = function() {} ")[[1]] 17 | 18 | expect_equal(get_tag(out, "name")$values, "a") 19 | expect_equal(get_tag(out, "alias")$values, "a") 20 | expect_equal(get_tag(out, "title")$values, "Title.") 21 | }) 22 | 23 | 24 | test_that("`$` not to be parsed as assignee in foo$bar(a = 1)", { 25 | out <- roc_proc_text(rd_roclet(), " 26 | #' foo object 27 | foo <- list(bar = function(a) a) 28 | foo$bar(a = 1)")[[1]] 29 | 30 | expect_equal(get_tag(out, "name")$values, "foo") 31 | }) 32 | 33 | 34 | test_that("names escaped, not quoted", { 35 | out <- roc_proc_text(rd_roclet(), " 36 | #' Title 37 | '%a%' <- function(x, y) x + y")[[1]] 38 | expect_equal(format(get_tag(out, "name")), "\\name{\\%a\\%}") 39 | }) 40 | 41 | test_that("quoted names captured from assignment", { 42 | out <- roc_proc_text(rd_roclet(), " 43 | #' Title. 44 | \"myfunction\" <- function(...) {}")[[1]] 45 | 46 | expect_equal(get_tag(out, "name")$values, "myfunction") 47 | expect_equal(get_tag(out, "alias")$values, "myfunction") 48 | 49 | out <- roc_proc_text(rd_roclet(), " 50 | #' Title. 51 | `myfunction` <- function(...) {}")[[1]] 52 | expect_equal(get_tag(out, "name")$values, "myfunction") 53 | expect_equal(get_tag(out, "alias")$values, "myfunction") 54 | 55 | out <- roc_proc_text(rd_roclet(), " 56 | #' Title. 57 | \"my function\" <- function(...) {}")[[1]] 58 | 59 | expect_equal(get_tag(out, "name")$values, "my function") 60 | expect_equal(get_tag(out, "alias")$values, "my function") 61 | }) 62 | 63 | test_that("@name overides default", { 64 | out <- roc_proc_text(rd_roclet(), " 65 | #' A 66 | #' @name b 67 | a <- function() {}")[[1]] 68 | 69 | expect_equal(get_tag(out, "name")$values, "b") 70 | expect_equal(sort(get_tag(out, "alias")$values), c("a", "b")) 71 | }) 72 | 73 | test_that("refclass topicname has class prefix", { 74 | env <- pkg_env() 75 | setRefClass("X1", where = env) 76 | on.exit(removeClass("X1", where = env)) 77 | obj <- object(getClass("X1", where = env)) 78 | expect_equal(object_topic(obj), "X1-class") 79 | }) 80 | 81 | test_that("class topicname has class prefix", { 82 | env <- pkg_env() 83 | setClass("Y1", where = env) 84 | on.exit(removeClass("Y1", where = env)) 85 | obj <- object(getClass("Y1", where = env)) 86 | expect_equal(object_topic(obj), "Y1-class") 87 | }) 88 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-package.R: -------------------------------------------------------------------------------- 1 | context("Rd: package") 2 | 3 | test_that("can create package documentation", { 4 | with_mock( 5 | `roxygen2::read.description` = function(...) 6 | list(Package = "roxygen_devtest", 7 | Title = "Package Title", 8 | Description = "Package description."), 9 | out <- roc_proc_text(rd_roclet(), " 10 | #' @details Details. 11 | '_PACKAGE'")[[1]] 12 | ) 13 | expect_equal(get_tag(out, "name")$values, "roxygen_devtest-package") 14 | expect_equal(get_tag(out, "alias")$values, c("roxygen_devtest", 15 | "roxygen_devtest-package")) 16 | expect_equal(get_tag(out, "title")$values, "roxygen_devtest: Package Title") 17 | expect_equal(get_tag(out, "description")$values, "Package description.") 18 | expect_equal(get_tag(out, "docType")$values, "package") 19 | expect_equal(get_tag(out, "details")$values, "Details.") 20 | }) 21 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-param.R: -------------------------------------------------------------------------------- 1 | context("Rd: param") 2 | 3 | test_that("@param documents arguments", { 4 | out <- roc_proc_text(rd_roclet(), " 5 | #' A 6 | #' @param a an incipit letter 7 | #' @param z a terminal letter 8 | a <- function(a=1, z=2) {}")[[1]] 9 | 10 | args <- get_tag(out, "param")$values 11 | expect_equivalent(args["a"], "an incipit letter") 12 | expect_equivalent(args["z"], "a terminal letter") 13 | }) 14 | 15 | test_that("grouped args get spaces", { 16 | out <- roc_proc_text(rd_roclet(), " 17 | #' A 18 | #' @param a,z Two arguments an incipit letter 19 | a <- function(a=1, z=2) {}")[[1]] 20 | 21 | args <- get_tag(out, "param") 22 | expect_match(format(args), "a, z") 23 | }) 24 | 25 | 26 | test_that("data objects don't get params", { 27 | out <- roc_proc_text(rd_roclet(), " 28 | #' x 29 | #' @rdname xy 30 | x <- 'x' 31 | ")[[1]] 32 | expect_equal(get_tag(out, "param"), NULL) 33 | 34 | }) 35 | 36 | test_that("find_params parses input", { 37 | params <- find_params("utils::`?`", NULL) 38 | expect_equal(names(params), c("topic", "type")) 39 | }) 40 | 41 | 42 | 43 | test_that("argument order for multi-parameter documentation", { 44 | out <- roc_proc_text(rd_roclet(), " 45 | #' A. 46 | #' 47 | #' @param x,y X,Y 48 | a <- function(x, y) {} 49 | 50 | #' B 51 | #' 52 | #' @param y Y 53 | #' @param x,z X,Z 54 | #' @param w W 55 | b <- function(x, y, z, w) {} 56 | ") 57 | 58 | expect_equal(get_tag(out[["a.Rd"]], "param")$values, c(`x,y`="X,Y")) 59 | expect_equal(get_tag(out[["b.Rd"]], "param")$values, c(`x,z`="X,Z", y="Y", w="W")) 60 | }) 61 | 62 | test_that("argument order for multiple usage statements", { 63 | out <- roc_proc_text(rd_roclet(), " 64 | #' A. 65 | #' 66 | #' @usage a(x, w) 67 | #' @usage a(x, y) 68 | #' @usage a(x, z) 69 | #' @param x X 70 | #' @param w W 71 | #' @param y Y 72 | #' @param z Z 73 | a <- function(x, y, z, w) {} 74 | ") 75 | 76 | expect_equal(get_tag(out[["a.Rd"]], "param")$values, c(x="X", y="Y", z="Z", w="W")) 77 | }) 78 | 79 | test_that("argument order for @rdfile", { 80 | out <- roc_proc_text(rd_roclet(), " 81 | #' A 82 | #' 83 | #' @param x X 84 | #' @param y Y 85 | #' @rdname rd 86 | a <- function(x, y) { 87 | } 88 | 89 | #' B 90 | #' 91 | #' @export 92 | #' @rdname rd 93 | b <- function(y, ...) { 94 | } 95 | ") 96 | 97 | expect_equal(get_tag(out[["rd.Rd"]], "param")$values, c(x="X", y="Y")) 98 | }) 99 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-raw.R: -------------------------------------------------------------------------------- 1 | context("Rd: raw output") 2 | 3 | test_that("rawRd inserted unchanged", { 4 | out <- roc_proc_text(rd_roclet(), " 5 | #' @rawRd #this is a comment 6 | #' @name a 7 | #' @title a 8 | NULL")[[1]] 9 | 10 | lines <- strsplit(format(out), "\n")[[1]] 11 | expect_equal(lines[[6]], "#this is a comment") 12 | }) 13 | 14 | test_that("evalRd must be valid code", { 15 | expect_warning( 16 | roc_proc_text(rd_roclet(), " 17 | #' @evalRd a + 18 | #' @name a 19 | #' @title a 20 | NULL"), 21 | "code failed to parse" 22 | ) 23 | }) 24 | 25 | test_that("error-ful evalRd generates warning", { 26 | expect_warning( 27 | roc_proc_text(rd_roclet(), " 28 | #' @evalRd stop('!') 29 | #' @name a 30 | #' @title a 31 | NULL"), 32 | "@evalRd failed with error" 33 | ) 34 | }) 35 | 36 | test_that("evalRd inserted unchanged", { 37 | out <- roc_proc_text(rd_roclet(), " 38 | z <- 10 39 | #' @evalRd z * 2 40 | #' @name a 41 | #' @title a 42 | NULL")[[1]] 43 | 44 | args <- get_tag(out, "rawRd")$values 45 | expect_equal(args, "20") 46 | }) 47 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-section.R: -------------------------------------------------------------------------------- 1 | context("Rd: section") 2 | 3 | test_that("warn if forgotton colom", { 4 | expect_warning( 5 | roc_proc_text(rd_roclet(), " 6 | #' Foo 7 | #' 8 | #' @section Haz dox 9 | #' Here. 10 | #' There 11 | foo <- function(x = '%') x 12 | "), 13 | "Section title spans multiple lines" 14 | ) 15 | }) 16 | 17 | 18 | test_that("@section-s with identical titles are merged", { 19 | out <- roc_proc_text(rd_roclet(), " 20 | #' Foo 21 | #' 22 | #' @section Haz dox: Here. 23 | #' 24 | #' @section TL: DR. 25 | foo <- function(x = '%') x 26 | 27 | #' @rdname foo 28 | #' @section RT: FM. 29 | #' @section Haz dox: 30 | #' Got news. 31 | bar <- function(y = '%') y 32 | ")[[1]] 33 | 34 | expect_equal( 35 | out$get_field("section"), 36 | roxy_field_section( 37 | c("Haz dox", "TL", "RT"), 38 | c(" Here.\n\n\n Got news.", " DR.", " FM.") 39 | ) 40 | ) 41 | }) 42 | 43 | test_that("@section-s with different titles are kept as they are", { 44 | out <- roc_proc_text(rd_roclet(), " 45 | #' Foo 46 | #' 47 | #' @section A: 1 48 | #' @section B: 2 49 | foo <- function(x) x 50 | 51 | #' @rdname foo 52 | #' @section C: 3 53 | bar <- function(x) x 54 | ")[[1]] 55 | 56 | expect_equal( 57 | out$get_field("section"), 58 | roxy_field_section(LETTERS[1:3], c(" 1", " 2", " 3")) 59 | ) 60 | }) 61 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-slot.R: -------------------------------------------------------------------------------- 1 | context("Rd: slot") 2 | 3 | test_that("@slot creates a new section and lists slots", { 4 | out <- roc_proc_text(rd_roclet(), " 5 | #' Important class. 6 | #' 7 | #' @slot a slot a 8 | #' @slot b slot b 9 | setClass('test') 10 | ")[[1]] 11 | expect_equal(get_tag(out, "slot")$values, c(a = "slot a", b = "slot b")) 12 | }) 13 | -------------------------------------------------------------------------------- /tests/testthat/test-rd-template.R: -------------------------------------------------------------------------------- 1 | context("Rd: template") 2 | 3 | test_that("template_find finds files with .r and .R extension, and fails to find missing files", { 4 | my.tempdir <- "." 5 | my.mandir <- file.path(my.tempdir, "man-roxygen") 6 | my.ucase <- file.path(my.mandir, "UCase.R") 7 | my.regex <- file.path(my.mandir, "reg.ex.R") 8 | my.lcase <- file.path(my.mandir, "lcase.r") 9 | 10 | expect_equal(template_find(my.tempdir, "UCase"), my.ucase) 11 | expect_error(template_find(my.tempdir, "Case")) 12 | expect_error(template_find(my.tempdir, "UCas")) 13 | expect_equal(template_find(my.tempdir, "reg.ex"), my.regex) 14 | expect_error(template_find(my.tempdir, "reggex")) 15 | expect_error(template_find(my.tempdir, "nada")) 16 | 17 | # On case-insentive file systems, will find upper case version first 18 | expect_equal(tolower(template_find(my.tempdir, "lcase")), tolower(my.lcase)) 19 | }) 20 | 21 | test_that("templates replace variables with their values", { 22 | out <- roc_proc_text(rd_roclet(), " 23 | #' @template values 24 | #' @templateVar x a 25 | #' @templateVar y b 26 | #' @templateVar z c 27 | x <- 10")[[1]] 28 | 29 | expect_equal(get_tag(out, "title")$values, "a") 30 | expect_equal(get_tag(out, "param")$values, c(b = "c")) 31 | }) 32 | 33 | test_that("allow empty line after @template", { 34 | out <- roc_proc_text(rd_roclet(), " 35 | #' @template values 36 | #' 37 | #' @templateVar x a 38 | #' @templateVar y b 39 | #' @templateVar z c 40 | x <- 10")[[1]] 41 | 42 | expect_equal(get_tag(out, "title")$values, "a") 43 | }) 44 | -------------------------------------------------------------------------------- /tests/testthat/test-rd.R: -------------------------------------------------------------------------------- 1 | context("Rd") 2 | 3 | test_that("empty file gives empty list", { 4 | out <- roc_proc_text(rd_roclet(), "") 5 | expect_identical(out, list()) 6 | }) 7 | 8 | test_that("NULL gives empty list", { 9 | out <- roc_proc_text(rd_roclet(), "NULL") 10 | expect_identical(out, list()) 11 | }) 12 | 13 | test_that("generic keys produce expected output", { 14 | out <- roc_proc_text(rd_roclet(), " 15 | #' @title a 16 | #' @references test 17 | #' @note test 18 | #' @author test 19 | #' @seealso test 20 | #' @concept test 21 | #' @encoding test 22 | #' @name a 23 | NULL")[[1]] 24 | expect_equal(get_tag(out, "references")$values, "test") 25 | expect_equal(get_tag(out, "note")$values, "test") 26 | expect_equal(get_tag(out, "seealso")$values, "test") 27 | expect_equal(get_tag(out, "concept")$values, "test") 28 | expect_equal(get_tag(out, "encoding")$values, "test") 29 | expect_equal(get_tag(out, "author")$values, "test") 30 | }) 31 | 32 | test_that("@noRd inhibits documentation", { 33 | out <- roc_proc_text(rd_roclet(), " 34 | #' Would be title 35 | #' @title Overridden title 36 | #' @name a 37 | #' @noRd 38 | NULL") 39 | 40 | expect_equal(length(out), 0) 41 | }) 42 | 43 | 44 | test_that("deleted objects not documented", { 45 | out <- roc_proc_text(rd_roclet(), " 46 | f <- function(){ 47 | .a <- 0 48 | function(x = 1){ 49 | .a <<- .a + x 50 | .a 51 | } 52 | } 53 | 54 | #' Addition function. 55 | f2 <- f() 56 | rm(f) 57 | ") 58 | expect_equal(names(out), "f2.Rd") 59 | }) 60 | 61 | 62 | test_that("documenting unknown function requires name", { 63 | expect_warning( 64 | roc_proc_text(rd_roclet(), " 65 | #' Virtual Class To Enforce Max Slot Lenght 66 | #' 67 | #' @export 68 | setClass('A') 69 | 70 | #' Validity function. 71 | setValidity('A', function(object) TRUE)" 72 | ), 73 | "Missing name" 74 | ) 75 | }) 76 | 77 | test_that("documenting NA gives useful error message (#194)", { 78 | expect_warning( 79 | roc_proc_text(rd_roclet(), " 80 | #' Missing value 81 | NA" 82 | ), 83 | "Missing name" 84 | ) 85 | }) 86 | -------------------------------------------------------------------------------- /tests/testthat/test-rdComplete.R: -------------------------------------------------------------------------------- 1 | context("rdComplete()") 2 | 3 | # Test low-level behaviour ---------------------------------------------------- 4 | 5 | test_that("braces must balance", { 6 | expect_true(rdComplete("{}")) 7 | expect_true(rdComplete("{{}}")) 8 | 9 | expect_false(rdComplete("{")) 10 | expect_false(rdComplete("}")) 11 | }) 12 | 13 | test_that("can't end with escape", { 14 | expect_false(rdComplete("\\")) 15 | }) 16 | 17 | test_that("escaped brackets are ignored", { 18 | expect_true(rdComplete("\\{")) 19 | expect_true(rdComplete("\\}")) 20 | expect_false(rdComplete("{\\}")) 21 | }) 22 | 23 | test_that("brackets in comments are ignored", { 24 | expect_true(rdComplete("% {")) 25 | expect_true(rdComplete("% }")) 26 | }) 27 | 28 | test_that("R comments don't close latex-like tags", { 29 | expect_true(rdComplete("A comment \\code{#}.")) 30 | }) 31 | 32 | test_that("newline ends comment", { 33 | expect_false(rdComplete("%\n{")) 34 | }) 35 | 36 | test_that("escape disables comment", { 37 | expect_false(rdComplete("\\%{")) 38 | }) 39 | 40 | test_that("strings must be closed in code", { 41 | expect_false(rdComplete("'", TRUE)) 42 | expect_false(rdComplete('"', TRUE)) 43 | }) 44 | 45 | test_that("strings respect escapes", { 46 | expect_false(rdComplete("'\\'", TRUE)) # '\' 47 | expect_true(rdComplete("'\\''", TRUE)) # '\'' 48 | }) 49 | 50 | test_that("braces in strings don't need to match in code", { 51 | expect_true(rdComplete("'{{'", TRUE)) 52 | }) 53 | 54 | test_that("strings in code comments don't need to be closed", { 55 | expect_true(rdComplete("# '", TRUE)) 56 | }) 57 | 58 | test_that("braces in code must match", { 59 | expect_false(rdComplete("# {", TRUE)) 60 | expect_true(rdComplete("# {}", TRUE)) 61 | }) 62 | 63 | 64 | 65 | 66 | # Test that incomplete Rd is caught in Rd blocks ------------------------------- 67 | 68 | test_that("incomplete rd in tag raises error", { 69 | expect_warning(roc_proc_text(rd_roclet(), " 70 | #' Title 71 | #' @aliases title{ 72 | x <- 1"), "mismatched braces") 73 | }) 74 | 75 | test_that("incomplete rd in prequel raises error", { 76 | expect_warning(roc_proc_text(rd_roclet(), " 77 | #' Title { 78 | x <- 1"), "mismatched braces") 79 | }) 80 | 81 | -------------------------------------------------------------------------------- /tests/testthat/test-reexport.R: -------------------------------------------------------------------------------- 1 | context("Re-export") 2 | 3 | test_that("exporting a call to :: produces re-exports documentation", { 4 | out <- roc_proc_text(rd_roclet(), " 5 | #' @export 6 | testthat::auto_test")[[1]] 7 | 8 | expect_equal( 9 | out$get_field("reexport"), 10 | roxy_field_reexport("testthat", "auto_test") 11 | ) 12 | 13 | expect_equal( 14 | out$get_field("title")$value, 15 | "Objects exported from other packages" 16 | ) 17 | 18 | expect_equal(out$get_field("keyword")$value, "internal") 19 | }) 20 | 21 | test_that("multiple re-exports are combined", { 22 | out <- roc_proc_text(rd_roclet(), " 23 | #' @export 24 | testthat::expect_lt 25 | 26 | #' @export 27 | testthat::expect_gt 28 | ")[[1]] 29 | 30 | expect_equal( 31 | out$get_field("reexport"), 32 | roxy_field_reexport(c("testthat", "testthat"), c("expect_lt", "expect_gt")) 33 | ) 34 | }) 35 | -------------------------------------------------------------------------------- /tests/testthat/test-select_args.R: -------------------------------------------------------------------------------- 1 | context("select_args") 2 | 3 | test_that("errors on invalid input", { 4 | expect_error(select_args_text(sum, "-xlab:"), "Failed to parse") 5 | expect_error(select_args_text(sum, '"a"'), "numbers") 6 | 7 | f <- function(x, y, z) {} 8 | expect_error(select_args_text(f, "-x:z"), "numbers") 9 | }) 10 | 11 | test_that("positive initial values starts from nothing", { 12 | f <- function(x, y, z) {} 13 | 14 | expect_equal(select_args_text(f, "x y"), c("x", "y")) 15 | }) 16 | 17 | test_that("negative initial starts from everything", { 18 | f <- function(x, y, z) {} 19 | 20 | expect_equal(select_args_text(f, "-z"), c("x", "y")) 21 | }) 22 | 23 | test_that("can alternative exclusion and inclusion", { 24 | f <- function(x, y, z) {} 25 | 26 | expect_equal(select_args_text(f, "-z z"), c("x", "y", "z")) 27 | expect_equal(select_args_text(f, "z -z"), character()) 28 | }) 29 | -------------------------------------------------------------------------------- /tests/testthat/test-topic.R: -------------------------------------------------------------------------------- 1 | context("Topic") 2 | 3 | test_that("adding tags merges with existing", { 4 | rd <- RoxyTopic$new() 5 | 6 | rd$add(roxy_field_simple("x", 1)) 7 | rd$add(roxy_field_simple("x", 2)) 8 | 9 | expect_equal(rd$get_field("x")$values, c(1, 2)) 10 | }) 11 | 12 | test_that("unless overwrite = TRUE", { 13 | rd <- RoxyTopic$new() 14 | 15 | rd$add(roxy_field_simple("x", 1)) 16 | rd$add(roxy_field_simple("x", 2), overwrite = TRUE) 17 | 18 | expect_equal(rd$get_field("x")$values, 2) 19 | }) 20 | 21 | test_that("can add a complete file", { 22 | rd1 <- RoxyTopic$new() 23 | rd2 <- RoxyTopic$new() 24 | 25 | rd1$add(roxy_field_simple("x", 1)) 26 | rd2$add(roxy_field_simple("x", 2)) 27 | rd2$add(rd1) 28 | 29 | expect_equal(rd2$get_field("x")$values, c(2, 1)) 30 | }) 31 | -------------------------------------------------------------------------------- /tests/testthat/test-utils.R: -------------------------------------------------------------------------------- 1 | context("Utils") 2 | 3 | test_that("determine if file is autogenerated", { 4 | expect_true(made_by_roxygen("made-by-roxygen/with-header.Rd")) 5 | expect_false(made_by_roxygen("made-by-roxygen/without-header.Rd")) 6 | expect_false(made_by_roxygen("made-by-roxygen/empty.Rd")) 7 | expect_true(check_made_by(made_by("#"))) 8 | expect_false(check_made_by(character())) 9 | }) 10 | -------------------------------------------------------------------------------- /tests/testthat/testCollateNoIncludes/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: testCollateNoIncludes 2 | Title: Test no change to Collate when there are no @includes 3 | License: GPL-2 4 | Description: 5 | Author: Geoff 6 | Maintainer: Geoff 7 | Version: 0.1 8 | Collate: b.r a.r 9 | -------------------------------------------------------------------------------- /tests/testthat/testCollateNoIncludes/NAMESPACE: -------------------------------------------------------------------------------- 1 | exportPattern("^[^\\.]") 2 | -------------------------------------------------------------------------------- /tests/testthat/testCollateNoIncludes/R/a.r: -------------------------------------------------------------------------------- 1 | # Manually edited the Collate field in the DESCRIPTION file so this *should* 2 | # run after b.r 3 | 4 | a <- 1 5 | -------------------------------------------------------------------------------- /tests/testthat/testCollateNoIncludes/R/b.r: -------------------------------------------------------------------------------- 1 | a <- 2 2 | -------------------------------------------------------------------------------- /tests/testthat/testCollateOverwrite/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: testCollateMissing 2 | Title: Tools to make developing R code easier 3 | License: GPL-2 4 | Description: 5 | Author: Hadley 6 | Maintainer: Hadley 7 | Version: 0.1 8 | Collate: 9 | 'b.r' 10 | -------------------------------------------------------------------------------- /tests/testthat/testCollateOverwrite/R/a.r: -------------------------------------------------------------------------------- 1 | #' @include b.r 2 | a <- 1 3 | -------------------------------------------------------------------------------- /tests/testthat/testCollateOverwrite/R/b.r: -------------------------------------------------------------------------------- 1 | b <- 2 -------------------------------------------------------------------------------- /tests/testthat/testEagerData/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: testEagerData 2 | Title: Tools to make developing R code easier 3 | License: GPL-2 4 | Description: 5 | Author: Hadley 6 | Maintainer: Hadley 7 | Version: 0.1 8 | -------------------------------------------------------------------------------- /tests/testthat/testEagerData/R/a.r: -------------------------------------------------------------------------------- 1 | #' Data 2 | #' 3 | #' Desc 4 | "a" 5 | -------------------------------------------------------------------------------- /tests/testthat/testEagerData/data/a.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yihui/roxygen2/14eae413099f00b3ac630c5fa7ec1e62db6c659d/tests/testthat/testEagerData/data/a.rda -------------------------------------------------------------------------------- /tests/testthat/testLazyData/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: testEagerData 2 | Title: Tools to make developing R code easier 3 | License: GPL-2 4 | Description: 5 | Author: Hadley 6 | Maintainer: Hadley 7 | Version: 0.1 8 | LazyData: TRUE 9 | -------------------------------------------------------------------------------- /tests/testthat/testLazyData/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | -------------------------------------------------------------------------------- /tests/testthat/testLazyData/R/a.r: -------------------------------------------------------------------------------- 1 | #' Data 2 | #' 3 | #' Desc 4 | "a" 5 | -------------------------------------------------------------------------------- /tests/testthat/testLazyData/data/a.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yihui/roxygen2/14eae413099f00b3ac630c5fa7ec1e62db6c659d/tests/testthat/testLazyData/data/a.rda -------------------------------------------------------------------------------- /tests/testthat/testNonASCII/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: testNonASCII 2 | Title: Test no change to Collate when there are no @includes 3 | License: GPL-2 4 | Description: 5 | Author: Shrektan 6 | Maintainer: Shrektan 7 | Encoding: GB2312 8 | Version: 0.1 9 | -------------------------------------------------------------------------------- /tests/testthat/testNonASCII/R/a.r: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yihui/roxygen2/14eae413099f00b3ac630c5fa7ec1e62db6c659d/tests/testthat/testNonASCII/R/a.r -------------------------------------------------------------------------------- /tests/testthat/testRbuildignore/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: testRbuildignore 2 | Title: Tools to make developing R code easier 3 | License: GPL-2 4 | Description: 5 | Author: Francois 6 | Maintainer: Francois 7 | Version: 0.1 8 | -------------------------------------------------------------------------------- /tests/testthat/testRbuildignore/R/a.R: -------------------------------------------------------------------------------- 1 | #' function a 2 | #' 3 | a <- 1 4 | -------------------------------------------------------------------------------- /tests/testthat/testRbuildignore/R/ignore_me.R: -------------------------------------------------------------------------------- 1 | #' Ignore me, I'm not ready 2 | #' 3 | ignore_me <- "ignore me" 4 | -------------------------------------------------------------------------------- /vignettes/collate.R: -------------------------------------------------------------------------------- 1 | ## ---- include = FALSE---------------------------------------------------- 2 | knitr::opts_chunk$set(comment = "#>", collapse = TRUE) 3 | 4 | ## ---- eval = FALSE------------------------------------------------------- 5 | # #' @include class-a.r 6 | # setClass("B", contains = "A") 7 | 8 | -------------------------------------------------------------------------------- /vignettes/collate.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Collation order" 3 | author: "Hadley Wickham" 4 | date: "`r Sys.Date()`" 5 | output: rmarkdown::html_vignette 6 | vignette: > 7 | %\VignetteIndexEntry{Collation order} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | ```{r, include = FALSE} 13 | knitr::opts_chunk$set(comment = "#>", collapse = TRUE) 14 | ``` 15 | 16 | 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. The order in which files are loaded doesn't matter for most packages. But if you're using S4, you'll need to make sure that classes are loaded before subclasses and generics are defined before methods. 17 | 18 | Rather than relying on alphabetic ordering, roxygen2 provides an explicit way of saying that one file must be loaded before another: `@include`. The `@include` tag gives a space separated list of file names that should be loaded before the current file: 19 | 20 | ```{r, eval = FALSE} 21 | #' @include class-a.r 22 | setClass("B", contains = "A") 23 | ``` 24 | 25 | If any `@include` tags are present in the package, roxygen2 will set the `Collate` field in the `DESCRIPTION`, which ensures that files are always loaded in the same order. 26 | -------------------------------------------------------------------------------- /vignettes/collate.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | # Collation order 9 | 10 | 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. The order in which files are loaded doesn't matter for most packages. But if you're using S4, you'll need to make sure that classes are loaded before subclasses and generics are defined before methods. 11 | 12 | Rather than relying on alphabetic ordering, roxygen2 provides an explicit way of saying that one file must be loaded before another: `@include`. The `@include` tag gives a space separated list of file names that should be loaded before the current file: 13 | 14 | 15 | ```r 16 | #' @include class-a.r 17 | setClass("B", contains = "A") 18 | ``` 19 | 20 | If any `@include` tags are present in the package, roxygen2 will set the `Collate` field in the `DESCRIPTION`, which ensures that files are always loaded in the same order. 21 | -------------------------------------------------------------------------------- /vignettes/formatting.R: -------------------------------------------------------------------------------- 1 | ## ---- include = FALSE---------------------------------------------------- 2 | knitr::opts_chunk$set(comment = "#>", collapse = TRUE) 3 | 4 | ## ------------------------------------------------------------------------ 5 | #' \enumerate{ 6 | #' \item First item 7 | #' \item Second item 8 | #' } 9 | 10 | ## ------------------------------------------------------------------------ 11 | #' \itemize{ 12 | #' \item First item 13 | #' \item Second item 14 | #' } 15 | 16 | ## ------------------------------------------------------------------------ 17 | #' \describe{ 18 | #' \item{One}{First item} 19 | #' \item{Two}{Second item} 20 | #' } 21 | 22 | ## ------------------------------------------------------------------------ 23 | tabular <- function(df, ...) { 24 | stopifnot(is.data.frame(df)) 25 | 26 | align <- function(x) if (is.numeric(x)) "r" else "l" 27 | col_align <- vapply(df, align, character(1)) 28 | 29 | cols <- lapply(df, format, ...) 30 | contents <- do.call("paste", 31 | c(cols, list(sep = " \\tab ", collapse = "\\cr\n "))) 32 | 33 | paste("\\tabular{", paste(col_align, collapse = ""), "}{\n ", 34 | contents, "\n}\n", sep = "") 35 | } 36 | 37 | cat(tabular(mtcars[1:5, 1:5])) 38 | 39 | -------------------------------------------------------------------------------- /vignettes/formatting.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Text formatting reference sheet" 3 | author: "Hadley Wickham" 4 | date: "`r Sys.Date()`" 5 | output: rmarkdown::html_vignette 6 | vignette: > 7 | %\VignetteIndexEntry{Text formatting reference sheet} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | ```{r, include = FALSE} 13 | knitr::opts_chunk$set(comment = "#>", collapse = TRUE) 14 | ``` 15 | 16 | Within roxygen tags, you use `.Rd` syntax to format text. This vignette shows you examples of the most important commands. The full details are described in [R extensions](https://cran.r-project.org/doc/manuals/R-exts.html#Marking-text). 17 | 18 | Note that `\` and `%` are special characters. To insert literals, escape with a backslash: `\\`, `\%`. 19 | 20 | ## Character formatting 21 | 22 | * `\emph{italics}` 23 | 24 | * `\strong{bold}` 25 | 26 | * `\code{r_function_call(with = "arguments")}`, `\code{NULL}`, `\code{TRUE}` 27 | 28 | * `\pkg{package_name}` 29 | 30 | ## Links 31 | 32 | To other documentation: 33 | 34 | * `\code{\link{function}}`: function in this package 35 | 36 | * `\code{\link[MASS]{stats}}`: function in another package 37 | 38 | * `\link[=dest]{name}`: link to dest, but show name 39 | 40 | * `\linkS4class{abc}`: link to an S4 class 41 | 42 | To the web: 43 | 44 | * `\url{http://rstudio.com}` 45 | 46 | * `\href{http://rstudio.com}{Rstudio}` 47 | 48 | * `\email{hadley@@rstudio.com}` (note the doubled `@`) 49 | 50 | ## Lists 51 | 52 | * Ordered (numbered) lists: 53 | 54 | ```{r} 55 | #' \enumerate{ 56 | #' \item First item 57 | #' \item Second item 58 | #' } 59 | ``` 60 | 61 | * Unordered (bulleted) lists 62 | 63 | ```{r} 64 | #' \itemize{ 65 | #' \item First item 66 | #' \item Second item 67 | #' } 68 | ``` 69 | 70 | * Definition (named) lists 71 | 72 | ```{r} 73 | #' \describe{ 74 | #' \item{One}{First item} 75 | #' \item{Two}{Second item} 76 | #' } 77 | ``` 78 | 79 | ## Mathematics 80 | 81 | Standard LaTeX (with no extensions): 82 | 83 | * `\eqn{a + b}`: inline eqution 84 | 85 | * `\deqn{a + b}`: display (block) equation 86 | 87 | ## Tables 88 | 89 | Tables are created with `\tabular{}`. It has two arguments: 90 | 91 | 1. Column alignment, specified by letter for each column (`l` = left, `r` = right, 92 | `c` = centre.) 93 | 94 | 2. Table contents, with columns separated by `\tab` and rows by `\cr`. 95 | 96 | The following function turns an R data frame into into the correct format. It ignores column and row names, but should get you started. 97 | 98 | ```{r} 99 | tabular <- function(df, ...) { 100 | stopifnot(is.data.frame(df)) 101 | 102 | align <- function(x) if (is.numeric(x)) "r" else "l" 103 | col_align <- vapply(df, align, character(1)) 104 | 105 | cols <- lapply(df, format, ...) 106 | contents <- do.call("paste", 107 | c(cols, list(sep = " \\tab ", collapse = "\\cr\n "))) 108 | 109 | paste("\\tabular{", paste(col_align, collapse = ""), "}{\n ", 110 | contents, "\n}\n", sep = "") 111 | } 112 | 113 | cat(tabular(mtcars[1:5, 1:5])) 114 | ``` 115 | -------------------------------------------------------------------------------- /vignettes/formatting.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | # Text formatting reference sheet 9 | 10 | Within roxygen tags, you use `.Rd` syntax to format text. This vignette shows you examples of the most important commands. The full details are described in [R extensions](http://cran.r-project.org/doc/manuals/R-exts.html#Marking-text). 11 | 12 | Note that `\` and `%` are special characters. To insert literals, escape with a backslash: `\\`, `\%`. 13 | 14 | ## Character formatting 15 | 16 | * `\emph{italics}` 17 | 18 | * `\strong{bold}` 19 | 20 | * `\code{r_function_call(with = "arguments")}`, `\code{NULL}`, `\code{TRUE}` 21 | 22 | * `\pkg{package_name}` 23 | 24 | ## Links 25 | 26 | To other documentation: 27 | 28 | * `\code{\link{function}}`: function in this package 29 | 30 | * `\code{\link[MASS]{stats}}`: function in another package 31 | 32 | * `\link[=dest]{name}`: link to dest, but show name 33 | 34 | * `\linkS4class{abc}`: link to an S4 class 35 | 36 | To the web: 37 | 38 | * `\url{http://rstudio.com}` 39 | 40 | * `\href{http://rstudio.com}{Rstudio}` 41 | 42 | * `\email{hadley@@rstudio.com}` (note the doubled `@`) 43 | 44 | ## Lists 45 | 46 | * Ordered (numbered) lists: 47 | 48 | 49 | ```r 50 | #' \enumerate{ 51 | #' \item First item 52 | #' \item Second item 53 | #' } 54 | ``` 55 | 56 | * Unordered (bulleted) lists 57 | 58 | 59 | ```r 60 | #' \itemize{ 61 | #' \item First item 62 | #' \item Second item 63 | #' } 64 | ``` 65 | 66 | * Definition (named) lists 67 | 68 | 69 | ```r 70 | #' \describe{ 71 | #' \item{One}{First item} 72 | #' \item{Two}{Second item} 73 | #' } 74 | ``` 75 | 76 | ## Mathematics 77 | 78 | Standard LaTeX (with no extensions): 79 | 80 | * `\eqn{a + b}`: inline eqution 81 | 82 | * `\deqn{a + b}`: display (block) equation 83 | 84 | ## Tables 85 | 86 | Tables are created with `\tabular{}`. It has two arguments: 87 | 88 | 1. Column alignment, specified by letter for each column (`l` = left, `r` = right, 89 | `c` = centre.) 90 | 91 | 2. Table contents, with columns separated by `\tab` and rows by `\cr`. 92 | 93 | The following function turns an R data frame into into the correct format. It ignores column and row names, but should get you started. 94 | 95 | 96 | ```r 97 | tabular <- function(df, ...) { 98 | stopifnot(is.data.frame(df)) 99 | 100 | align <- function(x) if (is.numeric(x)) "r" else "l" 101 | col_align <- vapply(df, align, character(1)) 102 | 103 | cols <- lapply(df, format, ...) 104 | contents <- do.call("paste", 105 | c(cols, list(sep = " \\tab ", collapse = "\\cr\n "))) 106 | 107 | paste("\\tabular{", paste(col_align, collapse = ""), "}{\n ", 108 | contents, "\n}\n", sep = "") 109 | } 110 | 111 | cat(tabular(mtcars[1:5, 1:5])) 112 | ``` 113 | 114 | ``` 115 | #> \tabular{rrrrr}{ 116 | #> 21.0 \tab 6 \tab 160 \tab 110 \tab 3.90\cr 117 | #> 21.0 \tab 6 \tab 160 \tab 110 \tab 3.90\cr 118 | #> 22.8 \tab 4 \tab 108 \tab 93 \tab 3.85\cr 119 | #> 21.4 \tab 6 \tab 258 \tab 110 \tab 3.08\cr 120 | #> 18.7 \tab 8 \tab 360 \tab 175 \tab 3.15 121 | #> } 122 | ``` 123 | -------------------------------------------------------------------------------- /vignettes/markdown.R: -------------------------------------------------------------------------------- 1 | ## ---- include = FALSE---------------------------------------------------- 2 | knitr::opts_chunk$set(comment = "#>", collapse = TRUE) 3 | 4 | -------------------------------------------------------------------------------- /vignettes/namespace.R: -------------------------------------------------------------------------------- 1 | ## ---- include = FALSE---------------------------------------------------- 2 | knitr::opts_chunk$set(comment = "#>", collapse = TRUE) 3 | 4 | -------------------------------------------------------------------------------- /vignettes/namespace.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | # Package namespace 9 | 10 | 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. 11 | 12 | ## Exports 13 | 14 | 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 publically available, you must explicitly tag it with `@export`. 15 | 16 | Use the following guidelines to decide what to export: 17 | 18 | * Functions: export functions that you want to make available. Exported 19 | functions must be documented, and you must be cautious when changing their 20 | interface. 21 | 22 | * Datasets: all datasets are publicly available. They exist outside of the 23 | package namespace and should not be exported. 24 | 25 | * S3 classes: if you want others to be able to create instances of the class 26 | `@export` the constructor function. 27 | 28 | * S3 generics: the generic is a function so `@export` if you want it to 29 | be usable outside the package 30 | 31 | * S3 methods: every S3 method _must_ be exported, even if the generic is not. 32 | Otherwise the S3 method table will not be generated correctly and internal 33 | generics will not find the correct method. 34 | 35 | * S4 classes: if you want others to be able to extend your class, `@export` it. 36 | If you want others to create instances of your class, but not extend it, 37 | `@export` the constructor function, but not the class. 38 | 39 | ```R 40 | # Can extend and create 41 | #' @export 42 | setClass("A") 43 | 44 | # Can extend, but constructor not exported 45 | #' @export 46 | B <- setClass("B") 47 | 48 | # Can create, but not extend 49 | #' @export C 50 | C <- setClass("C") 51 | 52 | # Can create and extend 53 | #' @export D 54 | #' @exportClass D 55 | D <- setClass("D") 56 | ``` 57 | 58 | * S4 generics: `@export` if you want the generic to be publicly usable. 59 | 60 | * S4 methods: you only need to `@export` methods for generics that you 61 | did not define. But `@export`ing every method is a good idea as it 62 | will not cause problems and prevents you from forgetting to export an 63 | important method. 64 | 65 | * RC classes: the same principles apply as for S4 classes. `@export` 66 | will only export the class. 67 | 68 | ## Imports 69 | 70 | 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. 71 | 72 | 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 `::`. 73 | 74 | If you are using many functions from another package, use `@import package` to import them all and make available without using `::`. 75 | 76 | If you want to add a new method to an S3 generic, import it with `@importFrom pkg generic`. 77 | 78 | If you are using S4 you may also need: 79 | 80 | * `@importClassesFrom package classa classb ...` to import selected S4 classes. 81 | 82 | * `@importMethodsFrom package methoda methodb ...` to import selected S4 methods. 83 | 84 | To import compiled code from another package, use `@useDynLib` 85 | 86 | * `@useDynLib package` imports all compiled functions. 87 | 88 | * `@useDynLib package routinea routineb` imports selected compiled functions. 89 | 90 | * Any `@useDynLib` specification containing a comma, e.g. 91 | `@useDynLib mypackage, .registration = TRUE` will be inserted as is 92 | into the the NAMESPACE, e.g. `useDynLib(mypackage, .registration = TRUE)` 93 | 94 | -------------------------------------------------------------------------------- /vignettes/rdkeywords.R: -------------------------------------------------------------------------------- 1 | ## ---- include = FALSE---------------------------------------------------- 2 | knitr::opts_chunk$set(comment = "#>", collapse = TRUE) 3 | 4 | ## ------------------------------------------------------------------------ 5 | cat(readLines(file.path(R.home("doc"), "KEYWORDS")), sep = "\n") 6 | 7 | -------------------------------------------------------------------------------- /vignettes/rdkeywords.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Rd keywords" 3 | author: "Hadley Wickham" 4 | date: "`r Sys.Date()`" 5 | output: rmarkdown::html_vignette 6 | vignette: > 7 | %\VignetteIndexEntry{Rd keywords} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | ```{r, include = FALSE} 13 | knitr::opts_chunk$set(comment = "#>", collapse = TRUE) 14 | ``` 15 | 16 | ```{r} 17 | cat(readLines(file.path(R.home("doc"), "KEYWORDS")), sep = "\n") 18 | ``` 19 | -------------------------------------------------------------------------------- /vignettes/rdkeywords.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | # Keywords 9 | 10 | 11 | ```r 12 | cat(readLines(file.path(R.home("doc"), "KEYWORDS")), sep = "\n") 13 | ``` 14 | 15 | ``` 16 | #> GROUPED Keywords 17 | #> ---------------- 18 | #> 19 | #> Graphics 20 | #> aplot & Add to Existing Plot / internal plot 21 | #> dplot & Computations Related to Plotting 22 | #> hplot & High-Level Plots 23 | #> iplot & Interacting with Plots 24 | #> color & Color, Palettes etc 25 | #> dynamic & Dynamic Graphics 26 | #> device & Graphical Devices 27 | #> 28 | #> Basics 29 | #> sysdata & Basic System Variables [!= S] 30 | #> datasets & Datasets available by data(.) [!= S] 31 | #> data & Environments, Scoping, Packages [~= S] 32 | #> manip & Data Manipulation 33 | #> attribute & Data Attributes 34 | #> classes & Data Types (not OO) 35 | #> & character & Character Data ("String") Operations 36 | #> & complex & Complex Numbers 37 | #> & category & Categorical Data 38 | #> & NA & Missing Values [!= S] 39 | #> list & Lists 40 | #> chron & Dates and Times 41 | #> package & Package Summaries 42 | #> 43 | #> Mathematics 44 | #> array & Matrices and Arrays 45 | #> & algebra & Linear Algebra 46 | #> arith & Basic Arithmetic and Sorting [!= S] 47 | #> math & Mathematical Calculus etc. [!= S] 48 | #> logic & Logical Operators 49 | #> optimize & Optimization 50 | #> symbolmath & "Symbolic Math", as polynomials, fractions 51 | #> graphs & Graphs, (not graphics), e.g. dendrograms 52 | #> 53 | #> Programming, Input/Ouput, and Miscellaneous 54 | #> 55 | #> programming & Programming 56 | #> & interface& Interfaces to Other Languages 57 | #> IO & Input/output 58 | #> & file & Files 59 | #> & connection& Connections 60 | #> & database & Interfaces to databases 61 | #> iteration & Looping and Iteration 62 | #> methods & Methods and Generic Functions 63 | #> print & Printing 64 | #> error & Error Handling 65 | #> 66 | #> environment & Session Environment 67 | #> internal & Internal Objects (not part of API) 68 | #> utilities & Utilities 69 | #> misc & Miscellaneous 70 | #> documentation & Documentation 71 | #> debugging & Debugging Tools 72 | #> 73 | #> Statistics 74 | #> 75 | #> datagen & Functions for generating data sets 76 | #> distribution & Probability Distributions and Random Numbers 77 | #> univar & simple univariate statistics [!= S] 78 | #> htest & Statistical Inference 79 | #> models & Statistical Models 80 | #> & regression& Regression 81 | #> & &nonlinear& Non-linear Regression (only?) 82 | #> robust & Robust/Resistant Techniques 83 | #> design & Designed Experiments 84 | #> multivariate & Multivariate Techniques 85 | #> ts & Time Series 86 | #> survival & Survival Analysis 87 | #> nonparametric & Nonparametric Statistics [w/o 'smooth'] 88 | #> smooth & Curve (and Surface) Smoothing 89 | #> & loess & Loess Objects 90 | #> cluster & Clustering 91 | #> tree & Regression and Classification Trees 92 | #> survey & Complex survey samples 93 | #> 94 | #> 95 | #> MASS (2, 1997) 96 | #> -------------- 97 | #> 98 | #> add the following keywords : 99 | #> 100 | #> classif & Classification ['class' package] 101 | #> spatial & Spatial Statistics ['spatial' package] 102 | #> neural & Neural Networks ['nnet' package] 103 | ``` 104 | -------------------------------------------------------------------------------- /vignettes/roxygen2.R: -------------------------------------------------------------------------------- 1 | ## ---- include = FALSE---------------------------------------------------- 2 | knitr::opts_chunk$set(comment = "#>", collapse = TRUE) 3 | 4 | -------------------------------------------------------------------------------- /vignettes/roxygen2.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Introduction to roxygen2" 3 | author: "Hadley Wickham" 4 | date: "`r Sys.Date()`" 5 | output: rmarkdown::html_vignette 6 | vignette: > 7 | %\VignetteIndexEntry{Introduction to roxygen2} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | ```{r, include = FALSE} 13 | knitr::opts_chunk$set(comment = "#>", collapse = TRUE) 14 | ``` 15 | 16 | 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: 17 | 18 | * Code and documentation are adjacent so when you modify your code, it's easy 19 | to remember that you need to update the documentation. 20 | 21 | * Roxygen2 dynamically inspects the objects that it's documenting, so it 22 | can automatically add data that you'd otherwise have to write by hand. 23 | 24 | * It abstracts over the differences in documenting S3 and S4 methods, 25 | generics and classes so you need to learn fewer details. 26 | 27 | As well as generating `.Rd` files, roxygen will also create a `NAMESPACE` for you, and will manage the `Collate` field in `DESCRIPTION`. 28 | 29 | This vignette provides a high-level description of roxygen2 and how the three main components work. The other vignettes provide more detail on the individual components: 30 | 31 | * [Generating .Rd files](rd.html) and [text formatting](formatting.html) 32 | describe how to generate function documentation via `.Rd` files 33 | 34 | * [Managing your `NAMESPACE`](namespace.html) describes how to generate 35 | a `NAMESPACE` file, how namespacing works in R, and how you can use Roxygen2 to be 36 | specific about what your package needs and supplies. 37 | 38 | * [Controlling collation order](collate.html) describes how roxygen2 39 | controls file loading order if you need to make sure one file is 40 | loaded before another. 41 | 42 | # Running roxygen 43 | 44 | There are three main ways to run roxygen: 45 | 46 | * `roxygen2::roxygenise()`, or 47 | 48 | * `devtools::document()`, if you're using devtools, or 49 | 50 | * `Ctrl + Shift + D`, if you're using RStudio. 51 | 52 | As of version 4.0.0, roxygen2 will never overwrite a file it didn't create. It does this by labelling every file it creates with a comment: "Generated by roxygen2: do not edit by hand". 53 | -------------------------------------------------------------------------------- /vignettes/roxygen2.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | # Introduction to roxygen2 9 | 10 | 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: 11 | 12 | * Code and documentation are adjacent so when you modify your code, it's easy 13 | to remember that you need to update the documentation. 14 | 15 | * Roxygen2 dynamically inspects the objects that it's documenting, so it 16 | can automatically add data that you'd otherwise have to write by hand. 17 | 18 | * It abstracts over the differences in documenting S3 and S4 methods, 19 | generics and classes so you need to learn fewer details. 20 | 21 | As well as generating `.Rd` files, roxygen will also create a `NAMESPACE` for you, and will manage the `Collate` field in `DESCRIPTION`. 22 | 23 | This vignette provides a high-level description of roxygen2 and how the three main components work. The other vignettes provide more detail on the individual components: 24 | 25 | * [Generating .Rd files](rd.html) and [text formatting](formatting.html) 26 | describe how to generate function documentation via `.Rd` files 27 | 28 | * [Managing your `NAMESPACE`](namespace.html) describes how to generate 29 | a `NAMESPACE` file, how namespacing works in R, and how you can use Roxygen2 to be 30 | specific about what your package needs and supplies. 31 | 32 | * [Controlling collation order](collate.html) describes how roxygen2 33 | controls file loading order if you need to make sure one file is 34 | loaded before another. 35 | 36 | # Running roxygen 37 | 38 | There are three main ways to run roxygen: 39 | 40 | * `roxygen2::roxygenise()`, or 41 | 42 | * `devtools::document()`, if you're using devtools, or 43 | 44 | * `Ctrl + Shift + D`, if you're using RStudio. 45 | 46 | As of version 4.0.0, roxygen2 will never overwrite a file it didn't create. It does this by labelling every file it creates with a comment: "Generated by roxygen2 (version): do not edit by hand". 47 | --------------------------------------------------------------------------------