There are some files containing work under progress that I'd like to exclude from the entire build process (checking, installing, even documenting if possible), but not loading (devtools::load_all()
).
I always name them dev-{feature}.R
so I was about to use a wildcard, but it happened that I was not even able to exclude a single file from the build.
For debugging, I created an R file as "R/dev-myfeature.R" containing only the line stop("TEST")
. I then ran usethis::use_build_ignore("R/dev-myfeature.R")
, which added ^R/dev-myfeature\.R$
in the .Rbuildignore
file.
Whether I run devtools::load_all(".")
, devtools::check()
or even devtools::document()
, I get the TEST
error, so .Rbuildignore
was ignored. Since it works fine with all other files, I guess it has no power inside the R
folder.
Is there any way around this limitation?
Otherwise, what would be a good workflow for work-in-progress files that should not be part of the build yet?
I think the .Rbuildignore
file is useful for bundling of your package, and that's about it. If you want certain functionality in R/*.R
files but only on your console when testing, then you may consider structuring the test files with a wrapping if
expression.
For example, I'll the existence and true-ness of a variable named MYDEV
to declare that I want to load the contents of the file.
if (exists("MYDEV") && MYDEV) {
stop("TEST")
}
In a default environment (MYDEV
not defined), load_all
, check
, and document
do not see the error. The use of exists(...)
helps ensure that this will not error (object not found
) in a different R instance, either on your computer or elsewhere.
If you set MYDEV <- TRUE
, then all the devtools
functions will see the stop
and error accordingly. I believe there is no (reasonable) way to get the code sourced in load_all
and not with document
.
One problem you have with not erring with devtools::document
is that it calls devtools::load_all
internally, as such simple tests do not work. One could adapt a function from https://stackoverflow.com/a/62747050/3358272, with:
search_calling_pkg <- function(pkgs, funcs) {
# <borrowed from="rlang::trace_back">
frames <- sys.frames()
idx <- rlang:::trace_find_bottom(NULL, frames)
frames <- frames[idx]
parents <- sys.parents()[idx]
calls <- as.list(sys.calls()[idx])
calls <- purrr::map(calls, rlang:::call_fix_car)
#==# calls <- lapply(calls, rlang:::call_fix_car)
calls <- rlang:::add_pipe_pointer(calls, frames)
calls <- purrr::map2(calls, seq_along(calls), rlang:::maybe_add_namespace)
#==# calls <- Map(rlang:::maybe_add_namespace, calls, seq_along(calls))
# </borrowed>
calls_chr <- vapply(calls, function(cl) as.character(cl)[1], character(1))
ptn <- paste0("^(", paste(pkgs, collapse = "|"), ")::")
pkgres <- any(grepl(ptn, calls_chr))
funcres <- !missing(funcs) && length(calls_chr) &&
any(mapply(grepl, paste0("(^|::)", funcs, "$"), list(calls_chr)))
return(pkgres && funcres)
}
This function returns true if any of the package/function pairs are found, and this combination will "see" (error on) stop("TEST")
with devtools::load_all
but not with devtools::document
:
if (search_calling_pkg("pkgload", "load_all") &&
!search_calling_pkg("devtools", "document")) {
stop("TEST")
}
Yes, this means you need search_calling_pkg
somewhere in your environment, whether part of this package or not. Recall that if the .Rbuildignore
file includes R/dev-myfeature.R
, then package bundles and all down-stream users will never see this code. If you wanted to be even more defensive, you could use
if (exists("search_calling_pkg") &&
search_calling_pkg("pkgload", "load_all") &&
!search_calling_pkg("devtools", "document")) {
stop("TEST")
}