rdplyrrlangr-glue

Which rlang function should I use to evaluate a glue string as a variable name?


Suppose that I want to create a function to be used within dplyr::mutate(), and in which I feed a variable name, and within the function, it will extract a particular pattern in the variable name given and create a new variable name out of it, like so:

library(rlang)
library(dplyr)
library(stringr)
library(glue)

myfun <- function(var) {
  y <- str_remove(ensym(var), "^.*\\.")
  other_var <- glue("Petal.{y}")
  
  if_else(var > 6 | other_var > 3, 1, 0) # What rlang function do I need to apply to other_var here?
}

The problem I'm running into, is how do I use rlang tools to evaluate the new variable name "other_var" within the data frame, such that when I make the call below, it would look at the data within iris$Sepal.Length and iris$Petal.Length?

mutate(iris, test = myfun(Sepal.Length))

EDIT: The following solves my immediate problem, but I feel like there's a more elegant way:

myfun <- function(df, x) {
  y <- str_remove(ensym(x), "^.*\\.")
  other_var <- glue("Petal.{y}")
  
  if_else(x > 6 | df[[other_var]] > 3, 0, 1) 
}

mutate(iris, test = myfun(iris, Sepal.Length))

Solution

  • You can use the environment and call eval_tidy().

    This uses caller_env(n = 1):

    myfun <- function(var) {
      
      .var <- enexpr(var)
      var_name <- as_name(.var)
      
      y <- str_remove(var_name, "^.*\\.")
      other_var <- glue("Petal.{y}")
      
      .expr <- parse_expr(glue("if_else({var_name} > 6 | {other_var} > 3, 1, 0)"))
    
      eval_tidy(.expr, env = caller_env(n = 1))
    }
    

    This grabs the var as a quosure and uses that environment, which could be useful if you had nested functions down from the original mutate call.

    myfun <- function(var) {
      
      .var <- enquo(var)
      var_name <- as_name(.var)
      
      y <- str_remove(var_name, "^.*\\.")
      other_var <- glue("Petal.{y}")
      
      .expr <- parse_expr(glue("if_else({var_name} > 6 | {other_var} > 3, 1, 0)"))
      .quo <- new_quosure(.expr, quo_get_env(.var))
      
      eval_tidy(.quo)
    }