Title: | Manage R Environments Better |
---|---|
Description: | Provides a small set of functions for managing R environments, with defaults designed to encourage usage patterns that scale well to larger code bases. It provides: import_from(), a flexible way to assign bindings that defaults to the current environment; include(), a vectorized alternative to base::source() that also default to the current environment; and attach_eval() and attach_source(), a way to evaluate expressions in attached environments. Together, these (and other) functions pair to provide a robust alternative to base::library() and base::source(). |
Authors: | Tomasz Kalinowski [aut, cre] |
Maintainer: | Tomasz Kalinowski <[email protected]> |
License: | GPL-3 |
Version: | 0.3.0 |
Built: | 2024-11-15 04:35:45 UTC |
Source: | https://github.com/t-kalinowski/envir |
Evaluate R expressions in an attached environment.
attach_eval( unquoted_expr, name = "local:utils", pos = 2L, warn.conflicts = TRUE, ..., expr = substitute(unquoted_expr), mask.ok = NULL )
attach_eval( unquoted_expr, name = "local:utils", pos = 2L, warn.conflicts = TRUE, ..., expr = substitute(unquoted_expr), mask.ok = NULL )
unquoted_expr |
The expression to be evaluated, This is automatically quoted. |
name |
The environment name. If an environment of that name already exists, it is reused, otherwise, a new environment is attached. |
pos |
The position where to attach the environment, if creating a new
one. If an environment of |
warn.conflicts |
logical. If TRUE (the default), print warnings about objects in the attached environment that that are masking or masked by other objects of the same name. |
... |
Ignored. |
expr |
An R language object. This is an escape hatch from the automatic
quoting of |
mask.ok |
character vector of names of objects that can mask objects on
the search path without signaling a warning if |
The result after evaluating expr
, invisibly.
attach_eval({ my_helper_funct <- function(x, y) x + y }) search() # environment "local:utils" is now attached my_helper_funct(1, 1) # the local utility is now available detach(local:utils) # cleanup
attach_eval({ my_helper_funct <- function(x, y) x + y }) search() # environment "local:utils" is now attached my_helper_funct(1, 1) # the local utility is now available detach(local:utils) # cleanup
Source R files into an attached environment
attach_source( ..., name = as_tidy_env_name(c(...), prefix = "source:"), recursive = FALSE, pos = 2L, chdir = FALSE, warn.conflicts = TRUE, mask.ok = NULL, parent = .GlobalEnv )
attach_source( ..., name = as_tidy_env_name(c(...), prefix = "source:"), recursive = FALSE, pos = 2L, chdir = FALSE, warn.conflicts = TRUE, mask.ok = NULL, parent = .GlobalEnv )
... |
filepaths to R files, or paths to directories containing R files. |
name |
A string, the name for the attached environment. By default, the
name is constructed from paths supplied to |
recursive |
If directories are passed to |
pos |
The position where to attach the environment, if creating a new
one. If an environment of |
chdir |
logical. if TRUE, the R working directory is temporarily changed to the directory containing the file(s) being sourced. |
warn.conflicts |
logical. If TRUE (the default), print warnings about
objects in the attached environment that that are masking or masked by
other objects of the same name. If the environment specified by |
mask.ok |
character vector of names of objects that can mask objects on
the search path without signaling a warning if |
parent |
R environment. If an environment specified by |
The attached environment, invisibly.
import_from, set_library_default_pos
This is inspired by the python idiom from module import object as new_name
.
import_from( x, ..., .into = parent.frame(), .parent = .GlobalEnv, .overwrite = interactive(), .chdir = FALSE, .recursive = FALSE, .pos = 2L )
import_from( x, ..., .into = parent.frame(), .parent = .GlobalEnv, .overwrite = interactive(), .chdir = FALSE, .recursive = FALSE, .pos = 2L )
x |
a bare symbol name of a package, a character vector of filepaths, an
environment (which could be a python module), or any object with |
... |
objects to import from x into |
.into |
An R environment, or something coercible to one by
|
.parent , .chdir , .recursive
|
Only applicable if |
.overwrite |
One of |
.pos |
Only applicable if |
The R environment or object that x
resolved to, invisibly.
If x
is a package name, then no check is performed to ensure the
object being imported is an exported function. As such, import_from()
can
be used to access package internal objects, though doing so is usually bad
practice.
show_whats_imported <- function(...) { import_from(...) setdiff(names(environment()), "...") } ## Importing from an R package # import one object show_whats_imported(envir, include) # rename an object on import show_whats_imported(envir, sys_source = include) # import all NAMESPACE exports show_whats_imported(envir, "*") show_whats_imported(envir) # missing `...` is interpreted as "*" # import all NAMESPACE exports, except for `include` show_whats_imported(envir, "*", -include) # import all NAMESPACE exports, except rename `include` to `sys_source` show_whats_imported(envir, "*", sys_source = include) # exclude more than one show_whats_imported(envir, "*", -include, -attach_eval) show_whats_imported(envir, "*", -c(include, attach_eval)) # import all NAMESPACE exports, also one internal function names `find_r_files` show_whats_imported(envir, "*", find_r_files) # import ALL package functions, including all internal functions show_whats_imported(envir, "**") # import ALL objects in the package NAMESPACE, including R's NAMESPACE machinery show_whats_imported(envir, "***") ## Importing from R files # setup dir.create(tmpdir <- tempfile()) owd <- setwd(tmpdir) writeLines(c("useful_function <- function() 'I am useful'", ".less_useful_fn <- function() 'less useful'"), "my_helpers.R") # import one function by name show_whats_imported("my_helpers.R", useful_function) # import all objects whose names don't start with a "." or "_" show_whats_imported("my_helpers.R", "*") # import all objects show_whats_imported("my_helpers.R", "**") # if the filepath to your scripts is stored in a variable, supply it in a call x <- "my_helpers.R" try(show_whats_imported(x)) # errors out, because no package 'x' # to force the value to be used, just supply it as a call rather than a bare symbol. # the simplest call can be just wrapping in () or {} show_whats_imported({x}) show_whats_imported((x)) show_whats_imported(c(x)) show_whats_imported({{x}}) # tidyverse style unquoting ## Importing R objects # if you have an actual R object that you want to import from, you will # have to supply it in a call x <- list(obj1 = "one", obj2 = "two") show_whats_imported({x}) ## Not run: # don't run this so we don't take a reticulate dependency import_from(reticulate, py_module = import) # rename object on import # import one object show_whats_imported(py_module("numpy"), random) # to prevent automatic conversion show_whats_imported(py_module("numpy", convert = FALSE), random) # import all objects that don't begin with a `_` # by default, other modules found in the module are also not imported show_whats_imported(py_module("glob"), "*") # to import EVERYTHING pass "**" # now includes modules that your modules imported, like `os` show_whats_imported(py_module("glob"), "**") rm(py_module) # clean up ## End(Not run) # cleanup setwd(owd) unlink(tmpdir, recursive = TRUE) rm(show_whats_imported, tmpdir, owd)
show_whats_imported <- function(...) { import_from(...) setdiff(names(environment()), "...") } ## Importing from an R package # import one object show_whats_imported(envir, include) # rename an object on import show_whats_imported(envir, sys_source = include) # import all NAMESPACE exports show_whats_imported(envir, "*") show_whats_imported(envir) # missing `...` is interpreted as "*" # import all NAMESPACE exports, except for `include` show_whats_imported(envir, "*", -include) # import all NAMESPACE exports, except rename `include` to `sys_source` show_whats_imported(envir, "*", sys_source = include) # exclude more than one show_whats_imported(envir, "*", -include, -attach_eval) show_whats_imported(envir, "*", -c(include, attach_eval)) # import all NAMESPACE exports, also one internal function names `find_r_files` show_whats_imported(envir, "*", find_r_files) # import ALL package functions, including all internal functions show_whats_imported(envir, "**") # import ALL objects in the package NAMESPACE, including R's NAMESPACE machinery show_whats_imported(envir, "***") ## Importing from R files # setup dir.create(tmpdir <- tempfile()) owd <- setwd(tmpdir) writeLines(c("useful_function <- function() 'I am useful'", ".less_useful_fn <- function() 'less useful'"), "my_helpers.R") # import one function by name show_whats_imported("my_helpers.R", useful_function) # import all objects whose names don't start with a "." or "_" show_whats_imported("my_helpers.R", "*") # import all objects show_whats_imported("my_helpers.R", "**") # if the filepath to your scripts is stored in a variable, supply it in a call x <- "my_helpers.R" try(show_whats_imported(x)) # errors out, because no package 'x' # to force the value to be used, just supply it as a call rather than a bare symbol. # the simplest call can be just wrapping in () or {} show_whats_imported({x}) show_whats_imported((x)) show_whats_imported(c(x)) show_whats_imported({{x}}) # tidyverse style unquoting ## Importing R objects # if you have an actual R object that you want to import from, you will # have to supply it in a call x <- list(obj1 = "one", obj2 = "two") show_whats_imported({x}) ## Not run: # don't run this so we don't take a reticulate dependency import_from(reticulate, py_module = import) # rename object on import # import one object show_whats_imported(py_module("numpy"), random) # to prevent automatic conversion show_whats_imported(py_module("numpy", convert = FALSE), random) # import all objects that don't begin with a `_` # by default, other modules found in the module are also not imported show_whats_imported(py_module("glob"), "*") # to import EVERYTHING pass "**" # now includes modules that your modules imported, like `os` show_whats_imported(py_module("glob"), "**") rm(py_module) # clean up ## End(Not run) # cleanup setwd(owd) unlink(tmpdir, recursive = TRUE) rm(show_whats_imported, tmpdir, owd)
Source R files
include( files_andor_dirs, envir = parent.frame(), chdir = FALSE, recursive = FALSE )
include( files_andor_dirs, envir = parent.frame(), chdir = FALSE, recursive = FALSE )
files_andor_dirs |
A character vector of filepaths to R files, or
directories containing R files. Directories are searched for files that end
with extension ".R" or ".r", ignoring those that start with a period ( |
envir |
An R environment. By default, the current R evaluation environment. |
chdir |
logical; if |
recursive |
whether to search directories recursively for R files. |
This is a vectorized wrapper around base::sys.source
with some
differences. Notably:
envir
defaults to the current frame
envir
is returned (invisibly)
keep.source
and keep.parse.data
default to
getOption("keep.source")
and getOption("keep.parse.data")
respectively,
instead of getOption("keep.source.pkgs")
and
getOption("keep.parse.data.pkgs")
toplevel.env
is set to getOption("topLevelEnvironment", envir)
. In
other words, if the option topLevelEnvironment
is already set, it is
respected.
The environment envir
, invisibly.
base::library()
This function is documented but not exported. Reach in with
envir:::set_library_default_pos()
to use it.
set_library_default_pos(..., after = NULL, before = NULL, value = NULL)
set_library_default_pos(..., after = NULL, before = NULL, value = NULL)
... |
Ignored. Arguments must be named |
after , before
|
string; the name of the environment on the search path that library() calls should by default attach after or before. |
value |
The value (or quoted expression) the new argument should be. |
This is primarily a way to "pin" a particular environment on the
search path. For example, say you have a "project_utils" environment where
you've defined a variety of useful functions. To prevent future library()
calls from masking any objects in your attached "project_utils"
environment, you can modify the default pos
argument to library.
attach_source("project_utils.R", name = "project_utils) set_library_default_pos(after = "project_utils") library(foo) # now foo will attach after the "project_utils" environment
The original default value of pos
, invisibly
within
methods for R environmentswithin
methods for R environments
## S3 method for class 'environment' within(data, expr, ..., quote = substitute(expr)) ## S3 method for class 'character' within( data, expr, ..., pos = 2L, warn.conflicts = TRUE, mask.ok = NULL, quote = substitute(expr) )
## S3 method for class 'environment' within(data, expr, ..., quote = substitute(expr)) ## S3 method for class 'character' within( data, expr, ..., pos = 2L, warn.conflicts = TRUE, mask.ok = NULL, quote = substitute(expr) )
data |
An R environment, or the name of a (potentially new) attached environment. |
expr |
The bare R expression to evaluate. Automatically quoted. |
... |
Ignored. Added for compatibility with the S3 generic. Throws an
error if any arguments are passed to |
quote |
An R language object. This is an escape hatch from the automatic
quoting of |
pos |
The position where to attach the environment, if creating a new
one. If an environment of |
warn.conflicts |
logical. If TRUE (the default), print warnings about objects in the attached environment that that are masking or masked by other objects of the same name. |
mask.ok |
character vector of names of objects that can mask objects on
the search path without signaling a warning if |
The only difference between attach_eval
and within.character
is
the order of the arguments and the return value; the first
returns the result of evaluating the expression, the latter the
environment.
The R environment, invisibly.
See the note in attach_source
about a potential pitfall of evaluating
code directly in an attached environment.
attach_eval attach_source eval within