I had some trouble to forward '...' in R.
I've found a solution but I still don't understand why my original code was incorrect. Maybe someone can explain it to me ?
I have prepared a reprex:
# modify a string with glue.
# z is an optional argument
fun_A <- function(my_string, ..., z = NULL){
print(paste0("z value: ", as.character(z))) # do something with z here
print(list(...)) # to test: print ... to check that all variables are still there
my_string <- glue::glue(my_string, ...)
my_string
}
# when fun_A() is used inside fun_B, 'z' must be filled with the same value in fun_A() and fun_B().
fun_B <- function(z, my_string, ...){
my_string_mod <- rlang::enquo(my_string) %>%
rlang::call_modify(z = z) %>%
rlang::eval_tidy()
my_string_mod
# then other stuff, useless for the reprex
}
# calls fun_B() but for a specific string, now the argument of my_string are explicit.
fun_C_ok <- function(x, y){
fun_B(z = "i am z",
my_string = fun_A(my_string = "replace {x} and {y}.",
x = !!x, y = !!y)
)
Everything works as I want:
In fun_A(), 'z' is missing as expected. 'x' and 'y' are changed as expected
> fun_A(my_string = "replace {x} and {y}.", x = "this", y = "that")
[1] "z value: "
$x
[1] "this"
$y
[1] "that"
replace this and that.
In fun_B(), 'z' is modified in fun_A() as expected. 'x' and 'y' are changed as expected
> fun_B(z = "i am z", my_string = fun_A(my_string = "replace {x} and {y}.", x = "this", y = "that"))
[1] "z value: i am z"
$x
[1] "this"
$y
[1] "that"
replace this and that.
In fun_C_ok(), 'z' is modified in fun_A() as expected. 'x' and 'y' are changed as expected
> fun_C_ok(x = "this", y = "that")
[1] "z value: i am z"
$x
[1] "this"
$y
[1] "that"
replace this and that.
At first, i wrote the last function like this (without the bang-bang operator (!!))
fun_C_notok <- function(x, y){
fun_B(z = "i am z",
my_string = fun_A(my_string = "replace {x} and {y}.",
x = x, y = y)
)
}
It wasn't working, 'x' was not found by glue inside fun_A() but I don't understand why because 'x' and 'y' exist in list(...)
> fun_C_notok(x = "this", y = "that")
[1] "z value: i am z"
$x
[1] "this"
$y
[1] "that"
Error in eval(parse(text = text, keep.source = FALSE), envir) :
object 'x' not found
11. eval(parse(text = text, keep.source = FALSE), envir)
10. eval(parse(text = text, keep.source = FALSE), envir)
9. .transformer(expr, env)
8. (function (expr)
{
eval_func <- .transformer(expr, env)
tryCatch(as.character(eval_func), error = function(e) { ...
7. glue_data(.x = NULL, ..., .sep = .sep, .envir = .envir, .open = .open,
.close = .close, .na = .na, .transformer = .transformer,
.trim = .trim)
6. glue::glue(my_string, ...)
5. fun_A(my_string = "replace {x} and {y}.", x = x, y = y, z = "i am z")
4. rlang::eval_tidy(.)
3. rlang::enquo(my_string) %>% rlang::call_modify(z = z) %>% rlang::eval_tidy()
2. fun_B(z = "i am z", my_string = fun_A(my_string = "replace {x} and {y}.",
x = x, y = y))
1. fun_C_notok(x = "this", y = "that")
Does somebody understand why glue() can't find 'x' in fun_C_notok() ??