Reputation: 692
The Problem
I would like to make sure my enquo
arguments of a custom function are of the correct type before I pass it off to a dplyr
chain.
What I've Tried
I was able to combine the arguments into a dataframe
and then test each variable's type. But I'm wondering if there is a solution that can test each type before putting it into a dataframe
?
I've also tried this, to no avail:
my_function_if <- function(data, numeric_arg, logic_arg, chr_arg){
if(is.numeric(data$numeric_arg)){
enq_numeric <- enquo(numeric_arg)
} else {
warning("Argument \"numeric_arg\" must be numeric")
}
if(is.logical(data$logic_arg)){
enq_logic <- enquo(logic_arg)
} else {
warning("Argument \"logic_arg\" must be logical")
}
if(is.character(data$chr_arg)){
enq_chr <- enquo(chr_arg)
} else {
warning("Argument \"chr_arg\" must be of type character")
}
df <- data %>%
mutate(numeric_col2 = UQ(enq_numeric)*2,
logic_col2 = !UQ(enq_numeric),
chr_col2 = UQ(enq_chr))
return(df)
}
The Sample Data and Sample Function
This is what I am using to test the general concept of evaluating columns with enquo:
library(dplyr)
dataFrame <- data.frame(numeric_col = c(1.5:10.5),
logic_col = c(rep(T, 10)),
chr_col = c(letters[1:10]),
stringsAsFactors = FALSE)
my_function <- function(data, numeric_arg, logic_arg, chr_arg){
enq_numeric <- enquo(numeric_arg)
enq_logic <- enquo(logic_arg)
enq_chr <- enquo(chr_arg)
df <- data %>%
mutate(numeric_col2 = UQ(enq_numeric)*2,
logic_col2 = !UQ(enq_numeric),
chr_col2 = UQ(enq_chr))
return(df)
}
Correct Output Without any Errors: (Though I'm looking for more general solutions, since this is a sample function)
numeric_col logic_col chr_col numeric_col2 logic_col2 chr_col2
1 1.5 TRUE a 3 FALSE a
2 2.5 TRUE b 5 FALSE b
3 3.5 TRUE c 7 FALSE c
4 4.5 TRUE d 9 FALSE d
5 5.5 TRUE e 11 FALSE e
6 6.5 TRUE f 13 FALSE f
7 7.5 TRUE g 15 FALSE g
8 8.5 TRUE h 17 FALSE h
9 9.5 TRUE i 19 FALSE i
10 10.5 TRUE j 21 FALSE j
Additionally
I have tried to search for this in many of Hadley's resources, StackOverflow, and other blogs. But I could just be having a difficult time knowing what to search for. I am always open to figuring it out myself, if you are able to point me in the right direction. Any additional resources are more than welcome.
Thanks, in advance!
Upvotes: 4
Views: 463
Reputation: 206536
I'd recommend something like this
check_class <- function(data, q, test) {
test(rlang::eval_tidy(q, data))
}
my_function <- function(data, numeric_arg, logic_arg, chr_arg){
enq_numeric <- enquo(numeric_arg)
enq_logic <- enquo(logic_arg)
enq_chr <- enquo(chr_arg)
stopifnot(check_class(data, enq_numeric, is.numeric))
stopifnot(check_class(data, enq_logic, is.logical))
stopifnot(check_class(data, enq_chr, is.character))
df <- data %>%
mutate(numeric_col2 = UQ(enq_numeric)*2,
logic_col2 = !UQ(enq_numeric),
chr_col2 = UQ(enq_chr))
return(df)
}
We use rlang::eval_tidy
to evaluate the quosures in the context of the data.frame. You really have to evaluate them because you really have no idea what might be in them until you evaluate. Then you can check the class of whatever comes out. This allows you to do functions of those variables as well. These both work.
my_function(dataFrame, numeric_col, logic_col, chr_col)
my_function(dataFrame, as.numeric(logic_col), logic_col, as.character(logic_col))
Upvotes: 2