fear 0.9.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/workflows/rubocop.yml +39 -0
- data/.github/workflows/spec.yml +42 -0
- data/.gitignore +0 -1
- data/.rubocop.yml +4 -12
- data/.simplecov +17 -0
- data/CHANGELOG.md +40 -0
- data/Gemfile +5 -2
- data/Gemfile.lock +130 -0
- data/LICENSE.txt +1 -1
- data/README.md +1293 -97
- data/Rakefile +369 -1
- data/benchmarks/README.md +1 -0
- data/benchmarks/dry_do_vs_fear_for.txt +11 -0
- data/benchmarks/dry_some_fmap_vs_fear_some_map.txt +11 -0
- data/benchmarks/factorial.txt +16 -0
- data/benchmarks/fear_gaurd_and1_vs_new.txt +13 -0
- data/benchmarks/fear_gaurd_and2_vs_and.txt +13 -0
- data/benchmarks/fear_gaurd_and3_vs_and_and.txt +13 -0
- data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +11 -0
- data/benchmarks/fear_pattern_matching_construction_vs_execution.txt +13 -0
- data/benchmarks/pattern_matching_dry_vs_qo_vs_fear_try.txt +14 -0
- data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +11 -0
- data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +11 -0
- data/examples/pattern_extracting.rb +17 -0
- data/examples/pattern_extracting_ruby2.7.rb +15 -0
- data/examples/pattern_matching_binary_tree_set.rb +101 -0
- data/examples/pattern_matching_number_in_words.rb +60 -0
- data/fear.gemspec +34 -23
- data/lib/dry/types/fear.rb +8 -0
- data/lib/dry/types/fear/option.rb +125 -0
- data/lib/fear.rb +65 -15
- data/lib/fear/await.rb +33 -0
- data/lib/fear/awaitable.rb +28 -0
- data/lib/fear/either.rb +131 -71
- data/lib/fear/either_api.rb +23 -0
- data/lib/fear/either_pattern_match.rb +53 -0
- data/lib/fear/empty_partial_function.rb +38 -0
- data/lib/fear/extractor.rb +112 -0
- data/lib/fear/extractor/anonymous_array_splat_matcher.rb +10 -0
- data/lib/fear/extractor/any_matcher.rb +17 -0
- data/lib/fear/extractor/array_head_matcher.rb +36 -0
- data/lib/fear/extractor/array_matcher.rb +40 -0
- data/lib/fear/extractor/array_splat_matcher.rb +16 -0
- data/lib/fear/extractor/empty_list_matcher.rb +20 -0
- data/lib/fear/extractor/extractor_matcher.rb +44 -0
- data/lib/fear/extractor/grammar.rb +203 -0
- data/lib/fear/extractor/grammar.treetop +129 -0
- data/lib/fear/extractor/identifier_matcher.rb +18 -0
- data/lib/fear/extractor/matcher.rb +53 -0
- data/lib/fear/extractor/matcher/and.rb +38 -0
- data/lib/fear/extractor/named_array_splat_matcher.rb +17 -0
- data/lib/fear/extractor/pattern.rb +58 -0
- data/lib/fear/extractor/typed_identifier_matcher.rb +26 -0
- data/lib/fear/extractor/value_matcher.rb +19 -0
- data/lib/fear/extractor_api.rb +35 -0
- data/lib/fear/failure.rb +46 -14
- data/lib/fear/failure_pattern_match.rb +10 -0
- data/lib/fear/for.rb +37 -95
- data/lib/fear/for_api.rb +68 -0
- data/lib/fear/future.rb +497 -0
- data/lib/fear/future_api.rb +21 -0
- data/lib/fear/left.rb +19 -2
- data/lib/fear/left_pattern_match.rb +11 -0
- data/lib/fear/none.rb +67 -3
- data/lib/fear/none_pattern_match.rb +14 -0
- data/lib/fear/option.rb +120 -56
- data/lib/fear/option_api.rb +40 -0
- data/lib/fear/option_pattern_match.rb +48 -0
- data/lib/fear/partial_function.rb +176 -0
- data/lib/fear/partial_function/and_then.rb +50 -0
- data/lib/fear/partial_function/any.rb +28 -0
- data/lib/fear/partial_function/combined.rb +53 -0
- data/lib/fear/partial_function/empty.rb +10 -0
- data/lib/fear/partial_function/guard.rb +80 -0
- data/lib/fear/partial_function/guard/and.rb +38 -0
- data/lib/fear/partial_function/guard/and3.rb +41 -0
- data/lib/fear/partial_function/guard/or.rb +38 -0
- data/lib/fear/partial_function/lifted.rb +23 -0
- data/lib/fear/partial_function/or_else.rb +64 -0
- data/lib/fear/partial_function_class.rb +38 -0
- data/lib/fear/pattern_match.rb +114 -0
- data/lib/fear/pattern_matching_api.rb +137 -0
- data/lib/fear/promise.rb +95 -0
- data/lib/fear/right.rb +20 -2
- data/lib/fear/right_biased.rb +6 -14
- data/lib/fear/right_pattern_match.rb +11 -0
- data/lib/fear/some.rb +55 -3
- data/lib/fear/some_pattern_match.rb +13 -0
- data/lib/fear/struct.rb +248 -0
- data/lib/fear/success.rb +35 -5
- data/lib/fear/success_pattern_match.rb +12 -0
- data/lib/fear/try.rb +136 -79
- data/lib/fear/try_api.rb +33 -0
- data/lib/fear/try_pattern_match.rb +33 -0
- data/lib/fear/unit.rb +32 -0
- data/lib/fear/utils.rb +39 -14
- data/lib/fear/version.rb +4 -1
- data/spec/dry/types/fear/option/constrained_spec.rb +22 -0
- data/spec/dry/types/fear/option/core_spec.rb +77 -0
- data/spec/dry/types/fear/option/default_spec.rb +21 -0
- data/spec/dry/types/fear/option/hash_spec.rb +58 -0
- data/spec/dry/types/fear/option/option_spec.rb +97 -0
- data/spec/fear/awaitable_spec.rb +17 -0
- data/spec/fear/done_spec.rb +8 -6
- data/spec/fear/either/mixin_spec.rb +17 -0
- data/spec/fear/either_pattern_match_spec.rb +37 -0
- data/spec/fear/either_pattern_matching_spec.rb +28 -0
- data/spec/fear/extractor/array_matcher_spec.rb +230 -0
- data/spec/fear/extractor/extractor_matcher_spec.rb +153 -0
- data/spec/fear/extractor/grammar_array_spec.rb +25 -0
- data/spec/fear/extractor/identified_matcher_spec.rb +49 -0
- data/spec/fear/extractor/identifier_matcher_spec.rb +68 -0
- data/spec/fear/extractor/pattern_spec.rb +34 -0
- data/spec/fear/extractor/typed_identifier_matcher_spec.rb +64 -0
- data/spec/fear/extractor/value_matcher_number_spec.rb +79 -0
- data/spec/fear/extractor/value_matcher_string_spec.rb +88 -0
- data/spec/fear/extractor/value_matcher_symbol_spec.rb +71 -0
- data/spec/fear/extractor_api_spec.rb +115 -0
- data/spec/fear/extractor_spec.rb +61 -0
- data/spec/fear/failure_spec.rb +145 -45
- data/spec/fear/for_spec.rb +57 -67
- data/spec/fear/future_spec.rb +691 -0
- data/spec/fear/guard_spec.rb +103 -0
- data/spec/fear/left_spec.rb +112 -46
- data/spec/fear/none_spec.rb +114 -16
- data/spec/fear/option/mixin_spec.rb +39 -0
- data/spec/fear/option_pattern_match_spec.rb +35 -0
- data/spec/fear/option_pattern_matching_spec.rb +34 -0
- data/spec/fear/option_spec.rb +121 -8
- data/spec/fear/partial_function/empty_spec.rb +38 -0
- data/spec/fear/partial_function_and_then_spec.rb +147 -0
- data/spec/fear/partial_function_composition_spec.rb +82 -0
- data/spec/fear/partial_function_or_else_spec.rb +276 -0
- data/spec/fear/partial_function_spec.rb +239 -0
- data/spec/fear/pattern_match_spec.rb +93 -0
- data/spec/fear/pattern_matching_api_spec.rb +31 -0
- data/spec/fear/promise_spec.rb +96 -0
- data/spec/fear/right_biased/left.rb +29 -32
- data/spec/fear/right_biased/right.rb +51 -54
- data/spec/fear/right_spec.rb +109 -41
- data/spec/fear/some_spec.rb +80 -15
- data/spec/fear/success_spec.rb +99 -32
- data/spec/fear/try/mixin_spec.rb +19 -0
- data/spec/fear/try_pattern_match_spec.rb +37 -0
- data/spec/fear/try_pattern_matching_spec.rb +34 -0
- data/spec/fear/utils_spec.rb +16 -14
- data/spec/spec_helper.rb +13 -7
- data/spec/struct_pattern_matching_spec.rb +36 -0
- data/spec/struct_spec.rb +226 -0
- data/spec/support/dry_types.rb +6 -0
- metadata +320 -29
- data/.travis.yml +0 -9
- data/lib/fear/done.rb +0 -22
- data/lib/fear/for/evaluation_context.rb +0 -91
@@ -0,0 +1,276 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Fear::PartialFunction, "#or_else" do
|
4
|
+
subject(:first_or_else_second) { first.or_else(second) }
|
5
|
+
|
6
|
+
let(:first) { Fear.case(->(x) { x.even? }) { |x| "first: #{x}" } }
|
7
|
+
let(:second) { Fear.case(->(x) { x % 3 == 0 }) { |x| "second: #{x}" } }
|
8
|
+
|
9
|
+
describe "#defined_at?" do
|
10
|
+
context "first defined, second not" do
|
11
|
+
subject { first_or_else_second.defined_at?(4) }
|
12
|
+
|
13
|
+
it { is_expected.to eq(true) }
|
14
|
+
end
|
15
|
+
|
16
|
+
context "first not defined, second defined" do
|
17
|
+
subject { first_or_else_second.defined_at?(9) }
|
18
|
+
|
19
|
+
it { is_expected.to eq(true) }
|
20
|
+
end
|
21
|
+
|
22
|
+
context "first not defined, second not defined" do
|
23
|
+
subject { first_or_else_second.defined_at?(5) }
|
24
|
+
|
25
|
+
it { is_expected.to eq(false) }
|
26
|
+
end
|
27
|
+
|
28
|
+
context "first and second defined" do
|
29
|
+
subject { first_or_else_second.defined_at?(6) }
|
30
|
+
|
31
|
+
it { is_expected.to eq(true) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#call" do
|
36
|
+
context "first defined, second not" do
|
37
|
+
subject { first_or_else_second.(4) }
|
38
|
+
|
39
|
+
it { is_expected.to eq("first: 4") }
|
40
|
+
end
|
41
|
+
|
42
|
+
context "first not defined, second defined" do
|
43
|
+
subject { first_or_else_second.(9) }
|
44
|
+
|
45
|
+
it { is_expected.to eq("second: 9") }
|
46
|
+
end
|
47
|
+
|
48
|
+
context "first not defined, second not defined" do
|
49
|
+
subject { -> { first_or_else_second.(5) } }
|
50
|
+
|
51
|
+
it { is_expected.to raise_error(Fear::MatchError, "partial function not defined at: 5") }
|
52
|
+
end
|
53
|
+
|
54
|
+
context "first and second defined" do
|
55
|
+
subject { first_or_else_second.(6) }
|
56
|
+
|
57
|
+
it { is_expected.to eq("first: 6") }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "#call_or_else" do
|
62
|
+
let(:fallback) { ->(x) { "fallback: #{x}" } }
|
63
|
+
|
64
|
+
context "first defined, second not" do
|
65
|
+
subject { first_or_else_second.call_or_else(4, &fallback) }
|
66
|
+
|
67
|
+
it { is_expected.to eq("first: 4") }
|
68
|
+
end
|
69
|
+
|
70
|
+
context "first not defined, second defined" do
|
71
|
+
subject { first_or_else_second.call_or_else(9, &fallback) }
|
72
|
+
|
73
|
+
it { is_expected.to eq("second: 9") }
|
74
|
+
end
|
75
|
+
|
76
|
+
context "first not defined, second not defined" do
|
77
|
+
subject { first_or_else_second.call_or_else(5, &fallback) }
|
78
|
+
|
79
|
+
it { is_expected.to eq("fallback: 5") }
|
80
|
+
end
|
81
|
+
|
82
|
+
context "first and second defined" do
|
83
|
+
subject { first_or_else_second.call_or_else(6, &fallback) }
|
84
|
+
|
85
|
+
it { is_expected.to eq("first: 6") }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "#or_else" do
|
90
|
+
let(:first_or_else_second_or_else_third) { first_or_else_second.or_else(third) }
|
91
|
+
let(:third) { Fear.case(->(x) { x % 7 == 0 }) { |x| "third: #{x}" } }
|
92
|
+
|
93
|
+
describe "#defined_at?" do
|
94
|
+
context "first defined, second not" do
|
95
|
+
subject { first_or_else_second_or_else_third.defined_at?(4) }
|
96
|
+
|
97
|
+
it { is_expected.to eq(true) }
|
98
|
+
end
|
99
|
+
|
100
|
+
context "first not defined, second defined" do
|
101
|
+
subject { first_or_else_second_or_else_third.defined_at?(9) }
|
102
|
+
|
103
|
+
it { is_expected.to eq(true) }
|
104
|
+
end
|
105
|
+
|
106
|
+
context "first not defined, second not defined, third defined" do
|
107
|
+
subject { first_or_else_second_or_else_third.defined_at?(7) }
|
108
|
+
|
109
|
+
it { is_expected.to eq(true) }
|
110
|
+
end
|
111
|
+
|
112
|
+
context "first not defined, second not defined, third not defined" do
|
113
|
+
subject { first_or_else_second_or_else_third.defined_at?(1) }
|
114
|
+
|
115
|
+
it { is_expected.to eq(false) }
|
116
|
+
end
|
117
|
+
|
118
|
+
context "first, second and third defined" do
|
119
|
+
subject { first_or_else_second.defined_at?(42) }
|
120
|
+
|
121
|
+
it { is_expected.to eq(true) }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "#call" do
|
126
|
+
context "first defined, second not" do
|
127
|
+
subject { first_or_else_second_or_else_third.(4) }
|
128
|
+
|
129
|
+
it { is_expected.to eq("first: 4") }
|
130
|
+
end
|
131
|
+
|
132
|
+
context "first not defined, second defined" do
|
133
|
+
subject { first_or_else_second_or_else_third.(9) }
|
134
|
+
|
135
|
+
it { is_expected.to eq("second: 9") }
|
136
|
+
end
|
137
|
+
|
138
|
+
context "first not defined, second not defined, third defined" do
|
139
|
+
subject { first_or_else_second_or_else_third.(7) }
|
140
|
+
|
141
|
+
it { is_expected.to eq("third: 7") }
|
142
|
+
end
|
143
|
+
|
144
|
+
context "first not defined, second not defined, third not defined" do
|
145
|
+
subject { -> { first_or_else_second_or_else_third.(1) } }
|
146
|
+
|
147
|
+
it { is_expected.to raise_error(Fear::MatchError, "partial function not defined at: 1") }
|
148
|
+
end
|
149
|
+
|
150
|
+
context "first, second and third defined" do
|
151
|
+
subject { first_or_else_second.(42) }
|
152
|
+
|
153
|
+
it { is_expected.to eq("first: 42") }
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "#call_or_else" do
|
158
|
+
let(:fallback) { ->(x) { "fallback: #{x}" } }
|
159
|
+
|
160
|
+
context "first defined, second not" do
|
161
|
+
subject { first_or_else_second_or_else_third.call_or_else(4, &fallback) }
|
162
|
+
|
163
|
+
it { is_expected.to eq("first: 4") }
|
164
|
+
end
|
165
|
+
|
166
|
+
context "first not defined, second defined" do
|
167
|
+
subject { first_or_else_second_or_else_third.call_or_else(9, &fallback) }
|
168
|
+
|
169
|
+
it { is_expected.to eq("second: 9") }
|
170
|
+
end
|
171
|
+
|
172
|
+
context "first not defined, second not defined, third defined" do
|
173
|
+
subject { first_or_else_second_or_else_third.call_or_else(7, &fallback) }
|
174
|
+
|
175
|
+
it { is_expected.to eq("third: 7") }
|
176
|
+
end
|
177
|
+
|
178
|
+
context "first not defined, second not defined, third not defined" do
|
179
|
+
subject { first_or_else_second_or_else_third.call_or_else(1, &fallback) }
|
180
|
+
|
181
|
+
it { is_expected.to eq("fallback: 1") }
|
182
|
+
end
|
183
|
+
|
184
|
+
context "first, second and third defined" do
|
185
|
+
subject { first_or_else_second_or_else_third.call_or_else(42, &fallback) }
|
186
|
+
|
187
|
+
it { is_expected.to eq("first: 42") }
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe "#and_then" do
|
193
|
+
let(:first_or_else_second_and_then_function) { first_or_else_second.and_then(&function) }
|
194
|
+
let(:function) { ->(x) { "f: #{x}" } }
|
195
|
+
|
196
|
+
describe "#defined_at?" do
|
197
|
+
context "first defined, second not" do
|
198
|
+
subject { first_or_else_second_and_then_function.defined_at?(2) }
|
199
|
+
|
200
|
+
it { is_expected.to eq(true) }
|
201
|
+
end
|
202
|
+
|
203
|
+
context "first not defined, second defined" do
|
204
|
+
subject { first_or_else_second_and_then_function.defined_at?(3) }
|
205
|
+
|
206
|
+
it { is_expected.to eq(true) }
|
207
|
+
end
|
208
|
+
|
209
|
+
context "first not defined, second not defined" do
|
210
|
+
subject { first_or_else_second_and_then_function.defined_at?(5) }
|
211
|
+
|
212
|
+
it { is_expected.to eq(false) }
|
213
|
+
end
|
214
|
+
|
215
|
+
context "first defined, second defined" do
|
216
|
+
subject { first_or_else_second_and_then_function.defined_at?(6) }
|
217
|
+
|
218
|
+
it { is_expected.to eq(true) }
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe "#call" do
|
223
|
+
context "first defined, second not" do
|
224
|
+
subject { first_or_else_second_and_then_function.(2) }
|
225
|
+
|
226
|
+
it { is_expected.to eq("f: first: 2") }
|
227
|
+
end
|
228
|
+
|
229
|
+
context "first not defined, second defined" do
|
230
|
+
subject { first_or_else_second_and_then_function.(3) }
|
231
|
+
|
232
|
+
it { is_expected.to eq("f: second: 3") }
|
233
|
+
end
|
234
|
+
|
235
|
+
context "first not defined, second not defined" do
|
236
|
+
subject { -> { first_or_else_second_and_then_function.(5) } }
|
237
|
+
|
238
|
+
it { is_expected.to raise_error(Fear::MatchError, "partial function not defined at: 5") }
|
239
|
+
end
|
240
|
+
|
241
|
+
context "first defined, second defined" do
|
242
|
+
subject { first_or_else_second_and_then_function.(6) }
|
243
|
+
|
244
|
+
it { is_expected.to eq("f: first: 6") }
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
describe "#call_or_else" do
|
249
|
+
let(:fallback) { ->(x) { "fallback: #{x}" } }
|
250
|
+
|
251
|
+
context "first defined, second not" do
|
252
|
+
subject { first_or_else_second_and_then_function.call_or_else(2, &fallback) }
|
253
|
+
|
254
|
+
it { is_expected.to eq("f: first: 2") }
|
255
|
+
end
|
256
|
+
|
257
|
+
context "first not defined, second defined" do
|
258
|
+
subject { first_or_else_second_and_then_function.call_or_else(3, &fallback) }
|
259
|
+
|
260
|
+
it { is_expected.to eq("f: second: 3") }
|
261
|
+
end
|
262
|
+
|
263
|
+
context "first not defined, second not defined" do
|
264
|
+
subject { first_or_else_second_and_then_function.call_or_else(5, &fallback) }
|
265
|
+
|
266
|
+
it { is_expected.to eq("fallback: 5") }
|
267
|
+
end
|
268
|
+
|
269
|
+
context "first defined, second defined" do
|
270
|
+
subject { first_or_else_second_and_then_function.call_or_else(6, &fallback) }
|
271
|
+
|
272
|
+
it { is_expected.to eq("f: first: 6") }
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Fear::PartialFunction do
|
4
|
+
describe "Fear.case()" do
|
5
|
+
context "condition is extractor" do
|
6
|
+
subject do
|
7
|
+
Fear.xcase("[1, [2, second_of_second, *], 3, *rest]") do |second_of_second:, rest:|
|
8
|
+
[second_of_second, rest]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it { is_expected.to be_defined_at([1, [2, 2, 3, 4], 3, 6, 7]) }
|
13
|
+
it { is_expected.not_to be_defined_at([1, [1, 3, 3, 4], 3, 6, 7]) }
|
14
|
+
it { is_expected.not_to be_defined_at([1, [1, 2, 3, 4], 4, 6, 7]) }
|
15
|
+
end
|
16
|
+
|
17
|
+
context "condition as symbol" do
|
18
|
+
subject { Fear.case(:even?) { |x| x } }
|
19
|
+
|
20
|
+
it "matches against the same symbol" do
|
21
|
+
is_expected.to be_defined_at(:even?)
|
22
|
+
is_expected.not_to be_defined_at(3)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "condition as Class" do
|
27
|
+
subject { Fear.case(Integer) { |x| x } }
|
28
|
+
|
29
|
+
it do
|
30
|
+
is_expected.to be_defined_at(4)
|
31
|
+
is_expected.not_to be_defined_at("3")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "condition as Proc" do
|
36
|
+
subject { Fear.case(->(x) { x.even? }) { |x| x } }
|
37
|
+
|
38
|
+
it do
|
39
|
+
is_expected.to be_defined_at(4)
|
40
|
+
is_expected.not_to be_defined_at(3)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "multiple condition" do
|
45
|
+
subject { Fear.case(Integer, :even?.to_proc, ->(x) { x % 3 == 0 }) { |x| x } }
|
46
|
+
|
47
|
+
it do
|
48
|
+
is_expected.to be_defined_at(12)
|
49
|
+
is_expected.not_to be_defined_at(12.0)
|
50
|
+
is_expected.not_to be_defined_at("3")
|
51
|
+
is_expected.not_to be_defined_at(3)
|
52
|
+
is_expected.not_to be_defined_at(4)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "multiple condition 2" do
|
57
|
+
subject { Fear.case(Integer, 4) { |x| x } }
|
58
|
+
|
59
|
+
it do
|
60
|
+
is_expected.to be_defined_at(4)
|
61
|
+
is_expected.not_to be_defined_at(3)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe ".or" do
|
67
|
+
subject { described_class.or(guard_1, guard_2, &Fear::Utils::IDENTITY) }
|
68
|
+
|
69
|
+
let(:guard_1) { ->(x) { x == 42 } }
|
70
|
+
let(:guard_2) { ->(x) { x == 21 } }
|
71
|
+
|
72
|
+
it { is_expected.to be_defined_at(42) }
|
73
|
+
it { is_expected.to be_defined_at(21) }
|
74
|
+
it { is_expected.not_to be_defined_at(20) }
|
75
|
+
end
|
76
|
+
|
77
|
+
describe ".and" do
|
78
|
+
subject { described_class.and(guard_1, guard_2, &Fear::Utils::IDENTITY) }
|
79
|
+
|
80
|
+
let(:guard_1) { ->(x) { x % 5 == 0 } }
|
81
|
+
let(:guard_2) { ->(x) { x % 2 == 0 } }
|
82
|
+
|
83
|
+
it { is_expected.to be_defined_at(10) }
|
84
|
+
it { is_expected.not_to be_defined_at(5) }
|
85
|
+
it { is_expected.not_to be_defined_at(2) }
|
86
|
+
it { is_expected.not_to be_defined_at(3) }
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "#lift" do
|
90
|
+
let(:lifted) { partial_function.lift }
|
91
|
+
|
92
|
+
let(:partial_function) { Fear.case(->(v) { v != 0 }) { |x| 4 / x } }
|
93
|
+
|
94
|
+
context "defined" do
|
95
|
+
subject { lifted.(2) }
|
96
|
+
|
97
|
+
it { is_expected.to eq(Fear::Some.new(2)) }
|
98
|
+
end
|
99
|
+
|
100
|
+
context "not defined" do
|
101
|
+
subject { lifted.(0) }
|
102
|
+
|
103
|
+
it { is_expected.to eq(Fear::None) }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#defined_at?" do
|
108
|
+
let(:partial_function) { Fear.case(->(v) { v == 42 }) {} }
|
109
|
+
|
110
|
+
it "defined at" do
|
111
|
+
expect(partial_function.defined_at?(42)).to eq(true)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "not defined at" do
|
115
|
+
expect(partial_function.defined_at?(24)).to eq(false)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "#call" do
|
120
|
+
let(:partial_function) { Fear.case(->(v) { v != 0 }) { |x| 4 / x } }
|
121
|
+
|
122
|
+
context "defined" do
|
123
|
+
subject { partial_function.(2) }
|
124
|
+
|
125
|
+
it { is_expected.to eq(2) }
|
126
|
+
end
|
127
|
+
|
128
|
+
context "not defined" do
|
129
|
+
subject { -> { partial_function.(0) } }
|
130
|
+
|
131
|
+
it { is_expected.to raise_error(Fear::MatchError, "partial function not defined at: 0") }
|
132
|
+
end
|
133
|
+
|
134
|
+
context "defined and condition is extractor" do
|
135
|
+
subject { partial_function.([1, 2, 3, 4, 5]) }
|
136
|
+
|
137
|
+
let(:partial_function) do
|
138
|
+
Fear.xcase("[1, second, 3, *rest]") { |second:, rest:| [second, rest] }
|
139
|
+
end
|
140
|
+
|
141
|
+
it { is_expected.to eq([2, [4, 5]]) }
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "#to_proc", "#call" do
|
146
|
+
let(:partial_function) { Fear.case(->(v) { v != 0 }) { |x| 4 / x }.to_proc }
|
147
|
+
|
148
|
+
context "defined" do
|
149
|
+
subject { partial_function.(2) }
|
150
|
+
|
151
|
+
it { is_expected.to eq(2) }
|
152
|
+
end
|
153
|
+
|
154
|
+
context "not defined" do
|
155
|
+
subject { -> { partial_function.(0) } }
|
156
|
+
|
157
|
+
it { is_expected.to raise_error(Fear::MatchError, "partial function not defined at: 0") }
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "#call_or_else" do
|
162
|
+
let(:default) { ->(x) { "division by #{x} impossible" } }
|
163
|
+
let(:partial_function) { Fear.case(->(x) { x != 0 }) { |x| 4 / x } }
|
164
|
+
|
165
|
+
context "defined" do
|
166
|
+
subject { partial_function.call_or_else(2, &default) }
|
167
|
+
|
168
|
+
it { is_expected.to eq(2) }
|
169
|
+
end
|
170
|
+
|
171
|
+
context "not defined" do
|
172
|
+
subject { partial_function.call_or_else(0, &default) }
|
173
|
+
|
174
|
+
it { is_expected.to eq("division by 0 impossible") }
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe "#and_then" do
|
179
|
+
let(:partial_function) { Fear.case(->(v) { v == 42 }) {} }
|
180
|
+
let(:and_then) { ->(x) { x } }
|
181
|
+
|
182
|
+
context "block given, arguments not given" do
|
183
|
+
subject { -> { partial_function.and_then(&and_then) } }
|
184
|
+
|
185
|
+
it { is_expected.not_to raise_error }
|
186
|
+
end
|
187
|
+
|
188
|
+
context "block given, argument given" do
|
189
|
+
subject { -> { partial_function.and_then(and_then, &and_then) } }
|
190
|
+
|
191
|
+
it { is_expected.to raise_error(ArgumentError) }
|
192
|
+
end
|
193
|
+
|
194
|
+
context "block given, arguments given" do
|
195
|
+
subject { -> { partial_function.and_then(and_then, 42, &and_then) } }
|
196
|
+
|
197
|
+
it { is_expected.to raise_error(ArgumentError) }
|
198
|
+
end
|
199
|
+
|
200
|
+
context "block not given, arguments not given" do
|
201
|
+
subject { -> { partial_function.and_then } }
|
202
|
+
|
203
|
+
it { is_expected.to raise_error(ArgumentError) }
|
204
|
+
end
|
205
|
+
|
206
|
+
context "block net given, arguments given" do
|
207
|
+
subject { -> { partial_function.and_then(and_then) } }
|
208
|
+
|
209
|
+
it { is_expected.not_to raise_error }
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
shared_examples "#or_else" do |method_name|
|
214
|
+
subject { is_even.__send__(method_name, is_odd).(value) }
|
215
|
+
|
216
|
+
let(:is_even) { Fear.case(:even?.to_proc) { |x| "#{x} is even" } }
|
217
|
+
let(:is_odd) { Fear.case(:odd?.to_proc) { |x| "#{x} is odd" } }
|
218
|
+
|
219
|
+
context "when left side is defined" do
|
220
|
+
let(:value) { 42 }
|
221
|
+
|
222
|
+
it { is_expected.to eq("42 is even") }
|
223
|
+
end
|
224
|
+
|
225
|
+
context "when left side is not defined" do
|
226
|
+
let(:value) { 21 }
|
227
|
+
|
228
|
+
it { is_expected.to eq("21 is odd") }
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "#or_else" do
|
233
|
+
include_examples "#or_else", :or_else
|
234
|
+
end
|
235
|
+
|
236
|
+
describe "#|" do
|
237
|
+
include_examples "#or_else", :|
|
238
|
+
end
|
239
|
+
end
|