Closed dereckmezquita closed 1 year ago
This sounds like something you could accomplish with an init script named ./modules/shinymodules/__init_\.R with contents like:
box::use(
./some_server_and_ui_func,
./some_other_server_and_ui_func
)
box::export(
some_server_and_ui_func,
some_other_server_and_ui_func
)
You could then easily write:
box::use(./modules/shiny_modules)
shiny_modules$some_server_and_ui_func$servec_func()
shiny_modules$some_other_server_and_ui_func$ui_func()
and it would work because box::use()
-ing a directory imports the init script as a module.
It would be great if there was method of delaying the usage of a module until it is needed, something like:
delayedAssign("some_server_and_ui_func", {
loadModule(./some_server_and_ui_func)
})
delayedAssign("some_other_server_and_ui_func", {
loadModule(./some_other_server_and_ui_func)
})
box::export(
some_server_and_ui_func,
some_other_server_and_ui_func
)
but there isn't. That being said, the method I wrote above is good enough. I hope this helps!
Yes, thank you again @ArcadeAntics this works nicely. The only friction I have is that autocompleting the functions inside that module doesn't work in VSCode (my primary editor). Autocomplete does work in RStudio though.
Thank you for the package @klmr, and you @ArcadeAntics - I keep commenting because I'm heavily using it! I think box
as a package elevates R
as a programming language. A sound modules system was severely missing from R
!
Note that you can use @export
directives directly on box::use()
declarations. So your code can be written as:
shiny_modules.R
:#' @export
box::use(
./shiny_modules/some_server_and_ui_func[
server_func
ui_func
]
)
Putting @export
on a box::use
declaration causes exactly those names to be exported which are made available by box::use
. So, in the above case, server_func
and ui_func
. Of course you can also use wildcard import (...
) which avoids having to spell out all exports manually.
Incidentally, the “canonical” style would be to have a file shiny_modules/__init__.R
instead of shiny_modules.R
. This has the advantage that you don’t need to repeat the shiny_modules
name inside the box::use
declaration:
.
├── main.R
└── modules/
├── shiny_modules/
│ ├── __init__.R
│ ├── some_other_server_and_ui_func.R
│ └── some_server_and_ui_func.R
└── some_module.R
shiny_modules/__init__.R
#' @export
box::use(./some_server_and_ui_func[...])
This should be pretty close to what you wanted to achieve. Now you can write the following in main.R
:
box::use(./modules/shiny_modules)
shiny_modules$server_func()
shiny_modules$ui_func()
If I understand correctly, your specific request is that the above should work without necessitating the need for the shiny/__init__.R
(or shiny_modules.R
) file, right? The reason why it is required is that ‘box’ encourages explicitness in defining a module’s public interface, and this would get lost if submodules were automatically exported (not to mention potential name clashes, as you mentioned). I hope you agree that the shortened shiny/__init__.R
file I showed makes it less cumbersome to have to be explicit about exports.
Regarding @ArcadeAntics’ suggestion about delayed loading: this is worth keeping in mind but I am also working on a byte-compilation cache which would make module loading faster anyway, so I am not sure having delayed loading would have a benefit. In addition, delayed loading would mess with the initialisation order of modules (i.e. the order in which the .on_load
hooks get called) and I am not sure how to fix that.
Exactly what I wanted thank you @klmr
Please describe your feature request
Desired usage
Typically I use a
modules
folder. There I store separate files or directories that house like modules. Currently working withshiny
so I would like to be able to do something like this:And then import as such:
main.R
The purpose is to be able to group modules by type/logic and easily import them.
Current solution
As of now, I have to do this to accomplish something like this:
shiny_modules.R
main.R
Instead I'd like to be able to do this:
main.R
Of course, when doing this, I have to use unique names; open to discussion and suggestions.