knitr::opts_chunk$set(
  error = FALSE,
  collapse = TRUE,
  comment = "#>")

The idea here is that we want to describe how to build a "context" and then evaluate one or more expressions in it. This is a little related to approaches like docker and packrat in that we want contexts to be isolated from one another, but different in that portability is more important than isolation.

Imagine that you have an analysis to run on another computer with:

The other computer may already have some packages installed, so you don't want to waste time and bandwidth re-installing them. So things end up littered with constructs like

if (!require("mypkg")) {
  install.packages("mypkg")
  library(mypkg)
}

If these packages are coming from GitHub (or worse also have dependencies on GitHub) the bootstrap code gets out of hand very quickly and tends to be non-portable.

Creating separate libraries (rather than sharing one from your personal computer) will be important if the architecture differs (e.g., you run Windows but you want to run code on a Linux cluster).

The idea here is that context helps describe a context made from the above ingredients and then attempts to recreate it on a different computer (or in a different directory on your computer).

Contexts

A minimal context looks like this:

path <- tempfile()
ctx <- context::context_save(path = path)
ctx

Typically one would use the arguments packages and sources to describe the requirements of any tasks that you'll be running.

Tasks

Once a context is defined, tasks can be defined in the context. These are simply R expressions associated with the identifier of a context.

t <- context::task_save(quote(sin(1)), context = ctx)
t

The task t above is just a key that can be used to retrieve information about the task later.

context::task_expr(t, ctx)

Several such tasks may exist, though here only one does

context::task_list(ctx)

To run a task we first need to "load" the context (this will actual load any required packages and source any scripts) then pass this through to task_run

res <- context::task_run(t, context::context_load(ctx))

This prints the result of restoring the context and running the task:

After all that, here is the result:

res

The result can also be retrieved using task_result():

context::task_result(t, ctx)

This is not immensely useful as it is; it's just evaluation with more steps. Typically we'd do this in another process. You can do this with callr here:

res <- callr::rscript(file.path(path, "bin", "task_run"), c(path, t),
                      echo = TRUE, show = TRUE)


mrc-ide/context documentation built on June 4, 2023, 5:36 a.m.