Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 27 additions & 22 deletions R/domains.R
Original file line number Diff line number Diff line change
Expand Up @@ -108,30 +108,35 @@ wrap_callback_reenter <- function(callback, domain) {
force(callback)
force(domain)

wrapper <- function(...) {
# replace = TRUE because we don't care what the current domain is; we're
# (temporarily) putting the world back to the way it was when the callback
# was bound to a promise.
reenter_promise_domain(domain, callback(...), replace = TRUE)
# We can't simply take `...` as arguments and call `callback(...)`. There are
# parts of this package that will inspect formals() to see if there's a
# `.visible` parameter in the callback. Using `match.call()` here ensures that
# the callback is called with the same arguments as it would have been if it
# were called directly.
#
# IMPORTANT NOTE: This technique changes callback arguments from lazy eval to
# eager eval--make sure you're OK with that before using!
wrapper <- function() {
# Evaluate the arguments in the caller's environment
call <- match.call()
# The `[-1]` is to drop the function name from the call--we just want the
# arguments
args <- lapply(call[-1], eval, parent.frame())
# Create and evaluate the callback call in our environment, wrapped in reenter_promise_domain
reenter_promise_domain(
domain,
rlang::exec(callback, !!!args),
# replace = TRUE because we don't care what the current domain is; we're
# (temporarily) putting the world back to the way it was when the callback
# was bound to a promise.
replace = TRUE
)
}
# Copy the formals from the original callback to the wrapper, so that the
# wrapper can be called with the same arguments as the original callback.
formals(wrapper) <- formals(callback)

# There are parts of this package that will inspect formals() to see if
# there's a `.visible` parameter in the callback. So it's important to have
# the returned wrapper have the same formals as the original callback.
wrap_with_signature(wrapper, formals(callback))
}

wrap_with_signature <- function(func, formal_args) {
# func must have a `...` signature
stopifnot("..." %in% names(formals(func)))

args <- names(formal_args)
recall <- rlang::call2(
func,
!!!rlang::set_names(lapply(args, as.symbol), args)
)

rlang::new_function(formal_args, recall)
wrapper
}

globals <- new.env(parent = emptyenv())
Expand Down
Loading