-
Notifications
You must be signed in to change notification settings - Fork 292
Expand file tree
/
Copy pathdeprec-when.R
More file actions
93 lines (86 loc) · 2.88 KB
/
deprec-when.R
File metadata and controls
93 lines (86 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#' Match/validate a set of conditions for an object and continue with the action
#' associated with the first valid match.
#'
#' @description
#' `r lifecycle::badge("deprecated")`
#'
#' This function was deprecated in purrr 1.0.0 because it's not related to the
#' core purpose of purrr. You can pull your code out of a pipe and use regular
#' `if`/`else` statements instead.
#'
#' `when()` is a flavour of pattern matching (or an if-else abstraction) in
#' which a value is matched against a sequence of condition-action sets. When a
#' valid match/condition is found the action is executed and the result of the
#' action is returned.
#'
#' @param . the value to match against
#' @param ... formulas; each containing a condition as LHS and an action as RHS.
#' named arguments will define additional values.
#' @return The value resulting from the action of the first valid
#' match/condition is returned. If no matches are found, and no default is
#' given, NULL will be returned.
#'
# @details condition-action sets are written as formulas with conditions as
# left-hand sides and actions as right-hand sides. A formula with only a
# right-hand will be treated as a condition which is always satisfied. For
# such a default case one can also omit the `~` symbol, but note that its
# value will then be evaluated. Any named argument will be made available in
# all conditions and actions, which is useful in avoiding repeated temporary
# computations or temporary assignments.
#
#' Validity of the conditions are tested with `isTRUE`, or equivalently
#' with `identical(condition, TRUE)`.
#' In other words conditions resulting in more than one logical will never
#' be valid. Note that the input value is always treated as a single object,
#' as opposed to the `ifelse` function.
#'
#' @keywords internal
#' @examples
#' 1:10 |>
#' when(
#' sum(.) <= 50 ~ sum(.),
#' sum(.) <= 100 ~ sum(.)/2,
#' ~ 0
#' )
#'
#' # now
#' x <- 1:10
#' if (sum(x) < 10) {
#' sum(x)
#' } else if (sum(x) < 100) {
#' sum(x) / 2
#' } else {
#' 0
#' }
#' @export
when <- function(., ...) {
lifecycle::deprecate_warn("1.0.0", "when()", I("`if`"))
dots <- list(...)
names <- names(dots)
named <- if (is.null(names)) rep(FALSE, length(dots)) else names != ""
if (sum(!named) == 0) {
cli::cli_abort("At least one matching condition is needed.")
}
is_formula <-
vapply(dots, function(dot) identical(class(dot), "formula"), logical(1L))
env <- new.env(parent = parent.frame())
env[["."]] <- .
if (sum(named) > 0) {
for (i in which(named)) {
env[[names[i]]] <- dots[[i]]
}
}
result <- NULL
for (i in which(!named)) {
if (is_formula[i]) {
action <- length(dots[[i]])
if (action == 2 || is_true(eval(dots[[i]][[2]], env, env))) {
result <- eval(dots[[i]][[action]], env, env)
break
}
} else {
result <- dots[[i]]
}
}
result
}