-
globalsByName()
, and therefore alsoglobalsOf()
, did not support special arguments..1
,..2
, etc. -
cleanup(globals, drop)
on aGlobals
object with non-existing globals and wheredrop
did not specify"missing"
would throw anError in exists(name, envir = env) : use of NULL environment is defunct
. Now the non-existing ("missing") globals are preserved.
- Drop duplicated arguments from
help("walkAST")
.
packagesOf()
forGlobals
failed to return the package of the globals if the global doesn't have a closure, e.g.base::pi
anddata.table::.N
.
- Add
[[<-
and[<-
forGlobals
, to complement$<-
.
- All functions modifying a
Globals
object guarantee that thewhere
and theclass
attributes are always the last two attributes and in that order.
c()
forGlobals
would lose thewhere
environment for any functions appended.
cleanup()
assumed it was safe to callenv$.packageName
on each scanned environment, but that might not be true. A classed environment could be such that$()
gives an error, rather than returning something.
-
globalsOf()
gained argumentlocals
, which controls whether globals that exist in "local" environments of a function should be considered or not, e.g. inf <- local({ a <- 1; function() a })
, shoulda
be considered a global off()
or not. For backward compatibility reasons, the default islocals = TRUE
, but this might becomelocals = FALSE
in a later release. -
Any
globals.*
options specific to this packages can now be set via environment variablesR_GLOBALS_*
when the package is loaded. For example,R_GLOBALS_DEBUG=true
sets optionglobals.debug = TRUE
.
as.Globals(list(a = NULL))
andc(Globals(), list(a = NULL))
would include the calling environment instead of an empty environment as part of thewhere
attribute.
-
Now
findGlobals(function(x) x <- x)
identifiesx
as a global variable. -
Now
findGlobals(function(x) x[1] <- 0)
identifiesx
as a global variable. Same for other variants likex[[1]] <- 0
andx$a <- 0
. -
Now
findGlobals(function(z) x <- z$x)
identifiesx
as a global variable. -
Now
findGlobals(quote({ f <- function(x) x; x }))
identifiesx
as a global variable. Previously, thex
of the function would hide the globalx
.
-
globalsOf()
could produce "Error in vapply(where, FUN = envname, FUN.VALUE = NA_character_, USE.NAMES = FALSE) : values must be length 1, but FUN(X[[2]]) result is length 10". This would happen if for instance argumentenvir
has attributes set. -
findGlobals()
works around a bug instats:::[.formula
of R (< 4.1.0) that revealed itself when scanning formulas with NULL components. -
findGlobals()
would not pass down argumentdotdotdot
when recursively parsing assignments. -
findGlobals()
could return...
as a global also when used in formulas. Now it respects argumentdotdotdot = "ignore"
and parses formulas accordingly, otherwise formulas will be parsed usingdotdotdot = "return"
.
-
findGlobals(expr)
now also scans any attributes ofexpr
for globals, e.g.purrr::partial()
puts the original function in attributebody
. Argumentattributes
controls which attributes, if any, should be scanned. Default is to scan all attributes. -
findGlobals()
,globalsOf()
, andglobalsByName()
now recognizes and returns values for..1
,..2
, etc. like they do for...
. -
cleanup()
now also drop exported and non-exportedNativeSymbolInfo
objects.
cleanup()
gained support for droppingNativeSymbolInfo
objects.
-
findGlobals()
did not pass down argumentmethod
in recursive calls. -
findGlobals(expr)
would fail to identify globals in anonymous function calls, e.g.expr <- as.call(list(function(...) NOT_FOUND, quote(FOUND)))
. -
Calls like
findGlobals(~ NULL)
with NULLs on the right-hand side could throw "Error in if (length(ans) == 0L || as.character(ans[[1L]])[1L] == "~") { : missing value where TRUE/FALSE needed". Solved by working around what looks like a bug in the stats package causing subsetting on formulas with NULLs to fail. -
cleanup(..., drop = c(..., "base-packages"))
forGlobals
would drop base R objects with names not exported by the corresponding base R package. Similarly,drop = c(..., "primitive")
would drop primitive R objects with names not exported by any base R package. -
findGlobals()
,globalsOf()
, andglobalsByName()
did not handle..1
,..2
, etc. -
findGlobals()
andglobalsOf()
produces warnings on ': ... may be used in an incorrect context' when formulas had...
,..1
,..2
, etc. -
findGlobals(function() NULL, substitute = TRUE, trace = TRUE)
would throw "Error in environment(w$enterLocal) : object 'w' not found".
findGlobals(function() { a; a <- a + 1 })
would fail to identifya
as a global variable whereas it was properly identified with{ a <- a + 1; a }
.
globalsOf()
could produce "Error in vapply(where, FUN = envname, FUN.VALUE = NA_character_, USE.NAMES = FALSE) : values must be length 1, but FUN(X[[...]]) result is length ...". This was because the internalenvname(env)
did not always handle whenclass(env) != "environment"
.
findGlobals()
,globalsOf()
, andpackagesOf()
no longer return elements sorted by name.
- globals::
findGlobals()
would not identifya
as a global in expressions of typea[1] = ...
andnames(a) = ...
although it did fora[1] <- ...
andnames(a) <- ...
.
cleanup()
forGlobals
should now be much faster. Previously, it could be very slow the first time it was called in a fresh R session, especially if the user had a large number of packages installed and/or the package libraries were on slow drives.
- Added help for
globals::findGlobals()
.
-
globals::findGlobals(x)
, wherex
is a list, iterated overx
incorrectly assuming no method dispatching onx
would take place. For instance, ifx
contained anfst::fst_table
object, then "Error in .subset2(x, i, exact = exact) : subscript out of bounds" would be produced. -
globals::
findGlobals()
could produce a "Warning in is.na(x): is.na() applied to non-(list or vector) of type 'NULL'" in R (< 3.5.0).
- globals::
findGlobals()
is now significantly faster for elements that are long lists with many elements of basic data types. This is because elements of such basic data type cannot contain globals and can therefore be skipped early in the search for globals.
- Now globals::
findGlobals()
identifiesa
as a global also when it is part of LHS expressions of typea[1] <- ...
andnames(a) <- ...
.
-
globals::
findGlobals()
incorrectly identifieda
as a global in expression of typea <- pkg::a
. -
If
...
was passed toglobalsByName(names)
, an error would be produced unless it was the last entry innames
.
- Now
findGlobals()
identifiesx
as a global variable inx <- x + 1
and likewise forx + 1 -> x
. Note that ditto using<<-
and->>
was already identifyingx
as a global.
findGlobals(..., trace = TRUE)
now outputs only to standard error. Previously, some of the output went to standard output.
globalsOf(..., recursive = TRUE)
would result in "Error in match.fun(FUN) : node stack overflow" if one of the globals identified was a function that called itself recursively (either directly or indirectly).
walkAST()
could produce error "Cannot walk expression. Unknown object type '...'" for objects of typeenvironment
.
walkAST()
could produce error "Cannot walk expression. Unknown object type '...'" for objects of typelist
,expression
andS4
.
-
Globals that are part of a formula are now identified.
-
findGlobals(..., trace = TRUE)
will now show low-level parse information as the abstract syntax tree (AST) is walked.
SOFTWARE QUALITY:
- Enabled more internal sanity checks.
walkAST()
could produce error "Cannot walk expression. Unknown object type 'nnn'" for expressions of typebuiltin
,closure
andspecial
.
- Added option
globals.debug
, which when TRUE enables debugging output.
-
globalsOf(..., recursive = TRUE)
would in some cases scan an incorrect subset of already identified globals. -
globalsOf(..., recursive = TRUE)
failed to skip objects part of package namespaces that where defined via alocal()
statement.
-
globalsOf()
identifies also globals in locally defined functions. This can be disabled with argumentrecursive = FALSE
. -
findGlobals()
now takes both closures (functions) and expressions.
c(x, list())
wherex
is aGlobals
object would give an error reporting that the list does not have named elements.
Globals()
andas.Globals()
now accepts an empty list as input as well.
walkAST(quote( function(x=NULL) 0 ))
would give a sanity check error due to the NULL argument. Thank you GitHub user 'billy34' for reporting on this.
-
Added
walkAST()
, which can be used to tweak expressions. -
Added
globalsByName()
for locating and retrieving a set of known global variables. -
Added
c()
,$<-()
,names()
,unique()
forGlobals
objects. -
Improved
as.Globals()
for lists.
- Now the error message of
globalsOf(..., mustExist = TRUE)
when it fails to locate a global also gives information on the expression that is problematic.
cleanup()
forGlobals
did not cleanup functions in core package environments namedpackage:<name>
.
findGlobals()
is updated to handle the case where a local variable is overwriting a global one with the same name, e.g.{ a <- b; b <- 1 }
. Nowb
is correctly identified as a global object. Previously it would have been missed. For backward compatibility, the previous behavior can be obtained using argumentmethod = "conservative"
.
globalsOf()
now returns attributewhere
specifying where each global object is located.
cleanup()
now only drops objects that are located in one of the "base" packages; previously it would also drop copies of such objects, e.g.FUN <- base::sample
.
globalsOf()
failed to return global variables with value NULL. They were identified but silently dropped.
findGlobals()
andglobalsOf()
gained argumentdotdotdot
.
- More test coverage.
- Renamed
getGlobals()
toglobalsOf()
.
-
Added
[()
forGlobals
. -
findGlobals()
andgetGlobals()
gained argumentsubstitute
. -
Added
cleanup(..., method = "internals")
.
-
Added
Globals
class with methodscleanup()
andpackagesOf()
. -
Added
as.Globals()
to coerce lists toGlobals
objects.
-
getGlobals()
gained argumentmustExist
for controlling whether to give an error when the corresponding object for an identified global cannot be found or to silently drop the missing global. -
findGlobals()
andgetGlobals()
gained argumentmethod
for controlling whether a"conservative"
or a"liberal"
algorithm for identifying true globals should be used.
- Moved "globals" functions from an in-house package to this package.
- Created.