Reputation: 1004
I am using the box package. In my project, I have a functions folder, with two functions saved in there: hello.r and goodbye.r
I can load them using the box package using:
box::use(functions/hello)
box::use(functions/goodbye)
The problem is that I potentially have dozens of .r files in the functions folder (one .r file for each function).
Is there a way of loading all the .r files in one go (whilst still using the box package) without having to repeat the box::use function many times?
Upvotes: 4
Views: 541
Reputation: 545995
For what it’s worth, it’s good practice to list the imports explicitly, rather than doing a catch-all of nested files. This was a conscious design decision of ‘box’, and working around it is generally not recommended.
That said, you don’t have to repeat the box::use()
call, because box::use()
supports multiple import declarations:
box::use(
functions/hello,
functions/goodbye,
)
This is the recommended syntax for multiple imports in the same scope.
Furthermore, you can make functions
itself into a module, and make it export all nested submodules. This seems to be appropriate in your case anyway, since the actual user-facing module seems to be functions
, not each individual file in the folder — the latter should be strictly an implementation detail of the module, the user should not know or care about it.
In that case, add an __init__.r
file to the functions
folder with the following code:
#' @export
box::use(
./hello,
./goodbye,
)
Now the user only needs a single import. However, function
on its own is not a valid module name because module names (intentionally) need to be namespaced (just like GitHub projects need to be namespaced: you can’t just have a GitHub project box
, it needs to be called (e.g.) klmr/box
. So let’s say you have your module basil/functions
(i.e. move the folder functions
into a parent folder basil
which is in the module search path), then you can use your module via
box::use(basil/functions[...])
The other solutions presented here work, but they are explicitly contravening the spirit of the ‘box’ package, and if you write modules this way you are not taking best advantage of the infrastructure that ‘box’ provides. I would only ever recommend using the other solutions as a quick hack while porting large legacy projects to ‘box’ — never as a long-term solution.
Upvotes: 5
Reputation: 20399
Since box::use
uses Non-Standard Evaluation (NSE) you have to transform strings into unevaluated language objects:
rm(list = ls())
ls()
# character(0)
rex <- "\\.[rR]$"
fld <- "functions"
fs::dir_tree(fld)
# functions
# ├── goodbye.R
# └── hello.R
fns <- list.files(fld, rex) |> ## read all files in the folder
gsub(rex, "", x = _) |> ## drop extension
paste(fld, . = _, sep = "/") |> ## pre-pend folder
lapply(str2lang) ## transform string into language object
## or (`tools` is a base package)
# fns <- tools::list_files_with_exts(fld, "R") |>
# tools::file_path_sans_ext() |>
# lapply(str2lang)
## call box::use with the the newly creataed list
do.call(box::use, fns)
ls()
# [1] "fld" "fns" "goodbye" "hello" "rex"
Update based on Friede's tip to use str2lang
Upvotes: 5
Reputation: 270045
1) On Windows assume the .R files are all in the boxtest
folder. This creates a new file boxtest.R
in the current folder and then uses box::use
shell("copy boxtest\\*.R > boxtest.R")
box::use(./boxtest[...]) # or remove [...] to not export objects
On Linux we can use this instead of the shell command above.
system("cat boxtest/*.R > boxtest.R")
This will also work on Windows if Rtools is installed and the usr\bin subdirectory is on the current Windows PATH.
2) Alternately do it all in R:
writeLines(unlist(Map(readLines, Sys.glob("boxtest/*.R")), "boxtest.R")
box::use(./boxtest[...]) # or remove [...] to not export objects
3) This also seems to work althoug hit uses a function that is not exported from box and gives a few warnings but it is short and is entirely in R:
Map(box:::box_source, Sys.glob("boxtest/*.R"))
or forget about box and just use source directly:
Map(source, Sys.glob("boxtest/*.R"))
Upvotes: 3