|
10 | 10 | #' \code{.env} and \code{.data}. These are thin wrappers around \code{.data} |
11 | 11 | #' and \code{.env} that throw errors if you try to access non-existent values. |
12 | 12 | #' |
| 13 | +#' You can also provide additional sources of data by supplying named |
| 14 | +#' lists or data frames in \code{...}. Each of these arguments will |
| 15 | +#' get a pronoun based on the argument name. These names are |
| 16 | +#' automatically prefixed with a dot. Contrarily to \code{data}, these |
| 17 | +#' additional sources are not directly accessible. Therefore you have |
| 18 | +#' to explicitly qualify them with the relevant pronoun to access |
| 19 | +#' these data. |
| 20 | +#' |
13 | 21 | #' @param f A one-sided formula. Any expressions wrapped in \code{ uq() } will |
14 | 22 | #' will be "unquoted", i.e. they will be evaluated, and the results inserted |
15 | 23 | #' back into the formula. See \code{\link{f_interp}} for more details. |
16 | 24 | #' @param data A list (or data frame). \code{find_data} is a generic used to |
17 | 25 | #' find the data associated with a given object. If you want to make |
18 | 26 | #' \code{f_eval} work for your own objects, you can define a method for this |
19 | 27 | #' generic. |
| 28 | +#' @param ... Additional sources of pronouns. These should be named |
| 29 | +#' lists or data frames. The names of the pronouns are automatically |
| 30 | +#' prefixed with a dot. |
20 | 31 | #' @param x An object for which you want to find associated data. |
21 | 32 | #' @export |
22 | 33 | #' @examples |
|
40 | 51 | #' f_eval(~ .data$cyl, mtcars) |
41 | 52 | #' f_eval(~ .env$cyl, mtcars) |
42 | 53 | #' |
| 54 | +#' # Additional pronouns can be added by supplying explicit: |
| 55 | +#' f_eval(~ .iris$Species, iris = iris) |
| 56 | +#' |
| 57 | +#' # The data contained in these sources can only be accessed |
| 58 | +#' # explicitly, through the pronoun. Direct access will fail: |
| 59 | +#' \dontrun{f_eval(~ Species, iris = iris)} |
| 60 | +#' |
43 | 61 | #' # Imagine you are computing the mean of a variable: |
44 | 62 | #' f_eval(~ mean(cyl), mtcars) |
45 | 63 | #' # How can you change the variable that's being computed? |
|
56 | 74 | #' |
57 | 75 | #' # Instead we need to use the prefix form of `$`. |
58 | 76 | #' f_eval(~ mean( `$`(.data, uq(var) )), mtcars) |
59 | | -f_eval <- function(f, data = NULL) { |
| 77 | +f_eval <- function(f, data = NULL, ...) { |
60 | 78 | expr <- f_rhs(f_interp(f)) |
61 | 79 |
|
62 | 80 | data <- find_data(data) |
63 | 81 | env <- environment(f) |
| 82 | + explicit <- list(...) |
| 83 | + |
| 84 | + if (length(explicit)) { |
| 85 | + if (is.null(names(explicit))) { |
| 86 | + stop("`explicit` should be named", call. = FALSE) |
| 87 | + } |
| 88 | + if (!all(vapply(explicit, is.list, logical(1)))) { |
| 89 | + stop("`explicit` should contain lists or data frames", call. = FALSE) |
| 90 | + } |
| 91 | + } |
| 92 | + names(explicit) <- vapply(names(explicit), |
| 93 | + function(x) paste0(".", x), character(1)) |
64 | 94 |
|
65 | 95 | expr_env <- new.env(parent = env) |
66 | | - expr_env$.env <- complain(env) |
67 | | - expr_env$.data <- complain(data) |
| 96 | + sources <- c(.env = env, .data = list(data), explicit) |
| 97 | + for (source in names(sources)) { |
| 98 | + expr_env[[source]] <- complain(sources[[source]]) |
| 99 | + } |
68 | 100 |
|
69 | 101 | eval(expr, data, expr_env) |
70 | 102 | } |
|
0 commit comments