Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement local_reproducible_output() #190

Merged
merged 7 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export(is.message)
export(is.recordedplot)
export(is.source)
export(is.warning)
export(local_reproducible_output)
export(new_output_handler)
export(parse_all)
export(remove_hooks)
Expand Down
103 changes: 103 additions & 0 deletions R/reproducible-output.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#' Control common output options
#'
#' @description
#' Often when using `evaluate()` you are running R code with a specific output
#' context in mind. But there are many options and env vars that packages
#' will take from the current environment, meaning that output depends on
#' the current state in undesirable ways.
#'
#' This function allows you to describe the characteristics of the desired
#' output and takes care of setting the options and environment variables
#' for you.
#'
#' @export
#' @param width Value of the `"width"` option.
#' @param color Determines whether or not cli/crayon colour should be used.
#' @param unicode Should we use unicode characaters where possible?
#' @param hyperlinks Should we use ANSI hyperlinks?
#' @param rstudio Should we pretend that we're running inside of RStudio?
#' @param frame Scope of the changes; when this calling frame terminates the
#' changes will be undone. For expert use only.
local_reproducible_output <- function(width = 80,
color = FALSE,
unicode = FALSE,
hyperlinks = FALSE,
rstudio = FALSE,
frame = parent.frame()) {

local_options(
# crayon
crayon.enabled = color,

# cli
cli.width = width,
cli.condition_width = width,
cli.num_colors = if (color) 8L else 1L,
cli.hyperlink = hyperlinks,
cli.hyperlink_run = hyperlinks,
cli.hyperlink_help = hyperlinks,
cli.hyperlink_vignette = hyperlinks,
cli.unicode = unicode,
cli.dynamic = FALSE,

# base R
width = width,
useFancyQuotes = FALSE,
hadley marked this conversation as resolved.
Show resolved Hide resolved
rlang_interactive = FALSE,

.frame = frame
)

local_envvar(
NO_COLOR = if (color) NA else 1,

# Simulate RStudio
RSTUDIO = if (rstudio) 1 else NA,
RSTUDIO_SESSION_PID = if (rstudio) Sys.getpid() else NA,
RSTUDIO_CHILD_PROCESS_PANE = if (rstudio) "build" else NA,
RSTUDIO_CLI_HYPERLINKS = if (rstudio) 1 else NA,
RSTUDIO_CONSOLE_WIDTH = width,
.frame = frame
)

local_collate("C", frame = frame)

invisible()
}

local_options <- function(..., .frame = parent.frame()) {
old <- options(...)
defer(options(old), .frame)

invisible()
}

local_envvar <- function(..., .frame = parent.frame()) {
old <- set_envvar(list(...))
defer(set_envvar(old), .frame)

invisible()
}

local_collate <- function(locale, frame = parent.frame()) {
hadley marked this conversation as resolved.
Show resolved Hide resolved
old <- Sys.getlocale("LC_COLLATE")
defer(Sys.setlocale("LC_COLLATE", old), frame)
Sys.setlocale("LC_COLLATE", locale)

invisible()
}

# adapted from withr:::set_envvar
set_envvar <- function(envs) {
if (length(envs) == 0) {
return()
}

old <- Sys.getenv(names(envs), names = TRUE, unset = NA)
set <- !is.na(envs)

if (any(set)) do.call("Sys.setenv", as.list(envs[set]))
if (any(!set)) Sys.unsetenv(names(envs)[!set])

invisible(old)
}
39 changes: 39 additions & 0 deletions man/local_reproducible_output.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion man/parse_all.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions tests/testthat/test-reproducible-output.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
test_that("local_reproducible_output() respects local context", {

local_reproducible_output(width = 105)
expect_equal(getOption("width"), 105)

local({
local_reproducible_output(width = 110)
expect_equal(getOption("width"), 110)
})

expect_equal(getOption("width"), 105)
})

test_that("local_envvar respects local context", {
local_envvar(test = "a")
expect_equal(Sys.getenv("test"), "a")

local({
local_envvar(test = "b")
expect_equal(Sys.getenv("test"), "b")
})

expect_equal(Sys.getenv("test"), "a")
local({
local_envvar(test = NA)
expect_equal(Sys.getenv("test"), "")
})

expect_equal(Sys.getenv("test"), "a")
})

test_that("local_collate respects local context", {
if (Sys.info()[["sysname"]] == "Windows") {
locale <- l10n_info()$codeset
} else {
locale <- "en_US"
}

local_collate("C")
expect_equal(Sys.getlocale("LC_COLLATE"), "C")

local({
local_collate(locale)
expect_equal(Sys.getlocale("LC_COLLATE"), locale)
})

expect_equal(Sys.getlocale("LC_COLLATE"), "C")
})
Loading