rlang::expr()1 to capture code directlyrlang::enexpr() to capture code indirectly#> a + b + c
#> [1] "" "x" "y"
#> f(x = 1, y = 2)
#> f(x = 1, y = 2, z = 3)
#> f(y = 2)
More on this next week!
lobstr::ast() to inspect these code treesrlang::call2() creates function call#> f1(f2("a", "b"), f3(1))
#> 1 + 2 * 3
!! bang-bang - unquote operator
#> xx/yy
#> (x + x)/(y + y)
#> sd(x)/mean(x)
#> sd(x + y)/mean(x + y)
paste() for building code
“You might think this is an esoteric concern, but not worrying about it when generating SQL code in web applications led to SQL injection attacks that have collectively cost billions of dollars.”
eval() uses current environment if not setFor example…
#> [1] "Hello cohort 9"
#> [1] "dslc is awesome---dslc is awesome---dslc is awesome---dslc is awesome---dslc is awesome---dslc is awesome---dslc is awesome---dslc is awesome---dslc is awesome---"
rlang::eval_tidy() rather than eval()Catch user input with enexpr()…
But there’s a bug!
with2(), but the expression likely refers to objects in the Global environment#> [1] 1001 1002 1003
enquo() instead of enexpr() (with eval_tidy())#> [1] 11 12 13
“Whenever you use a data mask, you must always use
enquo()instead ofenexpr().
This comes back in Chapter 20.
enquo() is called)Here, the global environment
with2 <- function(df, expr) {
a <- 1000
eq <- enquo(expr)
message("with2() Parent/Calling environment: ")
print(rlang::caller_env())
message("with2() environment: ")
print(rlang::current_env())
message("Quosure details: ")
print(eq) # Print the details of the quosure
eval_tidy(eq, df)
}
a <- 10000
df <- data.frame(x = 1:3)
with2(df, x + a)#> with2() Parent/Calling environment:
#> <environment: R_GlobalEnv>
#> with2() environment:
#> <environment: 0x0000018dede5ddd0>
#> Quosure details:
#> <quosure>
#> expr: ^x + a
#> env: global
#> [1] 10001 10002 10003
Here, the fun1() environment
#> fun1() Parent/Calling environment:
#> <environment: R_GlobalEnv>
#> fun1() environment:
#> <environment: 0x0000018df3e748f8>
#> with2() Parent/Calling environment:
#> <environment: 0x0000018df3e748f8>
#> with2() environment:
#> <environment: 0x0000018df3ebc698>
#> Quosure details:
#> <quosure>
#> expr: ^x + a
#> env: 0x0000018df3e748f8
#> [1] 11 12 13