teppo
teppo

Reputation: 696

How to test if R dplyr::select() helper function is NULL inside a function

I know you can use "indirection" when you use dplyr::select() inside a function:

myselect1 <- function( df, select_arg ) {
    df %>%
        select( {{ select_arg }} )
}

starwars %>%
    myselect1( contains( '_color' ) ) %>%
    head( n = 3 )

# hair_color    skin_color  eye_color
# <chr>         <chr>       <chr>
# blond         fair        blue
# NA            gold        yellow
# NA            white, blue red

But, since you can only use a selection helper within a selecting function, if I want to make the selection conditional, I get an error:

myselect2 <- function( df, select_arg = NULL ) {
    if( !is.null( select_arg ) ) {
        df %>%
            select( {{ select_arg }} )
    } else {
        df
    }
}

starwars %>%
    myselect2( contains( '_color' ) ) %>%
    head( n = 3 )

# Error:
# ! `contains()` must be used within a *selecting* function.
# i See <https://tidyselect.r-lib.org/reference/faq-selection-context.html>.
# Backtrace:
#  1. starwars %>% myselect2(contains("_color")) %>% head(n = 3)
#  4. tidyselect::contains("_color")
#  6. tidyselect::peek_vars(fn = "contains")

How could I test whether the selection helper exists or not?

Upvotes: 1

Views: 55

Answers (1)

stefan
stefan

Reputation: 125538

You have to rlang::enquote the function argument. Afterwards you could check for NULL using rlang::quo_is_null:

library(dplyr, warn=FALSE)

myselect2 <- function(df, select_arg = NULL) {
  if (!rlang::quo_is_null(enquo(select_arg))) {
    df %>%
      select({{ select_arg }})
  } else {
    df
  }
}

starwars %>%
  myselect2(contains("_color")) %>%
  head(n = 3)
#> # A tibble: 3 × 3
#>   hair_color skin_color  eye_color
#>   <chr>      <chr>       <chr>    
#> 1 blond      fair        blue     
#> 2 <NA>       gold        yellow   
#> 3 <NA>       white, blue red

starwars %>%
  myselect2() %>%
  head(n = 3)
#> # A tibble: 3 × 14
#>   name         height  mass hair_…¹ skin_…² eye_c…³ birth…⁴ sex   gender homew…⁵
#>   <chr>         <int> <dbl> <chr>   <chr>   <chr>     <dbl> <chr> <chr>  <chr>  
#> 1 Luke Skywal…    172    77 blond   fair    blue         19 male  mascu… Tatooi…
#> 2 C-3PO           167    75 <NA>    gold    yellow      112 none  mascu… Tatooi…
#> 3 R2-D2            96    32 <NA>    white,… red          33 none  mascu… Naboo  
#> # … with 4 more variables: species <chr>, films <list>, vehicles <list>,
#> #   starships <list>, and abbreviated variable names ¹​hair_color, ²​skin_color,
#> #   ³​eye_color, ⁴​birth_year, ⁵​homeworld

Upvotes: 2

Related Questions