How do I add checks to a function created using tidy eval framework?

Viewed 62

Say I have created a function using the tidy eval framework -

library(tidyverse)
library(rlang)

my_function <- function(data, var){
    
    var_expr <- enquo(var)
    
    data %>% 
        group_by(!!var_expr) %>% 
        summarise(count = n()) %>% 
        ungroup()
}

When I run the following function, I get the result below it

my_function(mtcars, cyl)

# A tibble: 3 x 2
    cyl count
  <dbl> <int>
1     4    11
2     6     7
3     8    14

How do I add the following checks to this function -

  1. Check if data is a dataframe. If not, return the error data should be a dataframe
  2. Check if var is missing. If so return the error var is missing
1 Answers

You can make the following modifications.

  • In order to check if our input data is of a particular class we can check its class attribute and in this case whether it's a data frame or tibble they both contains the class data.frame
  • Also for missing function, it is normally used inside many functions to check whether an argument is assigned a value so that they generate a value as the default value. In your case we can terminate the execution of the function (you can also check the source code of length function on how it specifies a value for size argument when it is missing)
  • You can use base::stop in place of rlang::abort as specified by dear @akrun
library(rlang)

my_function <- function(data, var){
  if(!"data.frame" %in% attr(data, "class")) {
    abort("data should be a data frame")
  } 
  if(missing(var)) {
    abort("var is missing")
  }
  
  var_expr <- enquo(var)
  
  data %>% 
    group_by(!!var_expr) %>% 
    summarise(count = n()) %>% 
    ungroup()
}

Special thanks to dear @27 ϕ 9 for bringing this valuable point to my attention. We can also customize the output error message in stopifnot function which is another way of checking your input arguments:

my_function <- function(data, var){
  stopifnot("The input data is not of class data frame" = "data.frame" %in% attr(data, "class") ,
            "var is missing" = !missing(var)) 
  
  var_expr <- enquo(var)
  
  data %>% 
    group_by(!!var_expr) %>% 
    summarise(count = n()) %>% 
    ungroup()
}

Special thanks to dear @IceCreamToucan for presenting yet another option which is using the inherits function in lieu of attr. In case the input data does not include data.frame in its class attributes it returns FALSE:

my_function <- function(data, var){
  if(!inherits(data, "data.frame")) {
    stop("data is not of class data.frame")
  } 
  
  if(missing(var)) {
    stop("var is missing")
  }
  
  var_expr <- enquo(var)
  
  data %>% 
    group_by(!!var_expr) %>% 
    summarise(count = n()) %>% 
    ungroup()
}
Related