I've taken quasiquotation to a top level. I'm close to getting my master-quasiquotator badge (see edits below). There's one chellenge bit left.
Using different inputs to create quosures with dplyr. The end result is:
the_quote <- quo( if_else(!!cond_expr, !!inter_quo, !!var_expr) )
And I have managed to construct expressions above from a customized table with character strings, like this:
var_expr <- as.name(rules_df$target_col)
cond_expr <- "make == '%s'" %>% sprintf(rules_df$context_col) %>% parse_expr()
inter_quo <- quo(
str_detect( !!var_expr, regex(!!rules_df$phrase_col) ))
And where context_col
, phrase_col
, target_col
are string columns in a table that I've defined the rules of engagement.
Example:
rules_df <- data_frame(
context_col = "BMW",
phrase_col = "Serie X(\\d)",
target_col = "model")
cars_table <- data_frame(
make = c("Mercedes", "BMW", "BMW"),
model = c("Viano", "Serie X5", "Z4"))
Tells me to find those BMW's as Serie X5
, which I would later replace with just X5
but that's another story.
On printing the quote, I noticed that the expressions work well, but intermediate quosure is giving an error.
> the_quote
<quosure>
expr: ^if_else(marca == "BMW",
^str_detect(model, regex("Serie X(\d)")), model)
env: 000000002001DEE0
> mutate(cars_table, detect = !!the_quote)
Error: Evaluation error: `false` must be type logical, not character.
In the quosure I have an extra ^
which is converting the result of str_detect into a character.
How do I integrate this intermediate quosure into the outside one?
Thanks.
Upon reviewing the solution, it ends up that the issue in this challenge was not quotation, but using if_else
correctly in detect
column. That is changing logical into character, or just having the false clause act accordingly.
Thus, the alternative solution is to set if_else(!!cond_expr, !!inter_quo, FALSE)
from the beginning.
We need to wrap with as.character
as the str_detect
returns a logical class, while the false
parameter of if_else
is returning 'character'. The if_else
is particular about the class. Thus, if we do
inter_quo <- quo( as.character(str_detect( !!var_expr,
regex(!!rules_df$phrase_col) )))
then it should work
mutate(cars_table, detect = !!the_quote)
# A tibble: 3 x 3
# make model detect
# <chr> <chr> <chr>
#1 Mercedes Viano Viano
#2 BMW Serie X5 TRUE
#3 BMW Z4 FALSE