staticimports makes it easy to statically import functions into R projects or packages. The “static” importing means that the functions are copied into the project as text, instead of being loaded from a separate package at run time.
The benefits of doing things this way:
Where can statically imported functions come from?
inst/staticexports/
directory. This includes the staticimports package itself, which contains many utility functions in inst/staticexports/
.Instead of copying and pasting utility functions from project to project, the utility functions can be centralized in a place where they can be vetted and tested.
The functions in staticimports are designed to be:
If your project imports a function from staticimports, and that function changes in a way that has a negative impact on your project, you can simply stop importing it from staticimports, and copy the old version to a separate file.
You can install the development version of staticimports with:
remotes::install_github("wch/staticimports")
To use, put a comment block starting with # @staticimports
in one of your R source files. For example, your utils.R
may have this at the top:
The pkg:staticimports
tells it to import from staticimports package. To import from a different package, use pkg:mypackage
. It looks in a directory of the package named staticexports
to find the objects. To import from a local absolute or relative path, you can use something like @staticimports ../r_utils/
.
The following lines name the objects to import from the source. In this case, they are os_name
, %||%
, map
, and walk
.
To perform the import, run:
By default this will write the functions to a file R/staticimports.R
in your project.
You examine the output by writing to stdout()
instead of R/staticimports.R
. Notice how importing os_name
automatically brings in is_windows
, is_mac
, and is_linux
.
#> # Generated by staticimports; do not edit by hand.
#> # ======================================================================
#>
#> `%||%` <- function(a, b) {
#> if (is.null(a)) b else a
#> }
#>
#> is_linux <- function() Sys.info()[['sysname']] == 'Linux'
#>
#> is_mac <- function() Sys.info()[['sysname']] == 'Darwin'
#>
#> is_windows <- function() .Platform$OS.type == "windows"
#>
#> map <- function(.x, .f, ...) {
#> lapply(.x, .f, ...)
#> }
#>
#> os_name <- function() {
#> if (is_windows()) {
#> "win"
#> } else if (is_mac()) {
#> "mac"
#> } else if (is_linux()) {
#> "linux"
#> } else if (.Platform$OS.type == "unix") {
#> "unix"
#> } else {
#> "unknown"
#> }
#> }
#>
#> walk <- function(.x, .f, ...) {
#> for (i in seq_along(.x)) {
#> .f(.x[[i]], ...)
#> }
#> NULL
#> }
For testing what the output will look like, you can use import_objs()
to see what it looks like when you import specific objects by name:
import_objs(c("map", "walk"), outfile = stdout())
#> # Generated by staticimports; do not edit by hand.
#> # ======================================================================
#>
#> map <- function(.x, .f, ...) {
#> lapply(.x, .f, ...)
#> }
#>
#> walk <- function(.x, .f, ...) {
#> for (i in seq_along(.x)) {
#> .f(.x[[i]], ...)
#> }
#> NULL
#> }
The functions provided by staticimports are in the inst/staticexports directory of the repository. When import()
is called, it sources all of those files into a new environment. Then it finds all the internal dependencies among those functions. If a function fn_a
is requested, and it uses a function fn_b
, then both of those functions will be copied to the project.
If a different set of source files is used, it sources all of the files in the target directory into a new environment and then proceeds the same way.