forked from hadley/adv-r
-
Notifications
You must be signed in to change notification settings - Fork 0
/
check.r
89 lines (74 loc) · 2.05 KB
/
check.r
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
# Tools for checking that a data structure is of the right form
# Basics:
# mode: character, numeric, integer, logical
# length: exactly, >, <
# identical, equal, equivalent
#
# Combining
# AND, OR, NOT
#
# Recursive
# contains
#
# Operators
# &, | (to replace and?or)
# Logic
# == (to replace check)
# Building a DSL:
# LENGTH() == 4, LENGTH() > 4, LENGTH() != 2
# LENGTH() %% 2 == 0
# PARTS(1, 3, 5) == c("A", "B", "C")
# PARTS() = rep(c(PATTERN("a", "b")))
# PARTS() = rep(c(PATTERN("a"), ANY()))
# MODE() == "character", IS_A(x, character)
# Exercises:
# * do a similar thing for regular expressions or xpath (small part of each)
new_check <- function(attr, subclass = NULL) {
structure(attr, class = c(subclass, "check"))
}
is.check <- function(x)
print.check <- function(x) cat(format(x), "\n")
length_equals <- function(n) {
new_check(list(n = n), "length_equal")
}
check.length_equal <- function(check, x) length(x) == check$n
format.length_equal <- function(check) paste("length(x) ==", check$n)
NOT <- function(check) {
stopifnot(is.check(check))
new_check(list(check = check), "NOT")
}
check.NOT <- function(check, x) !(check$check(x))
format.NOT <- function(check) {
paste("NOT: ", NextMethod())
}
length_between <- function(min = -Inf, max = Inf) {
new_check(list(min = min, max = max), "length_between")
}
check.length_between <- function(check, x) {
length(x) > check$min && length(x) < check$max
}
format.length_between <- function(check) {
paste("length(x) in [", check$min, ", ", check$max, "]", sep = "")
}
ANY <- function() {
new_check(list(), "any")
}
check.any <- function(check, x) TRUE
has_mode <- function()
# Either actual values or checks
# contains(ANY(), 1:4, AND(length_between(1, 10), is_character()))
contains <- function(...) {
elements <- list(...)
}
or <- function(a, b) {
list(
check = function(x) a$check(x) || b$check(x),
message = paste(a$name, "OR", b$name)
)
}
and <- function(a, b) {
list(
check = function(x) a$check(x) && b$check(x),
message = paste(a$name, "OR", b$name)
)
}