box::use() Fails for Modules Under Folders Whose Names Begin with Numbers
#248
Replies: 5 comments
-
|
Every part of the fully qualified module name needs to be a valid R name. To fix the concrete issue, backtick-quote the non-syntactic name: box::use(./path/`2`/one_number)The same is true for module names themselves: you can call a module |
Beta Was this translation helpful? Give feedback.
-
|
Regarding your other comment:
‘box’ attempts a delicate balancing act in that it attempts to be accommodating, but it is also intentionally opinionated1. The fact that fully-qualified names need to be syntactic R names is very much intentional. The local filepaths are intended to mirror R syntactic convention, rather than the other way round. In fact, don’t think of fully-qualified module names as paths at all: think of them as nested R names. They happen to map onto the filesystem, but that’s almost an accident. And arbitrary paths are not intended to be used as modules. If you have a module that’s inside an arbitrary path (e.g. The module here is
Incidentally, in the above, it must be
Yes; but, as noted, only inside the module itself. The rest of the path can be arbitrary, since it shouldn’t form part of the module name prefix. 1 This isn’t necessarily obvious but opinionated APIs are almost universally less error-prone than un-opinionated APIs, for a variety of reasons. It’s related to the idea of the pit of success: doing the right thing when using an API should be so easy that it happens “by accident”, whereas making a mistake should be hard. |
Beta Was this translation helpful? Give feedback.
-
|
Hi Konrad, Thanks as always for your thoughtful replies!
Good to know. I really should have thought to try it before bothering you, but the resulting discussion has been instructive!
I understand and certainly appreciate your opinionated convention, which is well-conceived and implemented. However, my use case is somewhat unique, since each project involves both approaches simultaneously. That is, each project has local modules and also access to global modules. The global modules are stored under a certain directory (to which I configure Now among these subdirectories are nested modules named according to semantic versioning: Now the local modules are stored in a designated subdirectory (
In summary, I really like your modular conventions for Perhaps there could be |
Beta Was this translation helpful? Give feedback.
-
Actually that’s expected to be the normal use-case: as projects get larger, it is natural to have both external dependencies and a hierarchical internal structure — hence, global and local modules.
Yes, in that case |
Beta Was this translation helpful? Give feedback.
-
To be precise, I meant the whole situation was unique: including the nested subdirectories intervening between the top of the search path and the
Sorry! You shouldn't have to explain to me the things you've already documented with so much effort. I could have sworn the Search Path section wasn't there the last time I checked, but that's probably because I've been staring at a screen for many hours.
I'd like to make a helper #####
#' @title Use Modules
#' @description Import modules (or packages) into the calling environment, as
#' found along given search paths.
#' @export
#####
#'
#' @param ... \href{https://klmr.me/box/reference/use.html#arguments}{Module
#' import declarations} passed to
#' \href{https://klmr.me/box/reference/use.html}{\code{box::use()}} in its
#' specified
#' \href{https://klmr.me/box/reference/use.html#module-names}{format}.
#' @param paths \code{character} vector. The
#' \href{https://klmr.me/box/reference/use.html#search-path}{search path}s in
#' which to search for the modules.
#'
#' @return There is no return value; see
#' \href{https://klmr.me/box/reference/use.html#value}{\code{box::use()}} for
#' further details.
#####
use_modules <- function(..., paths = "./Resources/Modules") {
# Sanitize arguments.
paths <- normalizePath(path = as.character(paths))
# Reset the 'box.path' afterwards.
original_paths <- getOption("box.path")
on.exit(expr = options(box.path = original_paths))
# Import the modules from every path.
for(path in paths[dir.exists(paths = paths)]) {
# Temporarily orient 'box.path' to the targeted path.
options(box.path = path)
# Call 'box::use()' on the modular expression.
eval.parent(expr = substitute(box::use(...)), n = 1)
}
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Naturally, one should not name their module
1_number, since this module becomes its own environment in R, and no such R objects may have a name beginning with number. The same goes for any other names illegal in R.However, if a local module
one_numbercan be found along a relative filepath./path/2/one_number.R, thenbox::use(./path/2/one_number)will fail:This is likely a minor issue, but it could throw newcomers for a loop. While everything under the global
box.pathis presumably a module (nested or otherwise) unto itself, the same cannot be said of local filepaths, and their directories (which need not be modules) should not be bound to naming conventions for R objects. Indeed, one might be forced to rename the entire subdirectory system within one's project.Is this worth a patch? Perhaps
box::use("./path/2/one_number")should be possible, if the unquoted declaration would fail...Beta Was this translation helpful? Give feedback.
All reactions