-
Notifications
You must be signed in to change notification settings - Fork 48
Description
Issue
Per the documentation for box::set_script_path(), we can capture the previous script path when setting it anew:
Value
box::set_script_pathreturns the previously set script path, orNULLif none was explicitly set.
However, when I try to capture each previous path, I get the following output
# Set new path.
box::set_script_path("C:/Users/gyannes/Documents/Test.R")
# Set another new path and capture old.
test <- box::set_script_path("C:/Users/Public/Public Documents")
test
# [1] "C:/Users/gyannes/Documents"
# Set yet another new path and capture old.
test <- box::set_script_path(".")
test
# [1] "C:/Users/Public"
where the terminal filename (Test.R) or directory name (Public Documents) is "lopped off" each captured path.
Notably, this behavior ends at the root drive, which is not lopped off:
box::set_script_path("C:/Users")
test <- box::set_script_path("C:/")
test
# [1] "C:/"
test <- box::set_script_path(".")
test
# [1] "C:/"
Thus, valuable information can be lost whenever we change a path.
Acknowledgement
After perusing the source code, I see that this behavior is due to the intentional use of dirname(), and it is baked into the script_path_env$value as soon as the script path is set. This feature is doubtless tied to important functionality, so I obviously wouldn't request a massive rewrite.
However, the manual strongly indicates the filepath itself, rather than the path to the parent directory. A slight revision to the manual would greatly improve clarity.
Request
This issue arose while I was hacking together an augmentation for box. I always like to have a get*() for every set*(), so I put together a get_script_path() function in a utility module:
#####
#' @title Get Script Path
#' @description Helper to get the script path last set by
#' \href{https://rdrr.io/cran/box/man/set_script_path.html}{box::set_script_path()}.
#' @export
#####
#'
#' @param script_env The global
#' \href{https://rdrr.io/r/base/environment.html}{environment} of the calling
#' script.
#'
#' @return A \code{character} string with the filepath to the calling script, or
#' \code{NULL} when no script path has previously been set.
#####
get_script_path <- function(script_env = parent.frame(n = 1)) {
# Capture the original script path by resetting it.
# * Since 'box' is the only package on which this module relies, and since it
# has no 'box::get_script_path()', we must use this workaround.
original_path <- evalq(
# For the appropriate side effect, it is prudent to call
# 'box::set_script_path(NULL)' as a literal command in the calling
# environment.
expr = box::set_script_path(NULL),
envir = script_env
)
# For existing path, append a "dummy" terminus that will get "lopped off" from
# the path as soon as it is set:
# https://github.com/klmr/box/blob/3d1644b8913657d236130271f340aef0c66fb4b7/R/paths.r#L18
if(length(original_path) > 0) {
new_path <- file.path(original_path, "dummy")
}
# Otherwise the path is missing ('NULL' or 'character(0)').
else {
new_path <- NULL
}
# Reset the script path to its original.
on.exit(expr = {eval(
# For the appropriate side effect, it is necessary for
# 'box::set_script_path()' to evaluate in the calling environment; yet as if
# it contained the literal string stored in 'new_path', a variable
# inaccessible to the calling environment.
# 'box::set_script_path("original/path/as/literal/string")'
expr = substitute(box::set_script_path(new_path)),
envir = script_env
)})
return(original_path)
}
However, this approach might prove unstable. Would it be possible to provide a box::get_script_path() function, which simply returns the character string currently being used as the script path?