Skip to content

Commit e5adcbd

Browse files
committed
feat(epi[x]_slide): hint on forgotten syntax specifying comp
1 parent 44e7095 commit e5adcbd

File tree

8 files changed

+115
-16
lines changed

8 files changed

+115
-16
lines changed

DESCRIPTION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Type: Package
22
Package: epiprocess
33
Title: Tools for basic signal processing in epidemiology
4-
Version: 0.9.0
4+
Version: 0.10.1
55
Authors@R: c(
66
person("Jacob", "Bien", role = "ctb"),
77
person("Logan", "Brooks", , "[email protected]", role = c("aut", "cre")),

NEWS.md

+7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
Pre-1.0.0 numbering scheme: 0.x will indicate releases, while 0.x.y will indicate PR's.
44

5+
# epiprocess 0.10
6+
7+
## Improvements
8+
- `epi_slide` and `epix_slide` now provide some hints if you forget a `~` when
9+
using a formula to specify the slide computation, and other bits of forgotten
10+
syntax.
11+
512
# epiprocess 0.9
613

714
## Breaking changes

R/grouped_epi_archive.R

+3-2
Original file line numberDiff line numberDiff line change
@@ -312,14 +312,15 @@ epix_slide.grouped_epi_archive <- function(
312312
cli_abort("If `f` is missing then a computation must be specified via `...`.")
313313
}
314314

315-
.slide_comp <- as_diagonal_slide_computation(quosures)
315+
.f_arg <- ".f" # dummy val, shouldn't be used since we're not using `.f`
316+
.slide_comp <- as_diagonal_slide_computation(quosures, .f_arg = .f_arg, .call = caller_env())
316317
# Magic value that passes zero args as dots in calls below. Equivalent to
317318
# `... <- missing_arg()`, but use `assign` to avoid warning about
318319
# improper use of dots.
319320
assign("...", missing_arg())
320321
} else {
321322
used_data_masking <- FALSE
322-
.slide_comp <- as_diagonal_slide_computation(.f, ...)
323+
.slide_comp <- as_diagonal_slide_computation(.f, ..., .f_arg = caller_arg(.f), .call = caller_env())
323324
}
324325

325326
# Computation for one group, one time value

R/slide.R

+3-1
Original file line numberDiff line numberDiff line change
@@ -147,14 +147,16 @@ epi_slide <- function(
147147
}
148148

149149
.f <- quosures
150+
.f_arg <- ".f" # dummy val, shouldn't be used since we're not using `.f`
150151
# Magic value that passes zero args as dots in calls below. Equivalent to
151152
# `... <- missing_arg()`, but `assign` avoids warning about improper use of
152153
# dots.
153154
assign("...", missing_arg())
154155
} else {
155156
used_data_masking <- FALSE
157+
.f_arg <- caller_arg(.f)
156158
}
157-
.slide_comp <- as_time_slide_computation(.f, ...)
159+
.slide_comp <- as_time_slide_computation(.f, ..., .f_arg = .f_arg, .call = caller_env())
158160

159161
.align <- rlang::arg_match(.align)
160162
time_type <- attr(.x, "metadata")$time_type

R/utils.R

