Is there a rlang equivalent to caller_env(sys.parent) to capture user function calls independently to how deeply nested the erroring function is?
caller_env() is great when working with functions that are closely related in the function tree but not so convenient when working with more distant functions because it's not always obvious to know how many callers one has to go back to get the right environment and can vary a lot, in particular when using R6 classes.
bar <- function(x) {
foo(x)
paste("input:", x)
}
foo <- function(x, arg = caller_arg(x), call = caller_env()) {
if (is.character(x)) {
return(invisible(NULL))
}
msg <- paste0("`", arg, "` must be a character vector.")
abort(msg, call = call)
}
If I execute bar(), I get a proper error message with the right function call:
bar(1)
#> Error in `bar()`:
#> ! `x` must be a character vector.
#> Run `rlang::last_error()` to see where the error occurred.
Now if I add more nesting, I won't get a proper error message (which points to bar() instead of blah()) unless I add a call parameter to bar/blah, call foo() in blah() or change the number of callers to go back.
blah <- function(x) {
bar(x)
}
blah(1)
#> Error in `bar()`:
#> ! `x` must be a character vector.
#> Run `rlang::last_error()` to see where the error occurred.
I can propagate the user function environment through the function tree by using caller_env(sys.parent) in foo(). I'm just wondering if there's a rlang function for that already.
Theres probably a proper way to do this; but I've stumbled through and found an arrangement that at least seems to work;
library(rlang)
bar <- function(x) {
foo(x)
paste("input:", x)
}
foo <- function(x, arg = caller_arg(x)) {
if (is.character(x)) {
return(invisible(NULL))
}
msg <- paste0("`", arg, "` must be a character vector.")
abort(msg,call=caller_call(trace_length(trace_back()) - 1))
}
bar(1)
# Error in `bar()`:
# ! `x` must be a character vector.
blah <- function(x) {
bar(x)
}
blah(1)
# Error in `blah()`:
# ! `x` must be a character vector.
Your solution seems to work but is more complicated and obscure than caller_env(sys.parent()). I was expecting a rlang function that does the trick directly but maybe that function doesn't exist, which explains why I didn't find it…