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(pattern = NULL, ignore.case = FALSE, perl = FALSE, fixed = FALSE, useBytes = FALSE, invert = FALSE) make_all_tests(...)
name | A string (character vector of lenght one). A module name can contain letters, figures and some special characters,
namely Names containing The name "modulr" corresponds to a special module and is therefore reserved. |
---|---|
... | For |
args | A list of arguments to be passed to the resulting function, if
any. The |
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. |
pattern | character string containing a regular expression
(or character string for |
ignore.case | if |
perl | logical. Should Perl-compatible regexps be used? |
fixed | logical. If |
useBytes | logical. If |
invert | logical. If |
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.
A call to the make
function triggers a series of actions, which are
actually the core purposes of the modulr package.
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.
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.
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.
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 touch
ed 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
.
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)
).
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.
.Last.name
, plot_dependencies
,
import_module
, maps_config
,
paths_config
, reset
, and touch
.
reset()#> [2018-12-02T17:14:05 CET] Resetting modulr state ... OKdefine("foo", NULL, function() { message("Generating timestamp ...") format(Sys.time(), "%H:%M:%OS6") })#> [2018-12-02T17:14:05 CET] Defining 'foo' ... OKmake("foo") # timestamp evaluated at *make-time*, ...#> [2018-12-02T17:14:05 CET] Making 'foo' ... #> [2018-12-02T17:14:05 CET] * Visiting and defining dependencies ... #> [2018-12-02T17:14:05 CET] * Constructing dependency graph ... OK#>#> [2018-12-02T17:14:05 CET] DONE ('foo' in 0.027 secs)#> [1] "17:14:05.554048"make("foo") # only once#> [2018-12-02T17:14:05 CET] Making 'foo' ... #> [2018-12-02T17:14:05 CET] * Visiting and defining dependencies ... #> [2018-12-02T17:14:05 CET] * Constructing dependency graph ... OK #> [2018-12-02T17:14:05 CET] DONE ('foo' in 0.026 secs)#> [1] "17:14:05.554048"reset()#> [2018-12-02T17:14:05 CET] Resetting modulr state ... OKdefine("foo", NULL, function() function() { message("Generating timestamp ...") format(Sys.time(), "%H:%M:%OS6") })#> [2018-12-02T17:14:05 CET] Defining 'foo' ... OKfoo <- make("foo")#> [2018-12-02T17:14:05 CET] Making 'foo' ... #> [2018-12-02T17:14:05 CET] * Visiting and defining dependencies ... #> [2018-12-02T17:14:05 CET] * Constructing dependency graph ... OK #> [2018-12-02T17:14:05 CET] DONE ('foo' in 0.026 secs)foo() # timestamp evaluated at *run-time*, ...#>#> [1] "17:14:05.636840"foo() # again, ...#>#> [1] "17:14:05.638202"foo() # and again#>#> [1] "17:14:05.639570"reset()#> [2018-12-02T17:14:05 CET] Resetting modulr state ... OKdefine("foo", NULL, function() { library(memoise) memoise(function() { message("Generating timestamp ...") format(Sys.time(), "%H:%M:%OS6") }) })#> [2018-12-02T17:14:05 CET] Defining 'foo' ... OKfoo <- make("foo")#> [2018-12-02T17:14:05 CET] Making 'foo' ... #> [2018-12-02T17:14:05 CET] * Visiting and defining dependencies ... #> [2018-12-02T17:14:05 CET] * Constructing dependency graph ... OK #> [2018-12-02T17:14:05 CET] DONE ('foo' in 0.027 secs)foo() # timestamp evaluated at *run-time*, but ...#>#> [1] "17:14:05.690563"foo() # only once#> [1] "17:14:05.690563"reset()#> [2018-12-02T17:14:05 CET] Resetting modulr state ... OK#> [2018-12-02T17:14:05 CET] Defining 'foo' ... OKfoo <- make("foo"); foo(1L)#> [2018-12-02T17:14:05 CET] Making 'foo' ... #> [2018-12-02T17:14:05 CET] * Visiting and defining dependencies ... #> [2018-12-02T17:14:05 CET] * Constructing dependency graph ... OK #> [2018-12-02T17:14:05 CET] DONE ('foo' in 0.027 secs)#> [1] 2make("foo", 1L)#> [2018-12-02T17:14:05 CET] Making 'foo' ... #> [2018-12-02T17:14:05 CET] * Visiting and defining dependencies ... #> [2018-12-02T17:14:05 CET] * Constructing dependency graph ... OK #> [2018-12-02T17:14:05 CET] DONE ('foo' in 0.026 secs)#> [1] 2do_make("foo", args = list(a = 1L))#> [2018-12-02T17:14:05 CET] Making 'foo' ... #> [2018-12-02T17:14:05 CET] * Visiting and defining dependencies ... #> [2018-12-02T17:14:05 CET] * Constructing dependency graph ... OK #> [2018-12-02T17:14:05 CET] DONE ('foo' in 0.026 secs)#> [1] 2reset()#> [2018-12-02T17:14:05 CET] Resetting modulr state ... OK#> [2018-12-02T17:14:05 CET] Defining 'A' ... OK#> [2018-12-02T17:14:05 CET] Defining 'B' ... OK#> [2018-12-02T17:14:05 CET] Defining 'C' ... OK#> [2018-12-02T17:14:05 CET] Defining 'D' ... OK#> [2018-12-02T17:14:05 CET] Defining 'E' ... OK#> [2018-12-02T17:14:05 CET] Defining 'F' ... OKmake()#> [2018-12-02T17:14:05 CET] Making 'F' ... #> [2018-12-02T17:14:05 CET] * Visiting and defining dependencies ... #> [2018-12-02T17:14:06 CET] * Constructing dependency graph ... OK #> [2018-12-02T17:14:06 CET] * Sorting 5 dependencies with 7 relations ... on 3 layers, OK #> [2018-12-02T17:14:06 CET] * Evaluating new and outdated dependencies ... #> [2018-12-02T17:14:06 CET] ** Evaluating #1/5 (layer #1/3): 'B' ... #> [2018-12-02T17:14:06 CET] ** Evaluating #2/5 (layer #1/3): 'A' ... #> [2018-12-02T17:14:06 CET] ** Evaluating #3/5 (layer #2/3): 'C' ... #> [2018-12-02T17:14:06 CET] ** Evaluating #4/5 (layer #2/3): 'D' ... #> [2018-12-02T17:14:06 CET] ** Evaluating #5/5 (layer #3/3): 'E' ... #> [2018-12-02T17:14:06 CET] DONE ('F' in 0.15 secs)#> [1] "(((A)C)((A)(B)D)(((A)(B)D)E)F)"#> [2018-12-02T17:14:06 CET] Re-defining 'B' ... OKmake("F")#> [2018-12-02T17:14:06 CET] Making 'F' ... #> [2018-12-02T17:14:06 CET] * Visiting and defining dependencies ... #> [2018-12-02T17:14:06 CET] * Constructing dependency graph ... OK #> [2018-12-02T17:14:06 CET] * Sorting 5 dependencies with 7 relations ... on 3 layers, OK #> [2018-12-02T17:14:06 CET] * Evaluating new and outdated dependencies ... #> [2018-12-02T17:14:06 CET] ** Evaluating #1/5 (layer #1/3): 'B' ... #> [2018-12-02T17:14:06 CET] ** Evaluating #4/5 (layer #2/3): 'D' ... #> [2018-12-02T17:14:06 CET] ** Evaluating #5/5 (layer #3/3): 'E' ... #> [2018-12-02T17:14:06 CET] DONE ('F' in 0.14 secs)#> [1] "(((A)C)((A)(B')D)(((A)(B')D)E)F)"#> [2018-12-02T17:14:06 CET] Resetting modulr state ... OKtmp_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!"#> [2018-12-02T17:14:06 CET] 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() })