@@ -215,6 +215,15 @@ assert_sufficient_f_args <- function(f, ...) {
215215# ' scoping issues involved. Package developers should avoid
216216# ' supplying functions by name and instead supply them by value.
217217# '
218+ # ' @param calc_ref_time_value Boolean indicating whether the computation
219+ # ' function should include a step to calculate `ref_time_value` based on the
220+ # ' contents of the group data `.x`. This is used in `epi_slide`. When this
221+ # ' flag is `FALSE`, as is the default, the resulting computation takes the
222+ # ' three standard arguments, group data, group key(s), and reference time
223+ # ' value, plus any extra arguments. When this flag is `TRUE`, the resulting
224+ # ' computation only takes two of the standard arguments, group data and
225+ # ' group key(s), plus any extra arguments. The `ref_time_value` argument is
226+ # ' unnecessary since its value is being calculated within the computation.
218227# ' @param env Environment in which to fetch the function in case `x`
219228# ' is a string.
220229# ' @inheritParams rlang::args_dots_empty
@@ -235,47 +244,97 @@ assert_sufficient_f_args <- function(f, ...) {
235244# '
236245# ' @noRd
237246as_slide_computation <- function (x ,
247+ calc_ref_time_value = FALSE ,
248+ before ,
238249 env = global_env(),
239250 ... ,
240251 arg = caller_arg(x ),
241252 call = caller_env()) {
242- if (is_function(x )) {
243- # Check that `f` takes enough args
244- assert_sufficient_f_args(x , ... )
245- return (x )
253+ # A quosure is a type of formula, so be careful with `if` logic here.
254+ if (is_quosure(x )) {
255+ if (calc_ref_time_value ) {
256+ f_wrapper = function (.x , .group_key , quo , ... ) {
257+ .ref_time_value = min(.x $ time_value ) + before
258+ .x <- .x [.x $ .real ,]
259+ .x $ .real <- NULL
260+
261+ data_env = rlang :: as_environment(.x )
262+ data_mask = rlang :: new_data_mask(bottom = data_env , top = data_env )
263+ data_mask $ .data <- rlang :: as_data_pronoun(data_mask )
264+ # We'll also install `.x` directly, not as an `rlang_data_pronoun`, so
265+ # that we can, e.g., use more dplyr and epiprocess operations.
266+ data_mask $ .x = .x
267+ data_mask $ .group_key = .group_key
268+ data_mask $ .ref_time_value = .ref_time_value
269+ rlang :: eval_tidy(quo , data_mask )
270+ }
271+ return (f_wrapper )
272+ }
273+
274+ f_wrapper = function (.x , .group_key , .ref_time_value , quo , ... ) {
275+ # Convert to environment to standardize between tibble and R6
276+ # based inputs. In both cases, we should get a simple
277+ # environment with the empty environment as its parent.
278+ data_env = rlang :: as_environment(.x )
279+ data_mask = rlang :: new_data_mask(bottom = data_env , top = data_env )
280+ data_mask $ .data <- rlang :: as_data_pronoun(data_mask )
281+ # We'll also install `.x` directly, not as an
282+ # `rlang_data_pronoun`, so that we can, e.g., use more dplyr and
283+ # epiprocess operations.
284+ data_mask $ .x = .x
285+ data_mask $ .group_key = .group_key
286+ data_mask $ .ref_time_value = .ref_time_value
287+ rlang :: eval_tidy(quo , data_mask )
288+ }
289+ return (f_wrapper )
246290 }
247291
248- if (is_formula(x )) {
249- if (length(x ) > 2 ) {
250- Abort(sprintf(" %s must be a one-sided formula" , arg ),
251- class = " epiprocess__as_slide_computation__formula_is_twosided" ,
252- epiprocess__x = x ,
253- call = call )
292+ if (is_function(x ) || is_formula(x )) {
293+ if (is_function(x )) {
294+ # Check that `f` takes enough args
295+ assert_sufficient_f_args(x , ... )
296+ fn <- x
297+ }
298+
299+ if (is_formula(x )) {
300+ if (length(x ) > 2 ) {
301+ Abort(sprintf(" %s must be a one-sided formula" , arg ),
302+ class = " epiprocess__as_slide_computation__formula_is_twosided" ,
303+ epiprocess__x = x ,
304+ call = call )
305+ }
306+
307+ env <- f_env(x )
308+ if (! is_environment(env )) {
309+ Abort(" Formula must carry an environment." ,
310+ class = " epiprocess__as_slide_computation__formula_has_no_env" ,
311+ epiprocess__x = x ,
312+ epiprocess__x_env = env ,
313+ arg = arg , call = call )
314+ }
315+
316+ args <- list (
317+ ... = missing_arg(),
318+ .x = quote(..1 ), .y = quote(..2 ), .z = quote(..3 ),
319+ . = quote(..1 ), .group_key = quote(..2 ), .ref_time_value = quote(..3 )
320+ )
321+ fn <- new_function(args , f_rhs(x ), env )
322+ fn <- structure(fn , class = c(" epiprocess_slide_computation" , " function" ))
254323 }
255324
256- env <- f_env(x )
257- if (! is_environment(env )) {
258- Abort(" Formula must carry an environment." ,
259- class = " epiprocess__as_slide_computation__formula_has_no_env" ,
260- epiprocess__x = x ,
261- epiprocess__x_env = env ,
262- arg = arg , call = call )
325+ if (calc_ref_time_value ) {
326+ f_wrapper = function (.x , .group_key , ... ) {
327+ .ref_time_value = min(.x $ time_value ) + before
328+ .x <- .x [.x $ .real ,]
329+ .x $ .real <- NULL
330+ fn(.x , .group_key , .ref_time_value , ... )
331+ }
332+ return (f_wrapper )
263333 }
264334
265- args <- list (
266- ... = missing_arg(),
267- .x = quote(..1 ), .y = quote(..2 ), .z = quote(..3 ),
268- . = quote(..1 ), .group_key = quote(..2 ), .ref_time_value = quote(..3 )
269- )
270- fn <- new_function(args , f_rhs(x ), env )
271- fn <- structure(fn , class = c(" epiprocess_slide_computation" , " function" ))
272335 return (fn )
273336 }
274337
275- if (is_string(x )) {
276- return (get(x , envir = env , mode = " function" ))
277- }
278-
279338 Abort(sprintf(" Can't convert a %s to a slide computation" , class(x )),
280339 class = " epiprocess__as_slide_computation__cant_convert_catchall" ,
281340 epiprocess__x = x ,
0 commit comments