Hi Reed,
I need to stress before giving my answer that no solution can handle everything. These scenarios will always lead to problems: * if any of the formal arguments rely on the current state of the call stack * if any of the formal arguments rely on a variable that is only defined later in the body of the function That being said, this function does well to handle other scenarios: ```R f <- function (...) { ## replace f0 as needed wrapped_function <- f0 call <- match.call(wrapped_function, expand.dots = FALSE) args <- as.list(call)[-1L] e <- new.env(parent = environment(wrapped_function)) parent_frame <- parent.frame() formal_args <- formals(wrapped_function) for (sym in names(formal_args)) { ## if the formal argument is one of the provided arguments if (i <- match(sym, names(args), 0L)) { ## if the argument is missing, assign as is if (identical(args[[i]], quote(expr = ))) e[[sym]] <- quote(expr = ) ## if the argument is not ..., assign as a promise else if (sym != "...") eval(call("delayedAssign", quote(sym), args[[i]], eval.env = quote(parent_frame), assign.env = quote(e))) else { ## handle ... separately ## create a variable corresponding to each dot argument, ## then capture them with get("...") dots <- args[[i]] for (i in seq_along(dots)) { sym <- paste0("dd", i) eval(call("delayedAssign", quote(sym), dots[[i]], eval.env = quote(parent_frame))) dots[[i]] <- as.symbol(sym) } e[["..."]] <- eval(as.call(c(function(...) get("..."), dots))) } } else { ## similar to above, but this time evaluate in e not parent_frame i <- match(sym, names(formal_args), 0L) if (identical(formal_args[[i]], quote(expr = ))) e[[sym]] <- quote(expr = ) else eval(call("delayedAssign", quote(sym), formal_args[[i]], eval.env = quote(e), assign.env = quote(e))) } } ## you don't need to turn into a list, but you can args2 <- as.list(e, all.names = TRUE) list(call = call, args = args, args2 = args2, e = e) ## do whatever else you want to here } ``` in the test scenario you described, it works: ```R f0 <- function(x, y = 2 * z, z, a = NULL, b) NULL a <- 1 x <- f(a, z = 1 + 100) x$args2 ``` produces: ``` > f0 <- function(x, y = 2 * z, z, a = NULL, b) NULL > a <- 1 > x <- f(a, z = 1 + 100) > x$args2 $x [1] 1 $y [1] 202 $z [1] 101 $a NULL $b > ``` Regards, Iris On Sun, Feb 18, 2024 at 3:51 AM Reed A. Cartwright <racartwri...@gmail.com> wrote: > > I'm wrapping a function in R and I want to record all the arguments > passed to it, including default values and missing values. I want to > be able to snoop on function calls in sourced scripts as part of a > unit testing framework. > > I can capture the values fine, but I'm having trouble evaluating them > as if `force()` had been applied to each of them. > > Here is a minimal example: > > f0 <- function(x, y = 2 * z, z, a = NULL, b) NULL > > f <- function(...) { > call <- rlang::call_match(fn = f0, defaults = TRUE) > args <- rlang::call_args(call) > # do something here to evaluate args as if force() had been called > # I've tried many things but haven't found a solution that handled > everything > args > } > > # In the below example args1 and args2 should be the same > a <- 1 > args1 <- f(a, z = 1 + 100) > > args2 <- list( a = 1, y = 202, z = 101, a = NULL, b = rlang::missing_arg() ) > > If anyone knows how to get this to work, I would appreciate the help. > > Thanks, > Reed > > -- > Reed A. Cartwright, PhD > Associate Professor of Genomics, Evolution, and Bioinformatics > School of Life Sciences and The Biodesign Institute > Arizona State University > ================== > Address: The Biodesign Institute, PO Box 876401, Tempe, AZ 85287-6401 USA > Packages: The Biodesign Institute, 1001 S. McAllister Ave, Tempe, AZ > 85287-6401 USA > Office: Biodesign B-220C, 1-480-965-9949 > Website: http://cartwrig.ht/ > > ______________________________________________ > R-help@r-project.org mailing list -- To UNSUBSCRIBE and more, see > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. ______________________________________________ R-help@r-project.org mailing list -- To UNSUBSCRIBE and more, see https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.