I want to let users of my function enter variables in the tidyeval data-masking way i.e. fun(x, c(y, z))
as opposed to fun("x", c("y", "z"))
, but when they enter arguments like c(y, z)
, I want to be able to use this as a character vector, like c("y", "z")
.
I do have a seriously overkill workaround for working with column names. That is, I use {{
in a dpylr::select()
call and then extract the column names:
fun_overkill <- function(data, cols) {
data_subset <- dplyr::select(data, {{cols}})
args_as_character_vector <- colnames(data_subset)
args_as_character_vector
}
fun_overkill(mtcars, c(mpg, drat))
Clearly, this cannot be the best way, and it does not generalise to a situation where my vector argument doesn't represent column names.
I suspect {rlang}
may have the answer but there are so many choices and I do not understand the terminology.
A situation where this could be useful is in creating a model formula, as you can use as.formula
on a string, which you create from the character vector:
rhs <- paste(fun_overkill(mtcars, c(mpg, drat)), collapse = " + ")
lhs <- "~ "
as.formula(paste0(lhs, rhs))
One way is to capture the cols
variables of an expression with enexpr()
(enquo()
would work too), and then get the arguments from the expression with call_args()
. These are now a list of symbols, so you need to loop over them to make them characters with as_string()
.
library(rlang)
fun <- function(data, cols) {
vars <- call_args(enexpr(cols))
vapply(vars, as_string, character(1), USE.NAMES = FALSE)
}
(fun(mtcars, c(mpg, drat)))
#> [1] "mpg" "drat"
rhs <- paste(fun(mtcars, c(mpg, drat)), collapse = " + ")
lhs <- "~ "
as.formula(paste0(lhs, rhs))
#> ~mpg + drat
Created on 2021-09-03 by the reprex package (v2.0.1)
To be fair, the data
argument isn't needed at all here. It's just there because it was there in your example.