I have been playing around with extending tinytest, and I noticed that the "call" argument in tinytest() gets overwritten by the function constructed by capture(). Additionally format.tinytest() has specific logic to reconstruct the call from the trace if needed. I assume that having capture() control the "call" is due to sys.call(sys.parent(1)), returning fun(...) for captured functions.
I was thinking of a solution around these issues, and decided to make capturing functions pass their call down to the captured functions. This allows expectations or anything that calls tinytest() to control what call looks like, making it easier to nest expectations.
An minimal example is below:
# Simple tinytest constructor
tinytest <- function(result, call = sys.call(sys.parent(1)), ...) {
force(call)
trace <- sys.calls()
structure(result, class = "tinytest", call = call, trace = trace, ...)
}
# Expectation that will be captured
expect_example <- function(...) {
tinytest(TRUE, ...)
}
# Simple capture function
capture <- function(fun) {
force(fun)
function(...) {
# Create a local variable that matches the name of the function that was called.
# Assign the captured function to that name.
# Evaluate the original call to pass it into the captured function.
call <- sys.call()
assign(as.character(call[[1]]), fun)
out <- eval(call)
## do stuff to out here.
attr(out, "captured") <- TRUE
out
}
}
So now when a captured function is called, sys.call(sys.parent(1)) behaves as expected. This allows the call attribute to be the same for captured and uncaptured functions.
expect_example(a=1, b=2) # call is `expect_example(a=1,b=2)`
expect_example <- capture(expect_example)
expect_example(a=1, b=2) # call is `expect_example(a=1,b=2)`
expect_example_alt <- expect_example
expect_example_alt(a=1, b=2) # call is `expect_example_alt(a=1,b=2)`
I have been playing around with extending tinytest, and I noticed that the "call" argument in
tinytest()gets overwritten by the function constructed bycapture(). Additionallyformat.tinytest()has specific logic to reconstruct the call from the trace if needed. I assume that havingcapture()control the "call" is due tosys.call(sys.parent(1)), returningfun(...)for captured functions.I was thinking of a solution around these issues, and decided to make capturing functions pass their call down to the captured functions. This allows expectations or anything that calls
tinytest()to control whatcalllooks like, making it easier to nest expectations.An minimal example is below:
So now when a captured function is called,
sys.call(sys.parent(1))behaves as expected. This allows the call attribute to be the same for captured and uncaptured functions.