knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
The mod
package is designed to be used either attached or unattached to your search path.
The following demonstrations show the package attached:
require(mod)
Define an inline module:
my <- module({ a <- 1 b <- 2 f <- function(x, y) x + y })
The resulting module contains the objects defined within.
ls(my)
Subset the module to access its objects.
my$a my$b my$f(my$a, my$b)
Use with()
to aceess the objects with their bare names.
with(my, f(a,b))
Just like a package, a module can be attached to the search path.
use(my)
The my
module is attached to the search path as "module:my".
search()
And you can use the objects inside directly, just like those from a package.
f(a,b)
Detach the module from the search path when done, if desired.
drop("my")
Use refer()
to "copy" objects from another module. In the following example, we create a new module my_other
that uses the objects from my
, which is previsouly defined.
ls(my) my_other<- module({ refer(my) c <- 4 d <- 5 f <- function() print("foo") }) ls(my_other) my_other$f()
In addition to its own objects, my_other
module has all objects from my
, except f
: because my_other
module also has a f
object, and replaces the f
from my
module.
We can re-define my_other
and prepend objects from my
with my. This way, both f
s are available.
my_other <- module({ refer(my, prefix = .) c <- 4 d <- 5 f <- function() print("foo") }) ls(my_other) my_other$my.f(1, 2) my_other$f()
A variable is private if its name starts with ..
.
room_101 <- module({ ..diary <- "Dear Diary: I used SPSS today..." get_diary <- function(){ ..diary } })
A private variable cannot be seen or touched. There is no way to directly access ..diary
from the outside, except by a function defined within the module, get_diary()
. This can be useful if you want to shield some information from the other users or programs.
ls(room_101) room_101$..diary room_101$get_diary()
If using provide()
function to explicitly declair public variables, all others become private.
room_102 <- module({ provide(open_info, get_classified) open_info <- "I am a data scientist." classified_info <- "I can't get the database driver to work." get_classified <- function(){ classified_info } }) ls(room_102) room_102$open_info room_102$classified_info room_102$get_classified()
The mod
package provides a require()
function. mod:::require()
works in the same manner as do base::require()
, but makes a packages available for use in its containing module only.
mpg_analysis <- module({ require(ggplot2) plot <- qplot(mtcars$mpg) }) mpg_analysis$plot
Meanwhile, the global search path remain unaffected, not containing the ggplot2
package:
"package:ggplot2" %in% search()
mod::ule
is simple, lightweight and staright-forward. It is plain R and contains zero GMO.
Modules live any any other R object.
You do things the R way. For example, acquire()
and module()
only returns a module object; It is up to you to put it into your working environemnt with <-
.d
In this example, Bobby gets hungry, Dad complains and calls Mom:
bobby <- mod::ule({ age_now <- 14 favorite_food <- c("hamburger", "pizza", "chow mein") hungry_for <- function() { set.seed(Sys.Date()) sample(favorite_food, 1) } cry <- function(){ sprintf("I just really really want some %s, now!!!", hungry_for()) } }) dad <- mod::ule({ refer(bobby, prefix = .) provide(complain, call_mom) complain <- function(){ sprintf("When I was %d, I've already earned a living on the dock.", bobby.age_now) } call_mom <- function(){ sprintf("Honey, can you stop by the convenience store and get some %s?", bobby.hungry_for()) } })
bobby$cry() dad$complain() dad$call_mom()
It is imperative that mod
be only adopted in simple cases; no mutable state is allowed in modules. If full-featured OOP is desired, use R6
. The user is reminded that OOP, in general, should be used sparingly and with deliberation.
A module is an environment. This means that every rule that applies to environments, such as copy-by-reference, applies to modules as well.
mode(my) is.environment(my)
Some may wonder the choice of terms. Why refer()
and provide()
? Further, why not import()
and export()
? This is because we feel import and export are used too commonly, in both R, and other popular languages with varying meanings. The popular reticulate
package also uses import()
. To avoid confusion, we decided to introduce some synonyms. With analogous semantics, refer()
is borrowed from Clojure, while provide()
from Racket; Both languages are R's close relatives.
A module is locked by default. It is impossible to either change the value of a object or add a new object to a module.
my$a <- 1 my$new_var <- 1
As a general R rule, names that start with .
define hidden objects.
my_yet_another <- module({ .var <- "I'm hidden!" })
Hidden objects are not returned by ls()
, unless specified.
ls(my_yet_another) ls(my_yet_another, all.names = TRUE)
Nonetheless, in a module, they are treated the same as public objects.
my_yet_another$.var
module_path <- system.file("misc/example_module.R", package = "mod")
To load and assign to object:
example_module <- acquire(module_path) ls(example_module) example_module$a example_module$d() example_module$e(100)
To load and attach to search path:
use(module_path) ls("module:example_module") a d() e(100)
As it could be confusing how to deal with modules and packages, the following clarification is made:
require()
To the global search path, at global environment: require()
Attach a Module
To the global search path: use()
Copy Objects from a Module
refer()
To the global environment: not available**
Use Modules inside a Package?
Depends
or Imports
the mod
package*: Modules cannot be attached to another module's "seach path". Use refer()
instead to make clearly visible objects in the module context.
**: Objects cannot be batch-copied from a module to the global environment, use use()
to attach the module to the global search path in order to use them directly.
These two features seek to avoid one very important problem mod
packages intends to solve: conflicting names.
As aforementioned, the package is designed to be usable both attached and unattached.
If you use the package unattached, you must always qualify the object name with ::
, such as mod::ule()
, a shorthand for mod::module()
. However, while inside a module, the mod
package is always available, so you do not need to use ::
. Note that in the following example, provide()
inside the module expression is unqualified.
See:
detach("package:mod") my_mind <- mod::ule({ provide(good_thought) good_thought <- "I love working on this package!" bad_thought <- "I worry that no one will appreciate it." }) mod::use(my_mind) good_thought
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.