[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