Make or remake a module.

make(name = .Last.name, ...)

do_make(name = .Last.name, args = list(), quote = FALSE,
  envir = parent.frame(1L))

do.make(name = .Last.name, args = list(), quote = FALSE,
  envir = parent.frame(1L))

make_all(regexp, reserved = FALSE, error = stop)

make_tests()

make_all_tests(...)

Arguments

name

A string (character vector of lenght one).

A module name can contain letters, figures and some special characters, namely _, -, and /. The latter is a namespace separator.

Names containing /mock/, /mocks/, /test/, /tests/, /example/, or /examples/ have a special meaning related to code testing and examples.

The name "modulr" corresponds to a special module and is therefore reserved.

...

For make, further arguments to be passed for evaluation to the resulting function, if any. For make_all_tests, further arguments to be passed to load_all_modules.

args

A list of arguments to be passed to the resulting function, if any. The names attribute of args gives the argument names.

quote

A flag. Should the arguments be quoted?

envir

An environment within which to evaluate the function call, if any. This will be most useful if the arguments are symbols or quoted expressions.

regexp

A regular expression. If not missing, the regular expression is used to filter the names of the modules to be made.

reserved

A flag. Should special modules with a reserved name be considered?

error

A function. This function is triggered on error.

Value

The object resulting of the evaluation of the provider function of the module. If the object is a function and arguments are passed, returns the object resulting of the evaluation of the function on these arguments.

Details

A call to the make function triggers a series of actions, which are actually the core purposes of the modulr package.

  1. All dependencies are visited and defined, recursively. This process is based on the explicit and implicit rules of name resolution, as explained in define. In particular, the configurations set by root_config, paths_config, and maps_config are taken into account and every module for which changes are detected is automatically redefined.

  2. Along the lines of this recursive process, an internal representation of the dependencies and the relations between them is constructed. This provides a directed graph, which vertices represent the modules to be evaluated, and edges represent constraints on evaluations that must be performed before others.

  3. If no cycle among dependencies is detected, the graph is then a Directed Acyclic Graph (DAG), and a so called topological sorting can be performed on it to compute a well ordered sequence of evaluations.

  4. Each module provider is then evaluated in the order, or re-evaluated if outdated, with all its dependencies passed as arguments. A module is considered outdated when it has been explicitly touched or if one of its dependencies has been redefined or is itself outdated. The result of the evaluation of every module provider is stored in the modulr internal state, so that it can be reused when appropriate, without re-evaluation.

The make_all function applies make to each defined module. If a regexp is specified, this applies only to modules which name satisfies the regular expression. Similarily, the make_tests function applies to each module which name contains /test/ or /tests/. It is also possible to run tests on all modules defined in a named directory with make_all_tests.

Syntactic Sugars

variable %<=% name

name %=>% variable

variable %<<=% name

name %=>>% variable

The expressions variable %<=% name and name %=>% variable (respectively variable %<<=% name and name %=>>% variable) are just syntactic sugars for the expression variable <- make(name) (respectively variable <<- make(name)).

Warning

It is considered a very bad practice to define, touch, undefine, load, make, reset, or perform any other operation from within a module definition that may alterate the internal state of modulr.

See also

.Last.name, plot_dependencies, import_module, maps_config, paths_config, reset, and touch.

Examples

