A package can import modulr for its own usage. There are then essentially two different and complementary ways to exploit all of the modulr features: for the limited scope of the internals of the package itself and/or for an exported usage.

Internal scope

In this use case, modules are defined and used inside the package’s namespace, without interference with any usage that could be made of modulr outside of the package. Something ressembling the following lines of code should then appear in your ./R package files:

# File: ./R/init.R

#' @import modulr
NULL

my_package_injector <- get_default_injector()
set_verbosity(0L)

Notice that we are using Roxygen2’s @import tag here to easily populate the NAMESPACE file of the package with an appropriate import field (the @importFrom tag could also import only a selected subset of exported methods from modulr), so that the prefix modulr:: can be omitted in front of modulr methods (in particular for syntactic sugars like %provides% and %requires%, see infra).

It is also important to make sure that this portion of code is loaded before defining and using modules, which is guaranteed by the @include tag (or by manually specifying a collation order in the NAMESPACE file), as shown in the following example:

# File: ./R/greetings.R

#' @include init.R
NULL

"hello" %provides% "Hello"

"world" %provides% "World"

"greetings" %requires% list(
  hello = "hello",
  world = "world"
) %provides% {
  paste0(hello, ", ", tolower(world), "!")
}

#' @export
say_hello <- function() {
  with_injector(my_package_injector, make("greetings"))
}

Notice the with_injector wrapper around make("greetings") in the body of the exported say_hello function: since say_hello is suscpetible to be called from outside of the package’s namespace, it is important to specify explicitely that the make call relies on the package’s default injector captured in the ./R/init.R file.

It is also possible to use the injector’s get method:

#' @export
say_hello <- function() {
  my_package_injector$get("greetings")
}

Notice that none of the modules is directly exposed by the package:

library(my_package)
(modulr::lsmod())
#> NULL

Exported usage

In this situation, the package is intended to provide the user with a predefined set of modules. The following example shows how to use the .onLoad hook function to define a module, just before sealing the namespace of the package and processing exports:

# File: ./R/zzz.R

.onLoad <- function(libname, pkgname) {

  with_injector(get_default_injector(), {
    set_verbosity(0L)
    "foobar" %provides% "FOOBAR"
  })
  
  invisible(NULL)

}

When the package is loaded, the "foobar" module is defined within the scope of the default modulr injector situated outside of the package’s namespace. It is then accessible by the user of the package:

library(my_package)
modulr::lsmod()
#>     name version   storage along type weight calls dependencies uses
#> 1 foobar    <NA> in-memory  <NA> <NA>   <NA>     0            0    0
#>        size lines                modified
#> 1 152 bytes     2 2018-12-02T16:14:51 UTC

Modules in inst/modules

Finally, it is possible to define an entire set of on-disk modules at once in the ./inst/modules directory. For instance:

# File: ./inst/modules/foo.R

library(modulr)

"foo" %provides% "FOO"

In this case, it is necessary to add the path of the modules sub-directory of the installed package to the modulr’s root paths. The system.file function is tailored for this kind of situation:

# File: ./R/zzz.R

.onLoad <- function(libname, pkgname) {

  # ...

  with_injector(get_default_injector(), {
    root_config$set(c(
      root_config$get_all()[[1L]], 
      system.file("modules", package = "my_package")))
  })
  
  invisible(NULL)

}

Once the package is loaded, the installed modules directory is then reachable:

library(my_package)
modulr::make("foo")
#> [2018-12-02T16:14:52 UTC] Resetting modulr state ... OK
#> [2018-12-02T16:14:52 UTC] Defining 'foo' ... OK
#> [2018-12-02T16:14:52 UTC] Making 'foo' ...
#> [2018-12-02T16:14:52 UTC] * Visiting and defining dependencies ...
#> [2018-12-02T16:14:52 UTC] * Constructing dependency graph ... OK
#> [2018-12-02T16:14:52 UTC] DONE ('foo' in 0.018 secs)
#> [1] "FOO"