Skip to content

Commit 7fac550

Browse files
committed
chore: adding tests, adding note about exports
1 parent cd25d46 commit 7fac550

File tree

6 files changed

+92
-28
lines changed

6 files changed

+92
-28
lines changed

R/utils_knitr.R

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,24 @@
1+
roxygen2_knitr_note <- function() {
2+
sprintf(
3+
paste(
4+
"`%s` `knitr` utilities are exported for use in",
5+
"reports maintained by the R Validation Hub.",
6+
"If you choose to use these functions for other purposes, be aware",
7+
"that these are not considered stable for broader use."
8+
),
9+
packageName()
10+
)
11+
}
12+
113
#' Handler for complex option passing through from a quarto parameter
214
#'
315
#' Importantly, handles [`S7::new_class()`] objects which cannot be passed
416
#' through as a `quarto` command-line parameter because they can not be
517
#' deparsed. This helper allows passing arbitrary expressions using the
618
#' `!expr` prefix, which is standardized by `yaml`.
719
#'
20+
#' @note `r roxygen2_knitr_note()`
21+
#'
822
#' @param opts A `list` of options. For any non-serializable values that would
923
#' fail using your preferred interface to `knitr`, you may pass them as an
1024
#' expression string such as `"!expr mtcars"`. Notably,
@@ -57,32 +71,25 @@ knitr_update_options <- function(opts, envir = parent.frame()) {
5771
#' a mutable environment that we can modify, which will be used to update the
5872
#' knitr document header upon render completion.
5973
#'
74+
#' @note `r roxygen2_knitr_note()`
75+
#'
6076
#' @param params Optionally, provide default parameters to initialize with
6177
#' @param envir Only used when `params` is not provided, as the source for where
6278
#' to try to discover the default knitr frontmatter parameters.
6379
#'
6480
#' @importFrom yaml yaml.load
6581
#' @export
66-
knitr_mutable_header <- function(params = NULL, envir = parent.frame()) {
82+
knitr_mutable_header <- function() {
6783
header <- new.env(parent = emptyenv())
6884

69-
# if not provided, try to get params from envir
70-
if (is.null(params)) {
71-
params <- get0("params", envir = envir, ifnotfound = list())
72-
}
73-
74-
# initialize with param values
75-
for (name in names(params)) {
76-
header[[name]] <- params[[name]]
77-
}
78-
7985
# add a hook that will replace the hard-coded front-matter with dynamic
8086
# front-matter just before rendering.
8187
knitr::knit_hooks$set(
8288
document = local({
8389
default_document_hook <- knitr::knit_hooks$get("document")
84-
function(x, output) {
90+
function(x, options) {
8591
# extract and split our document front-matter and body
92+
x <- paste(x, collapse = "\n")
8693
body <- sub("^\\s*(---|\\.\\.\\.).*\\1", "", x)
8794
fm <- substring(x, 0L, nchar(x) - nchar(body))
8895

@@ -115,7 +122,13 @@ knit_print.knitr_log <- local({
115122
prefix <- " \u205A " # vertical two dot punctuation
116123
last_log_trailing_newline <- FALSE
117124

118-
function(x, ...) {
125+
# "progress" is used by knitr::knit function internally to store whether
126+
# progress should be written to console, equivalent to !quiet
127+
function(x, ..., quiet = !knitr::opts_knit$get("progress")) {
128+
if (quiet) {
129+
return()
130+
}
131+
119132
# prefix newline only for the first message in each chunk
120133
knitr_log_env <- environment(knitr_logger)
121134
first_chunk_log <- knitr_log_env$first_chunk_log
@@ -156,6 +169,7 @@ knit_print.knitr_log <- local({
156169
if (first_chunk_log) {
157170
cat("\n", file = stderr(), sep = "")
158171
}
172+
159173
cat(x, file = stderr(), sep = "")
160174
}
161175
})
@@ -165,6 +179,8 @@ knit_print.knitr_log <- local({
165179
#' Sets necessary knitr hooks and returns a logging function that will emit
166180
#' messages to the console during knitting.
167181
#'
182+
#' @note `r roxygen2_knitr_note()`
183+
#'
168184
#' @return A `function` accepting `...` arguments, which will be used for
169185
#' printing out to the console while rendering the knitr document. Character
170186
#' values are logged directrly, while any other object is printed as though

man/knit_print.knitr_log.Rd

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/knitr_logger.Rd

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

man/knitr_mutable_header.Rd

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/knitr_update_options.Rd

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

tests/testthat/test-utils-knitr.R

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,19 @@ writeLines(
2828
title: Example
2929
params: { options: NULL }
3030
---
31-
```{r}
31+
32+
```{r, echo = FALSE}
3233
library(val.report)
34+
35+
# logging
36+
log <- knitr_logger()
37+
log("test 1 2 3\n")
38+
39+
# update header
40+
header <- knitr_mutable_header()
41+
header$title <- "Mutable Title"
42+
43+
# update and save out options
3344
opts <- knitr_update_options(params$options)
3445
saveRDS(opts, "%s")
3546
```',
@@ -54,13 +65,10 @@ test_that(
5465
{
5566
skip_if_not_installed("rmarkdown")
5667

57-
opts <- options()
58-
on.exit(options(opts))
59-
6068
# this would work even without our function by just setting
6169
# `options(params$options)`. However, we want to make sure it still works
6270
# when it gets passed through our helper
63-
rmarkdown::render(example_qmd, params = params_r)
71+
rmarkdown::render(example_qmd, params = params_r, quiet = TRUE)
6472
parsed_options <- example_parsed_options()
6573

6674
expect_identical(parsed_options$example_2, example_2)
@@ -69,14 +77,14 @@ test_that(
6977

7078
test_that("knitr_update_options is still required for quarto::quarto_render", {
7179
skip_if_not_installed("quarto")
72-
skip_if(is.null(quarto::quarto_path()))
80+
skip_if(
81+
is.null(quarto::quarto_path()),
82+
"system `quarto` executable unavailable"
83+
)
7384

7485
# ignore this test on cran because it is testing behavior of another package
7586
skip_on_cran()
7687

77-
opts <- options()
78-
on.exit(options(opts))
79-
8088
# if this test starts to fail, it probably means that S7 has found a solution
8189
# to serializing their objects, removing the need for `knitr_update_options`
8290
#
@@ -96,10 +104,10 @@ test_that(
96104
),
97105
{
98106
skip_if_not_installed("quarto")
99-
skip_if(is.null(quarto::quarto_path()))
100-
101-
opts <- options()
102-
on.exit(options(opts))
107+
skip_if(
108+
is.null(quarto::quarto_path()),
109+
"system `quarto` executable unavailable"
110+
)
103111

104112
quarto::quarto_render(
105113
example_qmd,
@@ -112,3 +120,34 @@ test_that(
112120
expect_identical(parsed_options$example_2, example_2)
113121
}
114122
)
123+
124+
test_that("knitr_mutable_header can modify yaml frontmatter during runtime", {
125+
skip_if_not_installed("rmarkdown")
126+
127+
rmarkdown::render(
128+
example_qmd,
129+
# pass content that will be used to modify the yaml frontmatter at runtime
130+
output_file = example_md <- tempfile(fileext = ".md"),
131+
output_format = rmarkdown::github_document(),
132+
quiet = TRUE
133+
)
134+
135+
content <- readLines(example_md)
136+
expect_match(paste(content, collapse = "\n"), "^Mutable Title\n===", )
137+
})
138+
139+
test_that("knitr_logger writes to console output", {
140+
skip_if_not_installed("rmarkdown")
141+
142+
output <- capture.output({
143+
messages <- capture.output(type = "message", {
144+
rmarkdown::render(
145+
example_qmd,
146+
output_file = example_md <- tempfile(fileext = ".md"),
147+
output_format = rmarkdown::github_document()
148+
)
149+
})
150+
})
151+
152+
expect_true(any(grepl("test 1 2 3", messages)))
153+
})

0 commit comments

Comments
 (0)