#> [2017-06-21T21:58:27 UTC] Resetting modulr state ... OK
define("foo", NULL, function() { message("Generating timestamp ...") format(Sys.time(), "%H:%M:%OS6") })
#> [2017-06-21T21:58:27 UTC] Defining 'foo' ... OK
make("foo") # timestamp evaluated at *make-time*, ...
#> [2017-06-21T21:58:27 UTC] Making 'foo' ... #> [2017-06-21T21:58:27 UTC] * Visiting and defining dependencies ... #> [2017-06-21T21:58:27 UTC] * Constructing dependency graph ... OK
#> Generating timestamp ...
#> [2017-06-21T21:58:27 UTC] DONE ('foo' in 0.012 secs)
#> [1] "21:58:27.141130"
make("foo") # only once
#> [2017-06-21T21:58:27 UTC] Making 'foo' ... #> [2017-06-21T21:58:27 UTC] * Visiting and defining dependencies ... #> [2017-06-21T21:58:27 UTC] * Constructing dependency graph ... OK #> [2017-06-21T21:58:27 UTC] DONE ('foo' in 0.012 secs)
#> [1] "21:58:27.141130"
#> [2017-06-21T21:58:27 UTC] Resetting modulr state ... OK
define("foo", NULL, function() function() { message("Generating timestamp ...") format(Sys.time(), "%H:%M:%OS6") })
#> [2017-06-21T21:58:27 UTC] Defining 'foo' ... OK
foo <- make("foo")
#> [2017-06-21T21:58:27 UTC] Making 'foo' ... #> [2017-06-21T21:58:27 UTC] * Visiting and defining dependencies ... #> [2017-06-21T21:58:27 UTC] * Constructing dependency graph ... OK #> [2017-06-21T21:58:27 UTC] DONE ('foo' in 0.011 secs)
foo() # timestamp evaluated at *run-time*, ...
#> Generating timestamp ...
#> [1] "21:58:27.190537"
foo() # again, ...
#> Generating timestamp ...
#> [1] "21:58:27.191840"
foo() # and again
#> Generating timestamp ...
#> [1] "21:58:27.193239"
#> [2017-06-21T21:58:27 UTC] Resetting modulr state ... OK
define("foo", NULL, function() { library(memoise) memoise(function() { message("Generating timestamp ...") format(Sys.time(), "%H:%M:%OS6") }) })
#> [2017-06-21T21:58:27 UTC] Defining 'foo' ... OK
foo <- make("foo")
#> [2017-06-21T21:58:27 UTC] Making 'foo' ... #> [2017-06-21T21:58:27 UTC] * Visiting and defining dependencies ... #> [2017-06-21T21:58:27 UTC] * Constructing dependency graph ... OK #> [2017-06-21T21:58:27 UTC] DONE ('foo' in 0.015 secs)
foo() # timestamp evaluated at *run-time*, but ...
#> Generating timestamp ...
#> [1] "21:58:27.243018"
foo() # only once
#> [1] "21:58:27.243018"
#> [2017-06-21T21:58:27 UTC] Resetting modulr state ... OK
define("foo", NULL, function() function(a) a + 1L)
#> [2017-06-21T21:58:27 UTC] Defining 'foo' ... OK
foo <- make("foo"); foo(1L)
#> [2017-06-21T21:58:27 UTC] Making 'foo' ... #> [2017-06-21T21:58:27 UTC] * Visiting and defining dependencies ... #> [2017-06-21T21:58:27 UTC] * Constructing dependency graph ... OK #> [2017-06-21T21:58:27 UTC] DONE ('foo' in 0.012 secs)
#> [1] 2
make("foo", 1L)
#> [2017-06-21T21:58:27 UTC] Making 'foo' ... #> [2017-06-21T21:58:27 UTC] * Visiting and defining dependencies ... #> [2017-06-21T21:58:27 UTC] * Constructing dependency graph ... OK #> [2017-06-21T21:58:27 UTC] DONE ('foo' in 0.012 secs)
#> [1] 2
do_make("foo", args = list(a = 1L))
#> [2017-06-21T21:58:27 UTC] Making 'foo' ... #> [2017-06-21T21:58:27 UTC] * Visiting and defining dependencies ... #> [2017-06-21T21:58:27 UTC] * Constructing dependency graph ... OK #> [2017-06-21T21:58:27 UTC] DONE ('foo' in 0.012 secs)
#> [1] 2
#> [2017-06-21T21:58:27 UTC] Resetting modulr state ... OK
define("A", NULL, function() "(A)")
#> [2017-06-21T21:58:27 UTC] Defining 'A' ... OK
define("B", NULL, function() "(B)")
#> [2017-06-21T21:58:27 UTC] Defining 'B' ... OK
define("C", list(a = "A"), function(a) paste0("(", a, "C)"))
#> [2017-06-21T21:58:27 UTC] Defining 'C' ... OK
define("D", list(a = "A", b = "B"), function(a, b) paste0("(", a, b, "D)"))
#> [2017-06-21T21:58:27 UTC] Defining 'D' ... OK
define("E", list(d = "D"), function(d) paste0("(", d, "E)"))
#> [2017-06-21T21:58:27 UTC] Defining 'E' ... OK
define("F", list(c = "C", d = "D", e = "E"), function(c, d, e) paste0("(", c, d, e, "F)"))
#> [2017-06-21T21:58:27 UTC] Defining 'F' ... OK
make()
#> [2017-06-21T21:58:27 UTC] Making 'F' ... #> [2017-06-21T21:58:27 UTC] * Visiting and defining dependencies ... #> [2017-06-21T21:58:27 UTC] * Constructing dependency graph ... OK #> [2017-06-21T21:58:27 UTC] * Sorting 5 dependencies with 7 relations ... on 3 layers, OK #> [2017-06-21T21:58:27 UTC] * Evaluating new and outdated dependencies ... #> [2017-06-21T21:58:27 UTC] ** Evaluating #1/5 (layer #1/3): 'B' ... #> [2017-06-21T21:58:27 UTC] ** Evaluating #2/5 (layer #1/3): 'A' ... #> [2017-06-21T21:58:27 UTC] ** Evaluating #3/5 (layer #2/3): 'C' ... #> [2017-06-21T21:58:27 UTC] ** Evaluating #4/5 (layer #2/3): 'D' ... #> [2017-06-21T21:58:27 UTC] ** Evaluating #5/5 (layer #3/3): 'E' ... #> [2017-06-21T21:58:27 UTC] DONE ('F' in 0.059 secs)
#> [1] "(((A)C)((A)(B)D)(((A)(B)D)E)F)"
define("B", NULL, function() "(B')")
#> [2017-06-21T21:58:27 UTC] Re-defining 'B' ... OK
make("F")
#> [2017-06-21T21:58:27 UTC] Making 'F' ... #> [2017-06-21T21:58:27 UTC] * Visiting and defining dependencies ... #> [2017-06-21T21:58:27 UTC] * Constructing dependency graph ... OK #> [2017-06-21T21:58:27 UTC] * Sorting 5 dependencies with 7 relations ... on 3 layers, OK #> [2017-06-21T21:58:27 UTC] * Evaluating new and outdated dependencies ... #> [2017-06-21T21:58:27 UTC] ** Evaluating #1/5 (layer #1/3): 'B' ... #> [2017-06-21T21:58:27 UTC] ** Evaluating #4/5 (layer #2/3): 'D' ... #> [2017-06-21T21:58:27 UTC] ** Evaluating #5/5 (layer #3/3): 'E' ... #> [2017-06-21T21:58:27 UTC] DONE ('F' in 0.06 secs)
#> [1] "(((A)C)((A)(B')D)(((A)(B')D)E)F)"
#> [2017-06-21T21:58:27 UTC] Resetting modulr state ... OK
tmp_dir <- tempfile("modulr_") dir.create(tmp_dir) tmp_file <- file.path(tmp_dir, "foo.R") cat('define("foo", NULL, function() "Hello World!")', file = tmp_file) root_config$set(tmp_dir) set_verbosity(1L) make("foo")
#> [1] "Hello World!"
make("foo")
#> [1] "Hello World!"
touch("foo") make("foo")
#> [2017-06-21T21:58:27 UTC] Re-defining 'foo' ... OK
#> [1] "Hello World!"
unlink(tmp_dir, recursive = TRUE) not_run({ reset() # https://gist.github.com/aclemen1/3fcc508cb40ddac6c1e3 "modulr/vault" %imports% paste0("https://gist.githubusercontent.com/aclemen1/", "3fcc508cb40ddac6c1e3/raw/modulr-vault.Rmd") list_modules() make_tests() make("modulr/vault/example") touch("modulr/vault") make_all() })