Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improving call support #132

Open
reedacartwright opened this issue Sep 1, 2024 · 0 comments
Open

Improving call support #132

reedacartwright opened this issue Sep 1, 2024 · 0 comments

Comments

@reedacartwright
Copy link

reedacartwright commented Sep 1, 2024

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)`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant