-
Notifications
You must be signed in to change notification settings - Fork 0
/
Scratchpad.java
143 lines (118 loc) · 4.31 KB
/
Scratchpad.java
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class Scratchpad {
@FunctionalInterface
public interface Predicate<T> {
boolean apply(T t);
}
@FunctionalInterface
public interface Validator<T, R> {
Optional<R> apply(T t);
}
@FunctionalInterface
public interface Check<T, R> {
ValidationResult<T, R> conform(T t);
}
public record ErrorTemplate(String id, String messageFmt) {};
public sealed interface ValidationResult<T, R> {
default boolean isValid() { return false; }
default boolean isInvalid() { return true; }
}
public record ValidationError<T, R>(List<String> id, T validated) implements ValidationResult<T, R> {};
public record ValidationSucess<T, R>(T t) implements ValidationResult<T, R> {
@Override
public boolean isValid() { return true; }
@Override
public boolean isInvalid() { return false; }
};
public static <T> Spec<T, T> spec(Predicate<T> predicate, String description) {
return new Single<>(
validator(predicate),
description,
new ErrorTemplate(predicate.toString(), "messageFmt"));
}
@SafeVarargs
public static <T, R> Spec<T, R> and(Spec<T, R>... specs) {
return new And<>(Arrays.asList(specs));
}
public static class And<T, R> implements Spec<T, R> {
public final String description;
public final List<Spec<T, R>> specs;
public And(List<Spec<T, R>> specs) {
this.specs = specs;
this.description = "And";
}
@Override
public Optional<R> apply(T t) {
return recurApply(specs, Optional.empty(), t);
}
private static <T, R> Optional<R> recurApply(List<Spec<T, R>> specs, Optional<R> r, T t) {
if (specs.size() <1 ) { return r; }
Spec<T, R> curr = specs.get(0);
Optional<R> newR = curr.apply(t);
if (!newR.isPresent()) {
return Optional.empty();
}
return recurApply(specs.subList(1, specs.size()), newR, t);
}
@Override
public ValidationResult<T, R> conform(T t) {
return this.apply(t).isPresent()
? new ValidationSucess<T, R>(t)
: new ValidationError<T, R>(
Arrays.asList(this.toString()), t);
}
@Override
public String description() {
return this.description;
}
}
public static interface Spec<T, R> extends Validator<T, R>, Check<T, R> {
String description();
}
public static class Single<T, R> implements Spec<T, R> {
public final Validator<T, R> validator;
public final String description;
public final ErrorTemplate errTmpl;
public Single(Validator<T, R> validator, String description, ErrorTemplate errTmpl) {
this.validator = validator;
this.description = description;
this.errTmpl = errTmpl;
}
@Override
public Optional<R> apply(T t) { return this.validator.apply(t); }
@Override
public ValidationResult<T, R> conform(T t) {
return this.validator.apply(t).isPresent()
? new ValidationSucess<T, R>(t)
: new ValidationError<T, R>(
Arrays.asList(this.errTmpl.id), t);
}
@Override
public String description() {
return this.description;
}
}
public static <T> Validator<T, T> validator(Predicate<T> predicate) {
return t -> predicate.apply(t) ? Optional.of(t) : Optional.empty();
}
public static <T> Optional<T> validate(Predicate<T> predicate, T t) {
return validator(predicate).apply(t);
}
public static <T, R> ValidationResult<T, R> conform(Spec<T, R> spec, T t) {
return spec.conform(t);
}
public static <T, R> String doc(Spec<T, R> spec) {
return spec.description();
}
public static Predicate<Integer> gt(int n) {
return v -> v > n;
}
public static boolean isString(Object o) {
return o instanceof String;
}
public static void main(String[] args) {
Scratchpad.spec(Scratchpad.gt(0), "The value should be greater than 0");
}
}