How can I reload a custom module using r-box

226 Views Asked by At

I start to use the R package box, but struggle during development of nested dependencies.

Setup

Usually I develop a first function helper.R:

# helper.R
helper <- function(i) {
  return(paste("help", i))
}

Then a I use it in a wrapper:

# wrapper.R
box::use(./helper[helper])
lapply(1:3, helper)

Returning:

r$> lapply(1:3, helper)
[[1]]
[1] "help 1"

[[2]]
[1] "help 2"

[[3]]
[1] "help 3"

So far so good :-)

Problem

Do not restart the R-session! Now, I change my helper:

# helper.R
helper <- function(i) {
  return(paste("Please help", i))
}

I would like to do box::reload(./helper[helper]) or box::reload("helper") to use the update helper function, but I get this Error:

"reload" expects a module object, got "helper", which is not a module alias variable

I was expecting that box::name() would return this "module alias variable", but it does not :-( It returns "helper" which does not work with box::reload().

I am clearly missing some terminology AND/OR syntax here? Can you please clarify how I can reload a local module without restarting the R session?

Thanks!

2

There are 2 best solutions below

1
On BEST ANSWER

box::reload (and box::unload) expect a module object as their argument — not a name or path.

This means that the following works:

box::use(./helper)
lapply(1:3, helper$helper)

# …

box::reload(helper)
lapply(1:3, helper$helper)
# [[1]]
# [1] "please help 1"
#
# [[2]]
# [1] "please help 2"
#
# [[3]]
# [1] "please help 3"

However, ‘box’ does not support reloading attached names. As a workaround you can use the “nuclear” option for now:

box::purge_cache()
box::use(./helper[helper])

In the future, ‘box’ will implement hot code reloading, which will make explicit calls to box::reload or box::purge_cache mostly unnecessary.

2
On

Workaround

Reading the vignette carefully is always a good idea.

If you box::use() a function from a module directly, it is loaded into into the Attached Namespace that can be listed via search() (not via ls()):

r$> search()
 [1] ".GlobalEnv"        "mod:./helper"      "tools:vscode"      "package:stats"     "package:graphics"  "package:grDevices" "package:utils"     "package:datasets"  "package:methods"   "Autoloads"
[11] "org:r-lib"         "package:base"

Now, I can use this string to detach() the module from the Namespace, load the module again with the updated code:

r$> detach("mod:./helper")
r$> box::use(./helper[helper])
r$> lapply(1:3, helper)
[[1]]
[1] "Please help 1"

[[2]]
[1] "Please help 2"

[[3]]
[1] "Please help 3"

Minimal code for reload

wrapper.R:

box::use(./helper)
lapply(1:3, helper$helper)

Now the whole module helper.R is loaded into the environment and can be listed with ls():

r$> ls()
[1] "helper"

Now, box::reload(helper) can be called :-)

Question

Is there a 1-liner to reload a single function from box::use(./helper[helper])?