Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you make tidyverse functions that support both quoted and unquoted arguments?

I know how to make functions that support quasi-quotation for an argument named 'variable' {using dplyr::enquo(variable) for unquoted function arguments} or functions that require you to quote the argument {using rlang::sym("variable")}. Is there an easy way to make functions that support both quoted an unquoted arguments?

For instance, dplyr::select() allows both select(mtcars, mpg) and select(mtcars, "mpg"). What is the best practice for building a function that can do either? One consideration is the impact on data masking, which I'm unsure if I need to consider in building out more complex functions.

I've been looking through the github pages for the basic dplyr functions, but a simple function like select relies on a whole new package (tidyselect), so there is a lot going on. I didn't see a clear explanation in the Tidy evaluation book either. Below is a hack function that supports both quoted and unquoted arguments, but this is not a reliable solution. I'm sure there is an easier way.

library(dplyr)

data(mtcars)

test_func <- function(variable) {
  if(nrow(count(mtcars, {{variable}})) == 1) {
    variable <- rlang::sym(variable)
  }
  count(mtcars, {{variable}})
}

all_equal(
  test_func(cyl),
  test_func("cyl")
)
like image 652
bholly Avatar asked Apr 28 '20 22:04

bholly


1 Answers

If it needs to work on both quoted/unquoted, use ensym

test_func <- function(variable) {  

    dplyr::count(mtcars, !!rlang::ensym(variable))    

  }

-testing

test_func(cyl)
#  cyl  n
#1   4 11
#2   6  7
#3   8 14
test_func('cyl')
#  cyl  n
#1   4 11
#2   6  7
#3   8 14

NOTE: Better to have data also as an argument to the function

like image 67
akrun Avatar answered Nov 15 '22 00:11

akrun