Testing a function that uses enquo() for a NULL parameter
This problem doesn't really have to do with quo
and enquo
returning different things, it's really about evaluating objects before you really want to. If you were to use the browser()
to step through your function, you'd see the error occurs at the if (is.null(new_var_name))
statement.
When you do is.null(new_var_name)
, you are evaluating the variable passed as new_var_name
so it's too late to enquo
it. That's because is.null
needs to look at the value of the variable rather than just the variable name itself.
A function that does not evaluate the parameter passed to the function but checks to see if it is there is missing()
.
my_fun <- function(df, col_name, new_var_name=NULL) {
target <- enquo(col_name)
c <- df %>% pull(!!target) * 3 # here may be more complex calculations
# handling NULL name
if (missing(new_var_name)) {
new_name <- "default_name"
} else{
new_name <- quo_name(enquo(new_var_name))
}
data_frame(
abc = df %>% pull(!!target),
!!new_name := c
)
}
Then you can run both of these
my_fun(dataframe, a)
my_fun(dataframe, a, NEW_NAME)
How to test null or missing for enquos-type quosures
Use length(dot_vars)
to determine if it has a length of 0.
Check if object is Null or undefined
{{
is the combination of enquo()
and !!
in one step. To inspect the contents of var
, you need to decompose these two steps. enquo()
defuses the argument and returns a quosure that you can inspect. !!
injects the quosure into other calls.
Below we enquo()
the argument at the start of the function. Inspect it with quo_is_null()
(you could also use quo_get_expr()
to see what's inside it). Then inject it inside group_by()
with !!
:
myfun <- function(dat, group = NULL, var = NULL) {
var <- enquo(var)
if (!quo_is_null(var)) {
print("It works!")
}
# Use `!!` instead of `{{` because we have decomposed the
# `enquo()` and `!!` steps that `{{` bundles
dat %>%
group_by({{ group }}, !!var) %>%
summarize(mean = mean(value), .groups = "drop")
}
Testing conditions on a function's parameter using testthat
testthat checks if the result of the function is what you expect.
If you want to test the result of the function to NAs, you can make a specific test for this :
library(testthat)
library(assertthat)
func <- function(expr,data.sizes) {
assert_that(noNA(data.sizes))
eval(expr)
}
test_that("data.sizes test for func", {
# Success
expect_error(func(expression(data.sizes[1]+data.sizes[2]), data.sizes = c(1,NA)))
expect_equal(func(expression(data.sizes[1]+data.sizes[2]), data.sizes = c(1,2)),3)
# Failure
expect_equal(func(expression(data.sizes[1]+data.sizes[2]), data.sizes = c(1,2)),4)
})
To test validity of parameters inside the function, you can use assertive programming packages like assertthat.
If/else condition in dplyr 0.7 function
The problem here is that when you supply unquoted arguments, is.null
doesn't know what to do with it. So this code tries to check whether object B
is null and errors because B
does not exist in that scope. Instead, you can use missing()
to check whether an argument was supplied to the function, like so. There may be a cleaner way but this at least works, as you can see at the bottom.
library(tidyverse)
test <- tibble(
A = c(1:5,1:5),
B = c(1,2,1,2,3,3,3,3,3,3),
C = c(1,1,1,1,2,3,4,5,4,3)
)
# begin function, set default for group var to NULL.
prop_tab <- function(df, column, group) {
col_name <- enquo(column)
group_name <- enquo(group)
# if group_by var is not supplied, then:
if(!missing(group)) {
temp <- df %>%
select(!!col_name, !!group_name) %>%
group_by(!!group_name) %>%
summarise(Percentages = 100 * length(!!col_name) / nrow(df))
} else {
# if group_by var is null, then...
temp <- df %>%
select(!!col_name) %>%
group_by(col_name = !!col_name) %>%
summarise(Percentages = 100 * length(!!col_name) / nrow(df))
}
temp
}
test %>% prop_tab(column = C) # works
#> # A tibble: 5 x 2
#> col_name Percentages
#> <dbl> <dbl>
#> 1 1 40
#> 2 2 10
#> 3 3 20
#> 4 4 20
#> 5 5 10
test %>% prop_tab(column = A, group = B)
#> # A tibble: 3 x 2
#> B Percentages
#> <dbl> <dbl>
#> 1 1 20
#> 2 2 20
#> 3 3 60
Created on 2018-06-29 by the reprex package (v0.2.0).
Related Topics
Are Data Tables with More Than 2^31 Rows Supported in R with the Data Table Package Yet
3D Equivalent of the Curve Function in R
How to Plot a List of Vectors with Different Lengths
How to 'Unlist' a Column in a Data.Table
How to Use With/Within Inside a Function
Error in If/While (Condition):Argument Is Not Interpretable as Logical
Loop Through a Series of Qplots
Store Arrangegrob to Object, Does Not Create Printable Object
How to Increase Smoothness of Spheres3D in Rgl
Dygraph in R Multiple Plots at Once
Vary the Color Gradient on a Scatter Plot Created with Ggplot2
Extract Hyperlink from Excel File in R
Plot Line and Bar Graph (With Secondary Axis for Line Graph) Using Ggplot
Write.Csv() a List of Unequally Sized Data.Frames
How to Change the Default Directory in Rstudio (Or R)
How to Change Color in Shiny Dashboard