define: Define a Module.

Description Usage Arguments Details Value Syntactic Sugars Warning See Also Examples

View source: R/define.R

Description

Define or redefine a module by name, dependencies, and provider.

Usage

1
define(name, dependencies = NULL, provider = function() NULL)

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.

dependencies

A (preferably named) list of strings.

Elements of the list of dependencies designate modules by their name.

provider

A string, a braced expression, or a function.

If any, function's formals must coincide with the list of dependencies.

Details

The definition of a module can be done explicitly in the console, implicitly from a file on a disk, or remotely at a given URL via the HTTP(S) protocol. These three ways of defining modules have their specificities.

Explicit Definition

This is the most direct method to define or redefine a module. This is also the most volatile since the lifespan of the module is limited to the R session. When a new module is defined, the internal state of the package is modified to record its name, dependencies and provider. Some other useful metadata are also recorded, like timestamps, various flags and counters, and a digest. When an existing module is redefined, the internal state is updated accordingly, unless no change is detected by digests comparison. No other side-effect occurs during the definition process, notably the evaluation of the provider which is postponed to a subsequent make call.

Implicit Definition

This is the natural method to choose when a module is intended to be reused. In such a case, the definition takes place in a dedicated file, which name is closely related to the module's name.

As a file /home/user/readme.txt is composed of a path /home/user and a file name readme.txt, a module name vendor/tool/swissknife is similarily composed of a namespace vendor/tool and a local name swissknife. For modulr to find this module, it is sufficient to store its definition in an R, R Markdown or R Sweave file named swissknife.R[md|nw] (R files have precedence over Rmd's and Rnw's), laid out on disk in the vendor/tool path, relative to the modulr root directory (see root_config).

  • vendor/

    • tool/

      • swissknife.R,

        contains the "vendor/tool/swissknife" definition.

Each time the definition of a module is needed, modulr resolves its name into a file location by applying the following configurable rules.

  1. The root_config accessor acts at the filesystem level, by specifying the root directory, relative to which all paths are expressed. For instance, root_config$set("./lib") tells modulr that all modules are to be found in lib (in the R working directory). The directory path can be relative (e.g. ./lib) or absolute (e.g. /home/user/lib). By default, modulr looks in turn into the following directories "./module", "./modules", "./lib", "./libs", and ".".

  2. The paths_config accessor acts at the namespace level, by mapping a specific namespace to a dedicated path, relative to the root directory. For instance, paths_config$set("vendor" = "third_parties/vendor") will map the vendor/great_module to the third_parties/vendor/great_module.R path, relative to the root directory.

    • third_parties

      is intended to be a dedicated container for third-parties modules.

      • vendor

        • great_module.R

          contains the "vendor/great_module" definition.

  3. The maps_config accessor acts at the module level, by substituting specific dependencies within the scope of a given module. This is especially useful in a situation where a dependency has been replaced by a newer version, but a module still needs to rely on the previous one. For instance, maps_config$set("foo/bar" = list("vendor/great_module" = "vendor/old_great_module")) tells modulr that for the module foo/bar only, the dependency vendor/great_module must be replaced by vendor/old_great_module.

  • foo

    • bar.R

      depends on vendor/great_module by definition, but will be replaced by vendor/old_great_module when needed.

  • vendor

    • great_module.R

      serves all modules that depend on it, except foo/bar.

    • old_great_module.R

      serves foo/bar only.

These rules are applied in reverse order, substituting dependencies first, then mapping namespaces and finally expressing the absolute path, relative to the modulr root directory.

It is possible to store several definitions into one main file. By doing so, the implicit definition of the main module (i.e. the module for which the name is resolved into the file location) triggers the simultaneous definition of a bunch of related modules. It is notably desirable for test purposes, when a module and its dependencies have to be mocked and injected into a new, testing module.

Remote Definition

This is the method used to share a module via the HTTP(S) protocol. The module is thus served at a given URL and has to be imported (see import_module) in order to be defined and used. Like files, it is possible to store several related definitions at one URL. Public and private gists, files on GitHub, and any HTTP server can be used to share so called modulr gears.

Value

A wrapper function around a make call for the defined module.

Syntactic Sugars

1
name %provides% provider
1
name %requires% dependencies %provides% provider

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, make, maps_config, paths_config, reset, touch, and undefine.

Examples

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
reset()
define("foo", NULL, "Hello")
bar <- define("bar", list(foo = "foo"), { paste(foo, "World!") })
bar()
define("foo", NULL, "Again, Hello")
bar()

reset()
"foo" %provides% "Hello"
"bar" %requires% list(
  foo = "foo"
) %provides% {
  paste(foo, "World!")
}
make()
"foo" %provides% "Again, Hello"
make("bar")

reset()
define("A", list(b = "B"), function(b) NULL)
define("B", list(a = "A"), function(a) NULL)
## Not run: make()

reset()
define("A", NULL, function() NULL)
define("B", NULL, function() NULL)
define("C", list(a = "A"), function(a) NULL)
define("D", list(a = "A", b = "B"), function(a, b) NULL)
define("E", list(d = "D"), function(d) NULL)
define("F", list(c = "C", d = "D", e = "E"), function(c, d, e) NULL)
plot_dependencies()
make()

openscienceunil/modulr documentation built on May 3, 2019, 5:49 p.m.