[med-svn] [r-cran-globals] 01/02: New upstream version 0.8.0
Andreas Tille
tille at debian.org
Thu Jan 19 07:41:51 UTC 2017
This is an automated email from the git hooks/post-receive script.
tille pushed a commit to branch master
in repository r-cran-globals.
commit 06e9a4845aceefc0ec72bf674a390f0bdb000649
Author: Andreas Tille <tille at debian.org>
Date: Thu Jan 19 08:26:01 2017 +0100
New upstream version 0.8.0
---
DESCRIPTION | 6 ++--
MD5 | 12 +++----
NEWS | 72 +++++++++++++++++++++++-------------------
R/findGlobals.R | 93 +++++++++++++++++++++++++++++++++++++++++++------------
R/globalsOf.R | 42 ++++++++++++++++++++++---
man/globalsOf.Rd | 11 +++++--
tests/globalsOf.R | 26 ++++++++++++++++
7 files changed, 195 insertions(+), 67 deletions(-)
diff --git a/DESCRIPTION b/DESCRIPTION
index 3a2865c..7681d9c 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,5 +1,5 @@
Package: globals
-Version: 0.7.2
+Version: 0.8.0
Depends: R (>= 3.1.2)
Imports: codetools
Title: Identify Global Objects in R Expressions
@@ -17,8 +17,8 @@ URL: https://github.com/HenrikBengtsson/globals
BugReports: https://github.com/HenrikBengtsson/globals/issues
RoxygenNote: 5.0.1
NeedsCompilation: no
-Packaged: 2017-01-08 20:27:44 UTC; hb
+Packaged: 2017-01-16 21:17:30 UTC; hb
Author: Henrik Bengtsson [aut, cre, cph]
Maintainer: Henrik Bengtsson <henrikb at braju.com>
Repository: CRAN
-Date/Publication: 2017-01-09 09:49:49
+Date/Publication: 2017-01-17 00:32:07
diff --git a/MD5 b/MD5
index 084f778..c3b93ab 100644
--- a/MD5
+++ b/MD5
@@ -1,23 +1,23 @@
-4f7678a310bd02d2afb22d63020883c3 *DESCRIPTION
+d69d3e82b199a73a6cd3fb860aba4bf1 *DESCRIPTION
24f2b3be1c6d7a2667c0c0e3a90a9776 *NAMESPACE
-013505ab454eba6b707ade7008e28206 *NEWS
+4b82fd577ffd37314cd93194ba8d5551 *NEWS
e130006674e21564fca015849dfb584f *R/Globals-class.R
2ff62afe0cc2ab9edb6505a1f5ee5a2c *R/cleanup.R
-8d3fe54f9457bec3553e7d32dd8da76c *R/findGlobals.R
-284765f49bc14c3396e4be823def24ec *R/globalsOf.R
+4ec85ed048ac5e6547334c9633956bad *R/findGlobals.R
+4f93f392bc2ed30efabaa2360a9bd4d7 *R/globalsOf.R
872b7b7be000da61e173d5be37df37c1 *R/packagesOf.R
4e2a5293b057aa77b586cb457cdf634b *R/utils.R
1759e8aee0418f536cacd508bf33d65b *R/walkAST.R
9d222e6e9bd19dedcf9398fdefddfe06 *man/Globals.Rd
6718bae8bf05b1744df49c2a6345251d *man/cleanup.Globals.Rd
e36067883b9755c96195d9f50b4700d1 *man/globalsByName.Rd
-79e73476957d6fa97778691ab9b30516 *man/globalsOf.Rd
+a30bc35f7e240bcca497bcda1a40ad43 *man/globalsOf.Rd
937c4cb33fb344a0c74330cd162a285c *man/packagesOf.Globals.Rd
e4d542b6757e65b7bd8dcee45f46996d *man/walkAST.Rd
60035e1924551a13e4ad79733e0f48a2 *tests/Globals.R
0a4fd4c3594bcf15e685886e0475e528 *tests/conservative.R
b840f7e78850bd3a4af136f8649bf05a *tests/dotdotdot.R
-9d591dfd75c1bd46615e59dd308fa405 *tests/globalsOf.R
+d7edc642e662195ae2a9f32d4a58169d *tests/globalsOf.R
04ee391b83ac7278c0040be00d32756b *tests/liberal.R
24cf238b33f0f3c7b9ae5e05904d40d8 *tests/utils.R
a7d6108d24e35128697e606d16d3c2e5 *tests/walkAST.R
diff --git a/NEWS b/NEWS
index 2630608..2424449 100644
--- a/NEWS
+++ b/NEWS
@@ -1,26 +1,34 @@
Package: globals
================
+Version: 0.8.0 [2017-01-14]
+
+NEW FEATURES:
+
+ o globalsOf() identifies also globals in locally defined functions.
+ This can be disabled with argument recursive = FALSE.
+
+ o findGlobals() now takes both closures (functions) and expressions.
+
+
Version: 0.7.2 [2016-12-28]
BUG FIXES:
- o c(x, list()) where x is a Globals object would give an error
- reporting that the list does not have named elements.
+ o c(x, list()) where x is a Globals object would give an error reporting
+ that the list does not have named elements.
Version: 0.7.1 [2016-10-13]
NEW FEATURES:
- o Globals() and as.Globals() now accepts an empty list
- as input as well.
+ o Globals() and as.Globals() now accepts an empty list as input as well.
BUG FIXES:
- o 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.
+ o 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.
Version: 0.7.0 [2016-09-08]
@@ -29,20 +37,21 @@ NEW FEATURES:
o Added walkAST(), which can be used to tweak expressions.
- o Added globalsByName() for locating and retrieving a set of
- known global variables.
+ o Added globalsByName() for locating and retrieving a set of known global
+ variables.
o Added c(), $<-(), names(), unique() for Globals objects.
- Improved as.Globals() for lists.
+
+ o Improved as.Globals() for lists.
Version: 0.6.1 [2016-01-31]
NEW FEATURES:
- o Now the error message of globalsOf(..., mustExist=TRUE) when
- it fails to locate a global also gives information on the
- expression that is problematic.
+ o Now the error message of globalsOf(..., mustExist=TRUE) when it fails to
+ locate a global also gives information on the expression that is
+ problematic.
BUG FIXES:
@@ -54,34 +63,33 @@ Version: 0.6.0 [2015-12-12]
NEW FEATURES:
- o 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 }. Now 'b' is correctly identified
- as a global object. Previously it would have been missed.
- For backward compatibility, the previous behavior can be
- obtained using argument method="conservative".
+ o 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 }.
+ Now 'b' is correctly identified as a global object. Previously it would
+ have been missed. For backward compatibility, the previous behavior can
+ be obtained using argument method="conservative".
Version: 0.5.0 [2015-10-13]
NEW FEATURES:
- o globalsOf() now returns attribute 'where' specifying where
- each global object is located.
+ o globalsOf() now returns attribute 'where' specifying where each global
+ object is located.
BUG FIXES:
- o 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.
+ o 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.
Version: 0.4.1 [2015-10-05]
BUG FIXES:
- o globalsOf() failed to return global variables with value NULL.
- They were identified but silently dropped.
+ o globalsOf() failed to return global variables with value NULL. They were
+ identified but silently dropped.
Version: 0.4.0 [2015-09-12]
@@ -126,13 +134,13 @@ Version: 0.2.1 [2015-05-20]
NEW FEATURES:
- o getGlobals() gained argument 'mustExist' 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.
+ o getGlobals() gained argument 'mustExist' 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.
- o findGlobals() and getGlobals() gained argument 'method' for
- controlling whether a "conservative" or a "liberal" algorithm
- for identifying true globals should be used.
+ o findGlobals() and getGlobals() gained argument 'method' for controlling
+ whether a "conservative" or a "liberal" algorithm for identifying true
+ globals should be used.
Version: 0.2.0 [2015-05-19]
diff --git a/R/findGlobals.R b/R/findGlobals.R
index 8bfe7d3..0e89ade 100644
--- a/R/findGlobals.R
+++ b/R/findGlobals.R
@@ -11,16 +11,23 @@ findGlobals_conservative <- function(expr, envir, ...) {
objs <<- c(objs, v)
}
- ## From codetools::findGlobals():
- fun <- asFunction(expr, envir=envir, ...)
- # codetools::collectUsage(fun, enterGlobal=enter)
-
- ## The latter becomes equivalent to (after cleanup):
- w <- makeUsageCollector(fun, enterGlobal=enter, name="<anonymous>")
- w$env <- new.env(hash=TRUE, parent=w$env)
- locals <- findLocalsList(list(expr))
- for (name in locals) assign(name, value=TRUE, envir=w$env)
- walkCode(expr, w)
+ if (is.function(expr)) {
+ if (typeof(expr) != "closure") return(character(0L)) ## e.g. `<-`
+ fun <- expr
+ w <- makeUsageCollector(fun, name="<anonymous>", enterGlobal=enter)
+ collectUsageFunction(fun, name="<anonymous>", w)
+ } else {
+ ## From codetools::findGlobals():
+ fun <- asFunction(expr, envir=envir, ...)
+ # codetools::collectUsage(fun, enterGlobal=enter)
+
+ ## The latter becomes equivalent to (after cleanup):
+ w <- makeUsageCollector(fun, name="<anonymous>", enterGlobal=enter)
+ w$env <- new.env(hash=TRUE, parent=w$env)
+ locals <- findLocalsList(list(expr))
+ for (name in locals) assign(name, value=TRUE, envir=w$env)
+ walkCode(expr, w)
+ }
unique(objs)
}
@@ -34,10 +41,16 @@ findGlobals_liberal <- function(expr, envir, ...) {
objs <<- c(objs, v)
}
- fun <- asFunction(expr, envir=envir, ...)
-
- w <- makeUsageCollector(fun, enterGlobal=enter, name="<anonymous>")
- walkCode(expr, w)
+ if (is.function(expr)) {
+ if (typeof(expr) != "closure") return(character(0L)) ## e.g. `<-`
+ fun <- expr
+ w <- makeUsageCollector(fun, name="<anonymous>", enterGlobal=enter)
+ collectUsageFunction(fun, name="<anonymous>", w)
+ } else {
+ fun <- asFunction(expr, envir=envir, ...)
+ w <- makeUsageCollector(fun, name="<anonymous>", enterGlobal=enter)
+ walkCode(expr, w)
+ }
unique(objs)
}
@@ -57,12 +70,21 @@ findGlobals_ordered <- function(expr, envir, ...) {
name <<- c(name, v)
}
- fun <- asFunction(expr, envir=envir, ...)
-
- w <- makeUsageCollector(fun, name="<anonymous>",
- enterLocal=enterLocal, enterGlobal=enterGlobal)
- walkCode(expr, w)
-
+ ## A function or an expression?
+ if (is.function(expr)) {
+ if (typeof(expr) != "closure") return(character(0L)) ## e.g. `<-`
+ fun <- expr
+
+ w <- makeUsageCollector(fun, name="<anonymous>",
+ enterLocal=enterLocal, enterGlobal=enterGlobal)
+ collectUsageFunction(fun, name="<anonymous>", w)
+ } else {
+ fun <- asFunction(expr, envir=envir, ...)
+ w <- makeUsageCollector(fun, name="<anonymous>",
+ enterLocal=enterLocal, enterGlobal=enterGlobal)
+ walkCode(expr, w)
+ }
+
## Drop duplicated names
dups <- duplicated(name)
class <- class[!dups]
@@ -138,3 +160,34 @@ findGlobals <- function(expr, envir=parent.frame(), ..., tweak=NULL, dotdotdot=c
globals
}
+
+
+## Utility functions adopted from codetools:::dropMissing()
+## and codetools:::collectUsageFun()
+dropMissingFormals <- function(x) {
+ nx <- length(x)
+ ix <- logical(length = nx)
+ for (i in seq_len(nx)) {
+ tmp <- x[[i]]
+ if (!missing(tmp)) ix[i] <- TRUE
+ }
+ x[ix]
+}
+
+#' @importFrom codetools walkCode findLocalsList
+collectUsageFunction <- function(fun, name, w) {
+ formals <- formals(fun)
+ body <- body(fun)
+
+ w$name <- c(w$name, name)
+ parnames <- names(formals)
+
+ formals_clean <- dropMissingFormals(formals)
+ locals <- findLocalsList(c(list(body), formals_clean))
+
+ w$env <- new.env(hash = TRUE, parent = w$env)
+ for (n in c(parnames, locals)) assign(n, TRUE, w$env)
+ for (a in formals_clean) walkCode(a, w)
+
+ walkCode(body, w)
+}
diff --git a/R/globalsOf.R b/R/globalsOf.R
index b5f7738..89bf9ce 100644
--- a/R/globalsOf.R
+++ b/R/globalsOf.R
@@ -1,28 +1,37 @@
#' Get all global objects of an expression
#'
#' @param expr An R expression.
+#'
#' @param envir The environment from where to search for globals.
+#'
#' @param \dots Not used.
+#'
#' @param method A character string specifying what type of search algorithm to use.
+#'
#' @param tweak An optional function that takes an expression
#' and returns a tweaked expression.
-## @param dotdotdot A @character string specifying how to handle a
-## \emph{global} \code{\dots} if one is discovered.
+#'
#' @param substitute If TRUE, the expression is \code{substitute()}:ed,
#' otherwise not.
+#'
#' @param mustExist If TRUE, an error is thrown if the object of the
#' identified global cannot be located. Otherwise, the global
#' is not returned.
+#'
#' @param unlist If TRUE, a list of unique objects is returned.
#' If FALSE, a list of \code{length(expr)} sublists.
#'
+#' @param recursive If TRUE, globals that are closures (functions) and that
+#' exist outside of namespaces ("packages"), will be recursively
+#' scanned for globals.
+#'
#' @return A \link{Globals} object.
#'
#' @details
#' There currently three methods for identifying global objects.
#'
#' The \code{"ordered"} search method identifies globals such that
-#' a global variable preceeding a local variable with the same name
+#' a global variable preceding a local variable with the same name
#' is not dropped (which the \code{"conservative"} method would).
#'
#' The \code{"conservative"} search method tries to keep the number
@@ -38,6 +47,9 @@
#' are most likely among the identified ones. At the same time,
#' there is a risk that some false positives are also identified.
#'
+#' With \code{recursive = TRUE}, globals part of locally defined
+#' functions will also be found, otherwise not.
+#'
#' @example incl/globalsOf.R
#'
#' @seealso
@@ -46,7 +58,7 @@
#'
#' @aliases findGlobals
#' @export
-globalsOf <- function(expr, envir=parent.frame(), ..., method=c("ordered", "conservative", "liberal"), tweak=NULL, substitute=FALSE, mustExist=TRUE, unlist=TRUE) {
+globalsOf <- function(expr, envir=parent.frame(), ..., method=c("ordered", "conservative", "liberal"), tweak=NULL, substitute=FALSE, mustExist=TRUE, unlist=TRUE, recursive=TRUE) {
method <- match.arg(method)
if (substitute) expr <- substitute(expr)
@@ -65,6 +77,28 @@ globalsOf <- function(expr, envir=parent.frame(), ..., method=c("ordered", "cons
stop(ex)
})
+ ## 3. Among globals that are closures (functions) and that exist outside
+ ## of namespaces ("packages"), check for additional globals?
+ if (recursive) {
+ ## Don't enter functions in namespaces / packages
+ where <- sapply(globals, FUN = function(x) environmentName(environment(x)))
+ globalsT <- globals[!(where %in% loadedNamespaces())]
+
+ ## Enter only functions
+ globalsT <- globals[sapply(globalsT, FUN = typeof) == "closure"]
+
+ if (length(globalsT) > 0) {
+ for (gg in seq_along(globalsT)) {
+ fcn <- globalsT[[gg]]
+ globalsGG <- globalsOf(fcn, envir=envir, ..., method=method, tweak=tweak, substitute=FALSE, mustExist=mustExist, unlist=unlist, recursive=recursive)
+ if (length(globalsGG) > 0) {
+ globals <- c(globals, globalsGG)
+ }
+ }
+ globals <- unique(globals)
+ }
+ }
+
globals
} ## globalsOf()
diff --git a/man/globalsOf.Rd b/man/globalsOf.Rd
index fc569f8..6f831db 100644
--- a/man/globalsOf.Rd
+++ b/man/globalsOf.Rd
@@ -7,7 +7,7 @@
\usage{
globalsOf(expr, envir = parent.frame(), ..., method = c("ordered",
"conservative", "liberal"), tweak = NULL, substitute = FALSE,
- mustExist = TRUE, unlist = TRUE)
+ mustExist = TRUE, unlist = TRUE, recursive = TRUE)
}
\arguments{
\item{expr}{An R expression.}
@@ -29,6 +29,10 @@ is not returned.}
\item{unlist}{If TRUE, a list of unique objects is returned.
If FALSE, a list of \code{length(expr)} sublists.}
+\item{recursive}{If TRUE, globals that are closures (functions) and that
+exist outside of namespaces ("packages"), will be recursively
+scanned for globals.}
+
\item{\dots}{Not used.}
}
\value{
@@ -41,7 +45,7 @@ Get all global objects of an expression
There currently three methods for identifying global objects.
The \code{"ordered"} search method identifies globals such that
-a global variable preceeding a local variable with the same name
+a global variable preceding a local variable with the same name
is not dropped (which the \code{"conservative"} method would).
The \code{"conservative"} search method tries to keep the number
@@ -56,6 +60,9 @@ The \code{"liberal"} search method tries to keep the
true-positive ratio as high as possible, i.e. the true globals
are most likely among the identified ones. At the same time,
there is a risk that some false positives are also identified.
+
+With \code{recursive = TRUE}, globals part of locally defined
+functions will also be found, otherwise not.
}
\examples{
b <- 2
diff --git a/tests/globalsOf.R b/tests/globalsOf.R
index c5949b2..974e770 100644
--- a/tests/globalsOf.R
+++ b/tests/globalsOf.R
@@ -117,6 +117,32 @@ stopifnot(
identical(where$d, globalenv())
)
+message(" ** globalsOf() w/ globals in local functions:")
+
+a <- 1
+foo <- function(x) x - a
+
+for (method in c("ordered", "conservative", "liberal")) {
+ globalsL <- globalsOf({ foo(3) }, substitute = TRUE, method = method, recursive = FALSE, mustExist = FALSE)
+ stopifnot(all(names(globalsL) %in% c("{", "foo")),
+ !any("a" %in% names(globalsL)))
+ globalsL <- cleanup(globalsL)
+ str(globalsL)
+ stopifnot(all(names(globalsL) %in% c("foo"), !any("a" %in% names(globalsL))))
+
+ globalsL <- globalsOf({ foo(3) }, substitute = TRUE, method = "ordered", recursive = TRUE, mustExist = FALSE)
+ stopifnot(all(names(globalsL) %in% c("{", "foo", "-", "a")))
+ globalsL <- cleanup(globalsL)
+ str(globalsL)
+ stopifnot(all(names(globalsL) %in% c("foo", "a")))
+
+ globalsL <- globalsOf({ foo(3) }, substitute = TRUE, recursive = TRUE, mustExist = FALSE)
+ stopifnot(all(names(globalsL) %in% c("{", "foo", "-", "a")))
+ globalsL <- cleanup(globalsL)
+ str(globalsL)
+ stopifnot(all(names(globalsL) %in% c("foo", "a")))
+}
+
message("*** globalsOf() ... DONE")
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-globals.git
More information about the debian-med-commit
mailing list