Skip to content

Commit 6918ffc

Browse files
committed
Roll the @examplesTempdir tag implementation
1 parent b1e2577 commit 6918ffc

11 files changed

+439
-0
lines changed

NAMESPACE

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Generated by roxygen2: do not edit by hand
2+
3+
S3method(roxygen2::roxy_tag_parse,roxy_tag_examplesTempdir)
4+
S3method(roxygen2::roxy_tag_rd,roxy_tag_examplesTempdir)
5+
export(insert_examplesTempdir_template)

R/examplesTempdir.R

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#' Custom `@examplesTempdir` tag.
2+
#'
3+
#' This function generates example code that runs in a temporary directory
4+
#' by automatically wrapping the code with the appropriate setup and teardown calls.
5+
#' When roxygen2 processes your documentation, the `@examplesTempdir` tag is transformed into
6+
#' an `@examples` tag with temporary directory handling, eliminating the need to manually
7+
#' include these calls in your documentation.
8+
#'
9+
#' The tag addresses a common need when writing package examples that create files
10+
#' or modify the filesystem. Running such examples in a temporary directory prevents
11+
#' cluttering the user's working directory with test files and ensures clean package checks.
12+
#'
13+
#' @section Implementation:
14+
#'
15+
#' When the `@examplesTempdir` tag is processed, it is transformed into an `@examples` tag with
16+
#' the following wrapper code automatically added:
17+
#'
18+
#' ```r
19+
#' \dontshow{.old_wd <- setwd(tempdir())}
20+
#'
21+
#' # Your example code here
22+
#'
23+
#' \dontshow{setwd(.old_wd)}
24+
#' ```
25+
#'
26+
#' The temporary directory setup saves the current working directory, switches to `tempdir()`,
27+
#' and then restores the original working directory when the example code has finished executing.
28+
#' This is all hidden from the user in the final documentation using `\dontshow{}`.
29+
#'
30+
#' @section Use Cases:
31+
#'
32+
#' The `@examplesTempdir` tag is particularly useful for:
33+
#'
34+
#' * Examples that create or write to files
35+
#' * Examples that need to test file operations
36+
#' * Examples that should not modify the user's working directory
37+
#' * Any code that should run in an isolated directory environment
38+
#'
39+
#' @section Package Configuration:
40+
#'
41+
#' To use the `@examplesTempdir` tag in your package, add `rocleteer` to your
42+
#' package dependencies and configure roxygen2 to use the `rocleteer`:
43+
#'
44+
#' In your `DESCRIPTION` file:
45+
#'
46+
#' ```
47+
#' Suggests:
48+
#' rocleteer
49+
#' Roxygen: list(roclets = c("namespace", "rd", "rocleteer"))
50+
#' Remotes: coatless-rpkg/rocleteer
51+
#' ```
52+
#'
53+
#' @name tag-examplesTempdir
54+
#'
55+
#' @usage
56+
#' #' @examplesTempdir
57+
#' #' # Your example code that needs to run in a temporary directory
58+
#'
59+
#' @examples
60+
#' # A function that writes a file and needs to run in a temporary directory
61+
#' #
62+
#' #' @title Write CSV to a File
63+
#' #' @description
64+
#' #' This function writes a data frame to a CSV file
65+
#' #'
66+
#' #' @param data A data frame to write
67+
#' #' @param filename Name of the file to write
68+
#' #'
69+
#' #' @return
70+
#' #' Invisibly returns the input data frame
71+
#' #'
72+
#' #' @examplesTempdir
73+
#' #' # Create a data frame
74+
#' #' df <- data.frame(x = 1:5, y = letters[1:5])
75+
#' #'
76+
#' #' # Write to a file
77+
#' #' write.csv(df, "test.csv", row.names = FALSE)
78+
#' #'
79+
#' #' # Check that the file exists
80+
#' #' file.exists("test.csv")
81+
#' #'
82+
#' #' # Read it back
83+
#' #' read.csv("test.csv")
84+
NULL
85+
86+
# Internal functions to handle the `@examplesTempdir` tag ----
87+
88+
#' Parse the `@examplesTempdir` tag
89+
#'
90+
#' This function handles the new `@examplesTempdir` tag, which automatically wraps
91+
#' example code in a pattern that temporarily changes to a temporary directory
92+
#' and restores the original directory afterward.
93+
#'
94+
#' @param x A roxygen2 tag
95+
#'
96+
#' @return
97+
#' A parsed roxygen2 tag
98+
#'
99+
#' @noRd
100+
#' @exportS3Method roxygen2::roxy_tag_parse roxy_tag_examplesTempdir
101+
roxy_tag_parse.roxy_tag_examplesTempdir <- function(x) {
102+
# Split the raw text into lines
103+
lines <- unlist(strsplit(x$raw, "\r?\n"))
104+
105+
# Wrap the example code in the temporary directory setup and teardown
106+
x$raw <- paste(c(
107+
"\\dontshow{\n.old_wd <- setwd(tempdir()) # examplesTempdir\n}",
108+
paste(lines[-1], collapse = "\n"), # Skip the first line (empty newline)
109+
"\\dontshow{\nsetwd(.old_wd) # examplesTempdir\n}"
110+
), collapse = "\n")
111+
112+
# Revert the tag to `examples`
113+
x$tag <- "examples"
114+
115+
# Process the tag as normal
116+
results <- roxygen2::tag_examples(x)
117+
118+
results
119+
}
120+
121+
122+
#' @noRd
123+
#' @exportS3Method roxygen2::roxy_tag_rd roxy_tag_examplesTempdir
124+
roxy_tag_rd.roxy_tag_examplesTempdir <- function(x, base_path, env) {
125+
# Hook into the `roxygen2::rd_section_examples` function to handle the `@examplesTempdir` tag
126+
roxygen2::rd_section("examples", x$val)
127+
}

R/rocleteer-package.R

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#' @keywords internal
2+
"_PACKAGE"
3+
4+
## usethis namespace: start
5+
## usethis namespace: end
6+
NULL

R/rstudio-addins.R

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#' Insert a temporary working directory template
2+
#'
3+
#' This function inserts a template for the `@examplesTempdir` tag at the cursor position.
4+
#' It's designed to be used as an RStudio addin.
5+
#'
6+
#' @export
7+
insert_examplesTempdir_template <- function() {
8+
if (!requireNamespace("rstudioapi", quietly = TRUE) || !rstudioapi::isAvailable()) {
9+
stop("This function must be used within RStudio")
10+
}
11+
12+
template <- paste(
13+
"#' @examplesTempdir",
14+
"#' # Your code here",
15+
sep = "\n"
16+
)
17+
18+
rstudioapi::insertText(template)
19+
}

inst/rstudio/addins.dcf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Name: Insert examplesTempdir
2+
Description: Insert a template for examples that run in a temporary working directory
3+
Binding: insert_examplesTempdir_template
4+
Interactive: false

man/insert_examplesTempdir_template.Rd

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/rocleteer-package.Rd

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/tag-examplesTempdir.Rd

Lines changed: 92 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat.R

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# This file is part of the standard setup for testthat.
2+
# It is recommended that you do not modify it.
3+
#
4+
# Where should you do additional test configuration?
5+
# Learn more about the roles of various files in:
6+
# * https://r-pkgs.org/testing-design.html#sec-tests-files-overview
7+
# * https://testthat.r-lib.org/articles/special-files.html
8+
9+
library(testthat)
10+
library(rocleteer)
11+
12+
test_check("rocleteer")

0 commit comments

Comments
 (0)