+31-10
Original file line numberDiff line numberDiff line change
@@ -358,9 +358,24 @@ assert_sufficient_f_args <- function(.f, ..., .ref_time_value_label) {
358358
#' @importFrom rlang is_function new_function f_env is_environment missing_arg
359359
#' f_rhs is_formula caller_arg caller_env
360360
#' @keywords internal
361-
as_slide_computation <- function(.f, ..., .ref_time_value_long_varnames, .ref_time_value_label) {
362-
arg <- caller_arg(.f)
363-
call <- caller_env()
361+
as_slide_computation <- function(.f, ..., .f_arg = caller_arg(.f), .call = caller_env(), .ref_time_value_long_varnames, .ref_time_value_label) {
362+
f_arg <- .f_arg # for cli interpolation, avoid dot prefix
363+
withCallingHandlers(
364+
{
365+
force(.f)
366+
},
367+
error = function(e) {
368+
cli_abort(
369+
c("Failed to convert {.code {f_arg}} to a slide computation.",
370+
"*" = "If you were trying to use the formula interface, maybe you forgot a tilde at the beginning.",
371+
"*" = "If you were trying to use the tidyeval interface, maybe you forgot to specify the name, e.g.: `my_output_col_name =`.",
372+
"*" = "If you were trying to use advanced features of the tidyeval interface such as `!! name_variable :=`, you might have forgotten the required leading comma."
373+
),
374+
parent = e,
375+
class = "epiprocess__as_slide_computation__error_forcing_.f"
376+
)
377+
}
378+
)
364379

365380
if (rlang::is_quosures(.f)) {
366381
quosures <- rlang::quos_auto_name(.f) # resolves := among other things
@@ -463,10 +478,10 @@ as_slide_computation <- function(.f, ..., .ref_time_value_long_varnames, .ref_ti
463478
}
464479

465480
if (length(.f) > 2) {
466-
cli_abort("{.code {arg}} must be a one-sided formula",
481+
cli_abort("{.code {f_arg}} must be a one-sided formula",
467482
class = "epiprocess__as_slide_computation__formula_is_twosided",
468483
epiprocess__f = .f,
469-
call = call
484+
.call = .call
470485
)
471486
}
472487
if (rlang::dots_n(...) > 0L) {
@@ -486,7 +501,7 @@ as_slide_computation <- function(.f, ..., .ref_time_value_long_varnames, .ref_ti
486501
class = "epiprocess__as_slide_computation__formula_has_no_env",
487502
epiprocess__f = .f,
488503
epiprocess__f_env = env,
489-
arg = arg, call = call
504+
.f_arg = .f_arg, .call = .call
490505
)
491506
}
492507

@@ -513,26 +528,32 @@ as_slide_computation <- function(.f, ..., .ref_time_value_long_varnames, .ref_ti
513528
class = "epiprocess__as_slide_computation__cant_convert_catchall",
514529
epiprocess__f = .f,
515530
epiprocess__f_class = class(.f),
516-
arg = arg,
517-
call = call
531+
.f_arg = .f_arg,
532+
.call = .call
518533
)
519534
}
520535

521536
#' @rdname as_slide_computation
537+
#' @importFrom rlang caller_arg caller_env
522538
#' @keywords internal
523-
as_time_slide_computation <- function(.f, ...) {
539+
as_time_slide_computation <- function(.f, ..., .f_arg = caller_arg(.f), .call = caller_env()) {
524540
as_slide_computation(
525541
.f, ...,
542+
.f_arg = .f_arg,
543+
.call = .call,
526544
.ref_time_value_long_varnames = ".ref_time_value",
527545
.ref_time_value_label = "reference time value"
528546
)
529547
}
530548

531549
#' @rdname as_slide_computation
550+
#' @importFrom rlang caller_arg caller_env
532551
#' @keywords internal
533-
as_diagonal_slide_computation <- function(.f, ...) {
552+
as_diagonal_slide_computation <- function(.f, ..., .f_arg = caller_arg(.f), .call = caller_env()) {
534553
as_slide_computation(
535554
.f, ...,
555+
.f_arg = .f_arg,
556+
.call = .call,
536557
.ref_time_value_long_varnames = c(".version", ".ref_time_value"),
537558
.ref_time_value_label = "version"
538559
)

man/as_slide_computation.Rd

+14-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/_snaps/utils.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# as_slide_computation raises errors as expected
2+
3+
Code
4+
toy_edf %>% group_by(geo_value) %>% epi_slide(.window_size = 6, tibble(
5+
slide_value = mean(.x$value)))
6+
Condition
7+
Error in `as_slide_computation()`:
8+
! Failed to convert `tibble(slide_value = mean(.x$value))` to a slide computation.
9+
* If you were trying to use the formula interface, maybe you forgot a tilde at the beginning.
10+
* If you were trying to use the tidyeval interface, maybe you forgot to specify the name, e.g.: `my_output_col_name =`.
11+
* If you were trying to use advanced features of the tidyeval interface such as `!! name_variable :=`, you might have forgotten the required leading comma.
12+
Caused by error:
13+
! object '.x' not found
14+
15+
---
16+
17+
Code
18+
toy_archive %>% epix_slide(tibble(slide_value = mean(.x$value)))
19+
Condition
20+
Error in `as_slide_computation()`:
21+
! Failed to convert `.f` to a slide computation.
22+
* If you were trying to use the formula interface, maybe you forgot a tilde at the beginning.
23+
* If you were trying to use the tidyeval interface, maybe you forgot to specify the name, e.g.: `my_output_col_name =`.
24+
* If you were trying to use advanced features of the tidyeval interface such as `!! name_variable :=`, you might have forgotten the required leading comma.
25+
Caused by error:
26+
! object '.x' not found
27+

tests/testthat/test-utils.R

+29
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,35 @@ test_that("as_slide_computation raises errors as expected", {
230230
expect_error(as_time_slide_computation(5),
231231
class = "epiprocess__as_slide_computation__cant_convert_catchall"
232232
)
233+
234+
# If `.f` doesn't look like tidyeval and we fail to force it, then we hint to
235+
# the user some potential problems:
236+
toy_edf <- tibble(geo_value = 1, time_value = c(1, 2), value = 1:2) %>%
237+
as_epi_df(as_of = 1)
238+
toy_archive <- tibble(version = c(1, 2, 2), geo_value = 1, time_value = c(1, 1, 2), value = 1:3) %>%
239+
as_epi_archive()
240+
expect_error(
241+
toy_edf %>%
242+
group_by(geo_value) %>%
243+
epi_slide(.window_size = 6, tibble(slide_value = mean(.x$value))),
244+
class = "epiprocess__as_slide_computation__error_forcing_.f"
245+
)
246+
expect_snapshot(
247+
error = TRUE,
248+
toy_edf %>%
249+
group_by(geo_value) %>%
250+
epi_slide(.window_size = 6, tibble(slide_value = mean(.x$value)))
251+
)
252+
expect_error(
253+
toy_archive %>%
254+
epix_slide(tibble(slide_value = mean(.x$value))),
255+
class = "epiprocess__as_slide_computation__error_forcing_.f"
256+
)
257+
expect_snapshot(
258+
error = TRUE,
259+
toy_archive %>%
260+
epix_slide(tibble(slide_value = mean(.x$value)))
261+
)
233262
})
234263

235264
test_that("as_slide_computation works", {

0 commit comments

Comments
 (0)