Rev 86207 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
saveTo <- function(to) function(cond) assign(to, cond, envir = globalenv())isCond <- function(x, class, msg) {inherits(x, "condition") && inherits(x, class) && identical(x$message, msg)}## Handler stack starts emptyhandlers <- withVisible(globalCallingHandlers())stopifnot(identical(handlers$value, list()),isTRUE(handlers$visible))## Handlers must be functionserr <- tryCatch(globalCallingHandlers(foo = identity, bar = NA),error = identity)stopifnot(identical(err$message, "condition handlers must be functions"))## Can register and inspect handlerglobalCallingHandlers(error = saveTo(".Last.error"))handlers <- withVisible(globalCallingHandlers())stopifnot(length(handlers$value) == 1,names(handlers$value) == "error",handlers$visible)## Handlers are invoked based on class.Last.error <- NULLsignalCondition(simpleCondition("foo"))stopifnot(is.null(.Last.error))signalCondition(simpleError("foo"))stopifnot(isCond(.Last.error, "error", "foo"))## Can register multiple handlersglobalCallingHandlers(condition = saveTo(".Last.condition"),warning = saveTo(".Last.warning"))handlers <- globalCallingHandlers()stopifnot(length(handlers) == 3,all(names(handlers) == c("condition", "warning", "error")))## Multiple handlers are invoked.Last.error <- NULLsignalCondition(simpleWarning("bar"))stopifnot(is.null(.Last.error),isCond(.Last.condition, "warning", "bar"),isCond(.Last.warning, "warning", "bar"))signalCondition(simpleError("baz"))stopifnot(isCond(.Last.error, "error", "baz"),isCond(.Last.condition, "error", "baz"),isCond(.Last.warning, "warning", "bar"))## Handlers are not invoked if error is caught.Last.error <- NULLtry(stop("baz"), TRUE)stopifnot(is.null(.Last.error))## Can remove handlershandlers <- globalCallingHandlers()old <- withVisible(globalCallingHandlers(NULL))stopifnot(identical(old$value, handlers),!old$visible,identical(globalCallingHandlers(), list()))signalCondition(simpleError("foo"))stopifnot(is.null(.Last.error))## Can pass list of handlersfoobars <- list(foo = function() "foo", bar = function() "bar")globalCallingHandlers(foobars)stopifnot(identical(globalCallingHandlers(), foobars))globalCallingHandlers(NULL)## Local handlers are not returnedhandlers <- withCallingHandlers(foo = function(...) NULL,globalCallingHandlers())stopifnot(identical(handlers, list()))globalCallingHandlers(foobars)handlers <- withCallingHandlers(foo = function(...) NULL,globalCallingHandlers())stopifnot(identical(handlers, foobars))globalCallingHandlers(NULL)## Registering a handler again moves it to the top of the stackglobalCallingHandlers(warning = function(...) "foo",error = function(...) "foo",condition = function(...) "foo",error = function(...) "bar")globalCallingHandlers(error = function(...) "foo")bumped <- list(error = function(...) "foo",warning = function(...) "foo",condition = function(...) "foo",error = function(...) "bar")stopifnot(identical(globalCallingHandlers(), bumped))## Fails in R 4.0globalCallingHandlers(warning = function(...) "foo",error = function(...) "foo")bumped <- list(warning = function(...) "foo",error = function(...) "foo",condition = function(...) "foo",error = function(...) "bar")stopifnot(identical(globalCallingHandlers(), bumped))globalCallingHandlers(NULL)## Attributes and closure environments are detected in the duplicate## handlers checkhnd1 <- function(...) "foo"hnd2 <- structure(function(...) "foo", bar = TRUE)hnd3 <- local(function(...) "foo")expectedList <- list(error = hnd1,error = hnd2,error = hnd3)globalCallingHandlers(error = hnd1, error = hnd2, error = hnd3)stopifnot(identical(globalCallingHandlers(), expectedList))globalCallingHandlers(NULL)## and removeSource() now retains attributes:stopifnot( identical(attributes(removeSource(hnd2)), list(bar = TRUE)) )## Source references do not cause handlers to be treated as distinctwithSource <- function(src, envir = parent.frame(), file = NULL) {if (is.null(file)) {file <- tempfile("sourced", fileext = ".R")}on.exit(unlink(file))writeLines(src, file)source(file, local = envir, keep.source = TRUE)}withSource("hnd1 <- structure(function(...) { NULL })")withSource("hnd2 <- structure(function(...) { NULL })")globalCallingHandlers(NULL)globalCallingHandlers(error = hnd1)globalCallingHandlers(error = hnd2) # message "pushing duplicate .."stopifnot(identical(globalCallingHandlers(), list(error = hnd2)))globalCallingHandlers(NULL)