I would like to load a library function within a script evaluated in a specified environment.
Example:
## foo.R
## -----
## blah blah
library(extrafont)
loadfonts()
Assuming for convenience the evaluation environment is the base environment:
sys.source("foo.R")
## Registering fonts with R
## Error in eval(expr, envir, enclos) : could not find function "loadfonts"
Replacing loadfonts()
with extrafont:::loadfonts()
works better, but still gives:
Error in get(as.character(FUN), mode = "function", envir = envir) :
object 'pdfFonts' of mode 'function' was not found
because loadfonts()
requires pdfFonts()
defined in grDevices
.
This is both a not totally satisfactory answer and a long comment to @waterling.
The proposed solution is:
i.e.
which is substantially equivalent to:
It works for much the same reason why:
As reported in the error (see question), the function not found,
pdfFonts()
is part of the packagegrDevices
Thesys.source
above executes the script in thepackage:grDevices
environment, hence the function is found. Instead by defaultsys.source(..., envir=baseenv())
and the base environment comes beforegrDevices
, thereforepdfFonts()
is not found.A first problem is that I do not know in advance which functions will happen to be in my script. In this case setting
envir=new.env()
is a more general approach. By defaultnew.env(parent=parent.frame())
, therefore it has the same parent ofsys.source()
, which is the global environment. So everything visible in the global environment is visible in the script withsys.source(..., envir=new.env())
, that is every object created by the user and by the user loaded packages.The problem here is that we are not insulating the script any more, which makes it less reproducible and stable. In fact, it depends on what is in R memory in the very moment we call
sys.source
. To make the things more practical, it meansfoo.R
might work just because we usually call it afterbar.R
.A second problem is that this not an actual solution. The question concerns how to run a script
foo.R
in an environmente
and still access, when needed, to functions not belonging toe
. Taking ane
that (directly or through its parents) has access to these functions is actually a workaround, not a solution.If this type of workaround is the only possible way to go, IMHO, the best is to make it dependent only on standard R packages.
At start, R shows:
that is eight official packages/environments.
New packages/environments, unless explicitly changing the default, go into the second slot and all those after the first one shift one position.
So we can take the last eight in the search path, which means taking the first of these eight inheriting the others. We need:
Therefore:
or one can take a standard R reference package, say
stats
, and its parents.Therefore:
UPDATE
I found the
SOLUTION
As for the script:
To execute in a new environment:
f()
now has access to all objects in the packageextrafont
and those loaded before it.In
sys.source()
creating anew.env()
with whatever parent is necessary to makeenvironment()
assignment work.