Skip to content

Commit b754b8f

Browse files
author
Stefan Fleck
committed
refactoring
1 parent 8468a0a commit b754b8f

7 files changed

Lines changed: 127 additions & 76 deletions

File tree

DESCRIPTION

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,5 @@ License: MIT + file LICENSE
1010
Encoding: UTF-8
1111
LazyData: true
1212
Suggests:
13-
testthat,
14-
dplyr
13+
testthat
1514
RoxygenNote: 6.0.1

R/case_when.R

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,11 @@ case_when <- function(...) {
121121
inconsistent_lengths <- non_atomic_lengths[-1]
122122
lhs_problems <- lhs_lengths %in% inconsistent_lengths
123123
rhs_problems <- rhs_lengths %in% inconsistent_lengths
124-
problems <- lhs_problems | rhs_problems
124+
125+
125126
bad_calls(
126-
formulas[problems],
127-
check_length_val(inconsistent_lengths, m, header = NULL, .stop = identity)
127+
formulas[lhs_problems | rhs_problems],
128+
inconsistent_lengths_message(inconsistent_lengths, m)
128129
)
129130
}
130131
}

R/utils.R

Lines changed: 75 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
2-
31
backticks <- function (x){
42
paste0("`", x, "`")
53
}
@@ -41,34 +39,6 @@ fmt_calls <- function(...){
4139

4240

4341

44-
check_length_val <- function(
45-
length_x,
46-
n,
47-
header,
48-
reason = NULL,
49-
.stop = stop
50-
){
51-
if (all(length_x %in% c(1L, n)))
52-
return()
53-
54-
if (is.null(reason))
55-
reason <- ""
56-
else
57-
reason <- paste0(" (", reason, ")")
58-
59-
if (is.null(header))
60-
header <- ""
61-
else
62-
header <- paste0(header, " ")
63-
64-
65-
if (n == 1) {
66-
.stop(sprintf("%smust be length 1%s, not %s", header, reason, paste(length_x, collapse = ", ")))
67-
} else {
68-
.stop(sprintf("%smust be length %s%s or one, not %s", header, n, reason, paste(length_x, collapse = ", ")))
69-
}
70-
}
71-
7242

7343

7444

@@ -83,9 +53,9 @@ replace_with <- function (
8353
return(x)
8454
}
8555

86-
check_length(val, x, name, reason)
87-
check_type(val, x, name)
88-
check_class(val, x, name)
56+
assert_length_1_or_n(val, length(x), name, reason)
57+
assert_equal_type(val, x, name)
58+
assert_equal_class(val, x, name)
8959

9060
i[is.na(i)] <- FALSE
9161
if (length(val) == 1L) {
@@ -99,26 +69,13 @@ replace_with <- function (
9969

10070

10171

102-
check_length <- function (
103-
x,
104-
template,
105-
header,
106-
reason = NULL
107-
){
108-
check_length_val(length(x), length(template), header, reason)
109-
}
110-
111-
112-
113-
114-
check_type <- function(
72+
assert_equal_type <- function(
11573
x,
11674
template,
11775
header
11876
){
119-
if (identical(typeof(x), typeof(template))) {
120-
return()
121-
}
77+
if (identical(typeof(x), typeof(template)))
78+
return(TRUE)
12279

12380
if (is.null(header))
12481
header <- ""
@@ -131,16 +88,16 @@ check_type <- function(
13188

13289

13390

134-
check_class <- function(
91+
assert_equal_class <- function(
13592
x,
13693
template,
13794
header
13895
){
13996
if (!is.object(x)) {
140-
return()
97+
return(TRUE)
14198

14299
} else if (identical(class(x), class(template))) {
143-
return()
100+
return(TRUE)
144101

145102
} else {
146103

@@ -150,15 +107,77 @@ check_class <- function(
150107
header <- paste0(header, " ")
151108

152109

153-
stop(sprintf("%smust be type %s, not %s", header, typeof(template), typeof(x)))
110+
stop(
111+
sprintf(
112+
"%smust be %s, not %s",
113+
header,
114+
paste(class(template), collapse = "/"),
115+
paste(class(x), collapse = "/")
116+
)
117+
)
154118
}
155119
}
156120

157121

158122

159123

160-
fmt_classes <- function(
161-
x
124+
check_length_1_or_n <- function(
125+
x,
126+
n,
127+
header,
128+
reason
162129
){
163-
paste(class(x), collapse = "/")
130+
if (length(x) %in% c(1, n)){
131+
return(NULL)
132+
}
133+
134+
135+
if (is.null(reason))
136+
reason <- ""
137+
else
138+
reason <- paste0(" (", reason, ")")
139+
140+
if (is.null(header))
141+
header <- ""
142+
else
143+
header <- paste0(header, " ")
144+
145+
146+
inconsistent_lengths_message(length(x), n, header = header, reason = reason)
147+
}
148+
149+
150+
151+
152+
assert_length_1_or_n <- function(
153+
x,
154+
n,
155+
header,
156+
reason
157+
){
158+
chk <- check_length_1_or_n(x, n, header, reason)
159+
160+
if (is.null(chk)){
161+
TRUE
162+
} else {
163+
stop(chk)
164+
}
165+
}
166+
167+
168+
169+
170+
# messages ----------------------------------------------------------------
171+
172+
inconsistent_lengths_message <- function(
173+
length_is,
174+
length_should,
175+
header = "",
176+
reason = ""
177+
){
178+
if (length_should == 1) {
179+
sprintf("%smust be length 1%s, not %s", header, reason, paste(length_is, collapse = ", "))
180+
} else {
181+
sprintf("%smust be length %s%s or one, not %s", header, length_should, reason, paste(length_is, collapse = ", "))
182+
}
164183
}

README.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,33 @@
11
# lest
22

3-
[![lifecycle](https://img.shields.io/badge/lifecycle-maturing-blue.svg)](https://www.tidyverse.org/lifecycle/#maturing)
3+
[![lifecycle](https://img.shields.io/badge/lifecycle-stable-blue.svg)](https://www.tidyverse.org/lifecycle/#stable)
44

5-
Vectorised Conditionals Similar to SQL CASE WHEN, forked from dplyr but without
6-
any dependencies.
5+
lest contains forks of the dplyr functions `case_when()` and `if_else()`.
6+
`case_when()` enables you to vectorise multiple `if` and `else` statements
7+
(like the `CASE WHEN` statement in SQL). `if_else()` is a stricter and
8+
more predictable version of `base::ifelse()` that preverves attributes
9+
(and therefore works with Dates).
710

11+
**lest** depends only on base, and will never add any external dependencies.
812

9-
Relationship to dplyr::case_when()
13+
14+
15+
Why use lest?
1016
----------------------------------
1117

1218
Use this package if you like the semantics of `dplyr::case_when()`, but do not
13-
want to use dplyr. If you already use dplyr, it is not recommended to use
14-
**lest**. `lest::case_when()` and `lest::if_else()` behave exactly identical to
19+
want to use dplyr.
20+
**If you already use dplyr, it is not recommended to use lest**.
21+
`lest::case_when()` and `lest::if_else()` behave exactly identical to
1522
the dplyr equivalents, just that they do not support tidyeval syntax
1623
(like `!!!`).
1724

18-
The dplyr `suggests` in the package descriptions is just for unit tests.
1925

2026

2127
Installation
2228
------------
2329

24-
You can install dint from GitHub with:
30+
You can install lest from GitHub with:
2531

2632
``` r
2733
# install.packages("devtools")
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
test_that("case_when can be used in anonymous functions (#3422)", {
2+
res <- tibble::tibble(a = 1:3) %>%
3+
dplyr::mutate(b = (function(x) case_when(x < 2 ~ TRUE, TRUE ~ FALSE))(a)) %>%
4+
dplyr::pull()
5+
expect_equal(res, c(TRUE, FALSE, FALSE))
6+
})

tests/testthat/test_case_when.R

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
context("case_when")
22

3+
4+
5+
36
test_that("zero inputs throws an error", {
47
expect_error(
58
case_when(),
@@ -8,6 +11,9 @@ test_that("zero inputs throws an error", {
811
)
912
})
1013

14+
15+
16+
1117
test_that("error messages", {
1218
expect_error(
1319
case_when(
@@ -26,6 +32,9 @@ test_that("error messages", {
2632
)
2733
})
2834

35+
36+
37+
2938
test_that("cases must yield compatible lengths", {
3039
expect_error(
3140
case_when(
@@ -47,6 +56,9 @@ test_that("cases must yield compatible lengths", {
4756
)
4857
})
4958

59+
60+
61+
5062
test_that("matches values in order", {
5163
x <- 1:3
5264
expect_equal(
@@ -59,6 +71,9 @@ test_that("matches values in order", {
5971
)
6072
})
6173

74+
75+
76+
6277
test_that("unmatched gets missing value", {
6378
x <- 1:3
6479
expect_equal(
@@ -70,6 +85,9 @@ test_that("unmatched gets missing value", {
7085
)
7186
})
7287

88+
89+
90+
7391
test_that("missing values can be replaced (#1999)", {
7492
x <- c(1:3, NA)
7593
expect_equal(
@@ -82,6 +100,9 @@ test_that("missing values can be replaced (#1999)", {
82100
)
83101
})
84102

103+
104+
105+
85106
test_that("NA conditions (#2927)", {
86107
expect_equal(
87108
case_when(
@@ -92,6 +113,9 @@ test_that("NA conditions (#2927)", {
92113
)
93114
})
94115

116+
117+
118+
95119
test_that("atomic conditions (#2909)", {
96120
expect_equal(
97121
case_when(
@@ -109,6 +133,9 @@ test_that("atomic conditions (#2909)", {
109133
)
110134
})
111135

136+
137+
138+
112139
test_that("zero-length conditions and values (#3041)", {
113140
expect_equal(
114141
case_when(
@@ -125,10 +152,3 @@ test_that("zero-length conditions and values (#3041)", {
125152
numeric()
126153
)
127154
})
128-
129-
test_that("case_when can be used in anonymous functions (#3422)", {
130-
res <- tibble::tibble(a = 1:3) %>%
131-
dplyr::mutate(b = (function(x) case_when(x < 2 ~ TRUE, TRUE ~ FALSE))(a)) %>%
132-
dplyr::pull()
133-
expect_equal(res, c(TRUE, FALSE, FALSE))
134-
})

0 commit comments

Comments
 (0)