Using rlang
, I'd like to have a function that works both when directly called and when passed arguments as part of constructing another function argument by default, e.g.:
refdf = data.frame(x=1:100, y=runif(100,-1,1))
test.helper <- function(z, df) {
qz <- enquo(z)
range(eval_tidy(qz, df))
}
test.helper(y, refdf) # works
test.main <- function(z, df, def = test.helper(z, df)) {
print(def)
}
test.main(y, refdf)
# doesn't work: Error in eval_tidy(qz, df) : object 'y' not found
If instead, I do
refdf = data.frame(x=1:100, y=runif(100,-1,1))
test.helper <- function(z, df) {
qz <- as_quosure(z)
range(eval_tidy(qz, df))
}
test.helper(y, refdf)
# doesn't work: Error in is_quosure(x) : object 'y' not found
test.main <- function(z, df, def = test.helper(enquo(z), df)) {
print(def)
}
test.main(y, refdf)
# now works
I feel like I'm missing something about what gets quoted when; is there an alternative syntax I can use to make both work? I know I could define a separate test.helper_quo
or some such, but I'd really like to use the test.helper
in the signature (as an extra hint to users about what functions are available).
This should work
library(rlang)
test.helper <- function(z, df) {
qz <- enquo(z)
range(eval_tidy(qz, df))
}
test.helper(y, refdf) # works
test.main <- function(z, df, def = test.helper(!!enquo(z), df)) {
print(def)
}
test.main(y, refdf) # works
# or with rlang >= 0.4.0
test.main <- function(z, df, def = test.helper({{z}}, df)) {
print(def)
}
test.main(y, refdf) # works
Note that in def
, we need to capture the quosure passed as z
and then expand that into the the call the test.helper
so the it's own enquo
will be able to see the original symbol.