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,691 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Fear::Future do
|
4
|
+
context "#on_complete" do
|
5
|
+
it "run callback with value" do
|
6
|
+
expect do |callback|
|
7
|
+
Fear::Future.successful(5).on_complete(&callback)
|
8
|
+
end.to yield_with_args(Fear.success(5))
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:error) { StandardError.new }
|
12
|
+
|
13
|
+
it "run callback with error" do
|
14
|
+
expect do |callback|
|
15
|
+
Fear::Future.failed(error).on_complete(&callback)
|
16
|
+
end.to yield_with_args(Fear.failure(error))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "#on_complete_match" do
|
21
|
+
context "successful covered" do
|
22
|
+
subject do
|
23
|
+
proc do |callback|
|
24
|
+
Fear::Future.successful(5).on_complete_match do |m|
|
25
|
+
m.success(&callback)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it { is_expected.to yield_with_args(5) }
|
31
|
+
end
|
32
|
+
|
33
|
+
context "successful not covered" do
|
34
|
+
subject do
|
35
|
+
proc do |callback|
|
36
|
+
Fear::Future.successful(5).on_complete_match do |m|
|
37
|
+
m.failure(&callback)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it { is_expected.not_to yield_control }
|
43
|
+
end
|
44
|
+
|
45
|
+
context "failed" do
|
46
|
+
subject do
|
47
|
+
proc do |callback|
|
48
|
+
Fear::Future.failed(error).on_complete_match do |m|
|
49
|
+
m.failure(&callback)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
let(:error) { StandardError.new }
|
54
|
+
|
55
|
+
it { is_expected.to yield_with_args(error) }
|
56
|
+
end
|
57
|
+
|
58
|
+
context "failed not covered" do
|
59
|
+
subject do
|
60
|
+
proc do |callback|
|
61
|
+
Fear::Future.failed(error).on_complete_match do |m|
|
62
|
+
m.success(&callback)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
let(:error) { StandardError.new }
|
67
|
+
|
68
|
+
it { is_expected.not_to yield_control }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
shared_examples :on_success do |method_name|
|
73
|
+
context "##{method_name}" do
|
74
|
+
context "successful" do
|
75
|
+
subject do
|
76
|
+
proc do |callback|
|
77
|
+
Fear::Future.successful(5).__send__(method_name, &callback)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
it { is_expected.to yield_with_args(5) }
|
82
|
+
end
|
83
|
+
|
84
|
+
context "failed" do
|
85
|
+
subject do
|
86
|
+
proc do |callback|
|
87
|
+
Fear::Future.failed(StandardError.new).__send__(method_name, &callback)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it { is_expected.not_to yield_control }
|
92
|
+
end
|
93
|
+
|
94
|
+
specify "call all registered callbacks" do
|
95
|
+
expect do |second|
|
96
|
+
expect do |first|
|
97
|
+
Fear::Future.successful(5)
|
98
|
+
.__send__(method_name, &first)
|
99
|
+
.__send__(method_name, &second)
|
100
|
+
end.to yield_with_args(5)
|
101
|
+
end.to yield_with_args(5)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
include_examples :on_success, :on_success
|
107
|
+
include_examples :on_success, :each
|
108
|
+
|
109
|
+
context "#on_success_match" do
|
110
|
+
context "successful covered" do
|
111
|
+
subject do
|
112
|
+
proc do |callback|
|
113
|
+
Fear::Future.successful(5).on_success_match do |m|
|
114
|
+
m.case(5, &callback)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it { is_expected.to yield_with_args(5) }
|
120
|
+
end
|
121
|
+
|
122
|
+
context "successful not covered" do
|
123
|
+
subject do
|
124
|
+
proc do |callback|
|
125
|
+
Fear::Future.successful(5).on_success_match do |m|
|
126
|
+
m.case(0, &callback)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
it { is_expected.not_to yield_control }
|
132
|
+
end
|
133
|
+
|
134
|
+
context "failed" do
|
135
|
+
subject do
|
136
|
+
proc do |callback|
|
137
|
+
Fear::Future.failed(StandardError.new).on_success_match(&callback)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
it { is_expected.not_to yield_control }
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context "#on_failure" do
|
146
|
+
let(:error) { StandardError.new }
|
147
|
+
|
148
|
+
it "do not run callback if no error" do
|
149
|
+
expect do |callback|
|
150
|
+
Fear::Future.successful(5).on_failure(&callback)
|
151
|
+
end.not_to yield_with_args
|
152
|
+
end
|
153
|
+
|
154
|
+
it "run callback if error occurred" do
|
155
|
+
expect do |callback|
|
156
|
+
Fear::Future.failed(error).on_failure(&callback)
|
157
|
+
end.to yield_with_args(error)
|
158
|
+
end
|
159
|
+
|
160
|
+
specify "call all registered callbacks" do
|
161
|
+
expect do |second|
|
162
|
+
expect do |first|
|
163
|
+
Fear::Future.failed(error)
|
164
|
+
.on_failure(&first)
|
165
|
+
.on_failure(&second)
|
166
|
+
end.to yield_with_args(error)
|
167
|
+
end.to yield_with_args(error)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context "#on_failure_match" do
|
172
|
+
context "failure covered" do
|
173
|
+
subject do
|
174
|
+
proc do |callback|
|
175
|
+
Fear::Future.failed(error).on_failure_match do |m|
|
176
|
+
m.case(StandardError, &callback)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
let(:error) { StandardError.new }
|
181
|
+
|
182
|
+
it { is_expected.to yield_with_args(error) }
|
183
|
+
end
|
184
|
+
|
185
|
+
context "failure not covered" do
|
186
|
+
subject do
|
187
|
+
proc do |callback|
|
188
|
+
Fear::Future.failed(error).on_failure_match do |m|
|
189
|
+
m.case(RuntimeError, &callback)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
let(:error) { StandardError.new }
|
194
|
+
|
195
|
+
it { is_expected.not_to yield_control }
|
196
|
+
end
|
197
|
+
|
198
|
+
context "successful" do
|
199
|
+
subject do
|
200
|
+
proc do |callback|
|
201
|
+
Fear::Future.successful(5).on_failure_match(&callback)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
it { is_expected.not_to yield_control }
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
context "#completed?" do
|
210
|
+
context "not completed" do
|
211
|
+
subject do
|
212
|
+
Fear.future do
|
213
|
+
sleep 0.1
|
214
|
+
value
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
it { is_expected.not_to be_completed }
|
219
|
+
end
|
220
|
+
|
221
|
+
context "completed with error" do
|
222
|
+
subject { Fear::Await.ready(Fear.future { raise StandardError }, 1) }
|
223
|
+
|
224
|
+
it { is_expected.to be_completed }
|
225
|
+
end
|
226
|
+
|
227
|
+
context "completed with value" do
|
228
|
+
subject { Fear::Await.ready(Fear.future { 5 }, 0.5) }
|
229
|
+
|
230
|
+
it { is_expected.to be_completed }
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
context "#value" do
|
235
|
+
subject { future.value }
|
236
|
+
|
237
|
+
context "future returns nil" do
|
238
|
+
let(:future) { Fear::Future.successful(nil) }
|
239
|
+
|
240
|
+
it { is_expected.to eq(Fear.some(Fear.success(nil))) }
|
241
|
+
end
|
242
|
+
|
243
|
+
context "not completed" do
|
244
|
+
let(:future) do
|
245
|
+
Fear.future do
|
246
|
+
sleep 0.1
|
247
|
+
value
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
it { is_expected.to eq(Fear.none) }
|
252
|
+
end
|
253
|
+
|
254
|
+
context "completed with success" do
|
255
|
+
let(:future) { Fear::Future.successful(5) }
|
256
|
+
|
257
|
+
it { is_expected.to eq(Fear.some(Fear.success(5))) }
|
258
|
+
end
|
259
|
+
|
260
|
+
context "completed with failure" do
|
261
|
+
let(:future) { Fear::Future.failed(error) }
|
262
|
+
let(:error) { StandardError.new }
|
263
|
+
|
264
|
+
it { is_expected.to eq(Fear.some(Fear.failure(error))) }
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
context "#transform" do
|
269
|
+
context "successful" do
|
270
|
+
subject { Fear::Await.result(future, 1) }
|
271
|
+
|
272
|
+
let(:future) { Fear.future { 2 }.transform(->(v) { v * 2 }, :itself.to_proc) }
|
273
|
+
|
274
|
+
it { is_expected.to eq(Fear.success(4)) }
|
275
|
+
end
|
276
|
+
|
277
|
+
context "failed" do
|
278
|
+
subject { Fear::Await.result(future, 1) }
|
279
|
+
|
280
|
+
let(:future) { Fear.future { raise error }.transform(:itself.to_proc, :message.to_proc) }
|
281
|
+
let!(:error) { StandardError.new("fooo") }
|
282
|
+
|
283
|
+
it { is_expected.to eq(Fear.failure("fooo")) }
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
context "#map" do
|
288
|
+
subject { Fear::Await.result(future.map { |x| x * 2 }, 1) }
|
289
|
+
|
290
|
+
context "successful" do
|
291
|
+
let(:future) { Fear.future { 5 } }
|
292
|
+
|
293
|
+
it { is_expected.to eq(Fear.success(10)) }
|
294
|
+
end
|
295
|
+
|
296
|
+
context "failed" do
|
297
|
+
let(:future) { Fear.future { raise error } }
|
298
|
+
let!(:error) { StandardError.new("foo") }
|
299
|
+
|
300
|
+
it { is_expected.to eq(Fear.failure(error)) }
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
context "#flat_map" do
|
305
|
+
subject { Fear::Await.result(future, 1) }
|
306
|
+
|
307
|
+
context "successful" do
|
308
|
+
let(:future) { Fear.future { 5 }.flat_map { |r| Fear.future { r * 2 } } }
|
309
|
+
|
310
|
+
it { is_expected.to eq(Fear.success(10)) }
|
311
|
+
end
|
312
|
+
|
313
|
+
context "failed" do
|
314
|
+
let(:future) { Fear.future { raise error }.flat_map { |r| Fear.future { r * 2 } } }
|
315
|
+
let!(:error) { StandardError.new("foo") }
|
316
|
+
|
317
|
+
it { is_expected.to eq(Fear.failure(error)) }
|
318
|
+
end
|
319
|
+
|
320
|
+
context "failed callback future" do
|
321
|
+
let(:future) { Fear.future { 5 }.flat_map { Fear.future { raise error } } }
|
322
|
+
let!(:error) { StandardError.new("foo") }
|
323
|
+
|
324
|
+
it { is_expected.to eq(Fear.failure(error)) }
|
325
|
+
end
|
326
|
+
|
327
|
+
context "failed callback" do
|
328
|
+
let(:future) { Fear.future { 5 }.flat_map { raise error } }
|
329
|
+
let!(:error) { StandardError.new("foo") }
|
330
|
+
|
331
|
+
it { is_expected.to eq(Fear.failure(error)) }
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
context "#select" do
|
336
|
+
context "successful and satisfies predicate" do
|
337
|
+
subject { Fear::Await.result(future, 1) }
|
338
|
+
|
339
|
+
let(:future) { Fear.future { 2 }.select(&:even?) }
|
340
|
+
|
341
|
+
it { is_expected.to eq(Fear.success(2)) }
|
342
|
+
end
|
343
|
+
|
344
|
+
context "successful and does not satisfy predicate" do
|
345
|
+
subject { Fear::Await.result(future, 1).exception }
|
346
|
+
|
347
|
+
let(:future) { Fear.future { 3 }.select(&:even?) }
|
348
|
+
|
349
|
+
it { is_expected.to be_kind_of(Fear::NoSuchElementError) }
|
350
|
+
end
|
351
|
+
|
352
|
+
context "failure" do
|
353
|
+
subject { Fear::Await.result(future, 1).exception }
|
354
|
+
|
355
|
+
let(:future) { Fear.future { raise error }.select(&:even?) }
|
356
|
+
let!(:error) { StandardError.new }
|
357
|
+
|
358
|
+
it { is_expected.to eq(error) }
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
context "#recover" do
|
363
|
+
subject { Fear::Await.result(future, 1) }
|
364
|
+
|
365
|
+
context "successful" do
|
366
|
+
let(:future) do
|
367
|
+
Fear.future { 2 }.recover do |m|
|
368
|
+
m.case { 0 }
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
it { is_expected.to eq(Fear.success(2)) }
|
373
|
+
end
|
374
|
+
|
375
|
+
context "failure and managed to recover" do
|
376
|
+
let(:future) do
|
377
|
+
Fear.future { 2 / 0 }.recover do |m|
|
378
|
+
m.case(RuntimeError, &:message)
|
379
|
+
m.case(ZeroDivisionError) { Float::INFINITY }
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
it { is_expected.to eq(Fear.success(Float::INFINITY)) }
|
384
|
+
end
|
385
|
+
|
386
|
+
context "failure and error case not covered by pattern match" do
|
387
|
+
let(:future) do
|
388
|
+
Fear.future { 2 / 0 }.recover do |m|
|
389
|
+
m.case(RuntimeError, &:message)
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
it { is_expected.to match(Fear.failure(be_kind_of(ZeroDivisionError))) }
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
context "#zip" do
|
398
|
+
subject { Fear::Await.result(future, 1) }
|
399
|
+
|
400
|
+
context "successful" do
|
401
|
+
let!(:this) { Fear.future { 1 } }
|
402
|
+
let!(:that) { Fear.future { 2 } }
|
403
|
+
|
404
|
+
context "without a block" do
|
405
|
+
let(:future) { this.zip(that) }
|
406
|
+
|
407
|
+
it { is_expected.to eq(Fear.success([1, 2])) }
|
408
|
+
end
|
409
|
+
|
410
|
+
context "with a block" do
|
411
|
+
let(:future) { this.zip(that) { |x, y| x + y } }
|
412
|
+
|
413
|
+
it { is_expected.to eq(Fear.success(3)) }
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
context "first failed" do
|
418
|
+
let(:future) { this.zip(that) }
|
419
|
+
let!(:error) { StandardError.new }
|
420
|
+
let!(:this) { Fear.future { raise error } }
|
421
|
+
let!(:that) { Fear.future { 2 } }
|
422
|
+
|
423
|
+
it { is_expected.to eq(Fear.failure(error)) }
|
424
|
+
end
|
425
|
+
|
426
|
+
context "second failed" do
|
427
|
+
let(:future) { this.zip(that) }
|
428
|
+
let!(:error) { StandardError.new }
|
429
|
+
let!(:this) { Fear.future { 1 } }
|
430
|
+
let!(:that) { Fear.future { raise error } }
|
431
|
+
|
432
|
+
it { is_expected.to eq(Fear.failure(error)) }
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
context "#fallback_to" do
|
437
|
+
subject { Fear::Await.result(future, 1) }
|
438
|
+
|
439
|
+
context "successful" do
|
440
|
+
let(:future) { Fear.future { 2 }.fallback_to(fallback) }
|
441
|
+
let!(:fallback) { Fear.future { 42 } }
|
442
|
+
|
443
|
+
it { is_expected.to eq(Fear.success(2)) }
|
444
|
+
end
|
445
|
+
|
446
|
+
context "failed" do
|
447
|
+
let(:future) { Fear.future { raise error }.fallback_to(fallback) }
|
448
|
+
let!(:fallback) { Fear.future { 42 } }
|
449
|
+
let!(:error) { StandardError.new }
|
450
|
+
|
451
|
+
it { is_expected.to eq(Fear.success(42)) }
|
452
|
+
end
|
453
|
+
|
454
|
+
context "fallback failed" do
|
455
|
+
let(:future) { Fear.future { raise error }.fallback_to(fallback) }
|
456
|
+
let!(:fallback) { Fear.future { raise } }
|
457
|
+
let!(:error) { StandardError.new }
|
458
|
+
|
459
|
+
it { is_expected.to eq(Fear.failure(error)) }
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
context "#and_then" do
|
464
|
+
context "single callback" do
|
465
|
+
context "callback is called" do
|
466
|
+
it "calls callback" do
|
467
|
+
expect do |callback|
|
468
|
+
Fear::Future.successful(5).and_then do |m|
|
469
|
+
m.success(&callback)
|
470
|
+
end
|
471
|
+
end.to yield_with_args(5)
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
context "future with Success" do
|
476
|
+
subject { Fear::Await.result(future, 1) }
|
477
|
+
|
478
|
+
context "callback is not failing" do
|
479
|
+
let(:future) do
|
480
|
+
Fear.future { 5 }
|
481
|
+
.and_then { |m| m.success { |x| x * 2 } }
|
482
|
+
end
|
483
|
+
|
484
|
+
it "returns the same future" do
|
485
|
+
is_expected.to eq(Fear.success(5))
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
context "callback is failing" do
|
490
|
+
let(:future) { Fear.future { 5 }.and_then { |m| m.success { raise "foo" } } }
|
491
|
+
|
492
|
+
it { is_expected.to eq(Fear.success(5)) }
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
context "future with Failure" do
|
497
|
+
let(:error) { StandardError.new }
|
498
|
+
|
499
|
+
it "ensure callback is called" do
|
500
|
+
expect do |callback|
|
501
|
+
Fear::Future.failed(error).and_then do |m|
|
502
|
+
m.failure(&callback)
|
503
|
+
end
|
504
|
+
end.to yield_with_args(error)
|
505
|
+
end
|
506
|
+
|
507
|
+
context "callback is not failing" do
|
508
|
+
subject { Fear::Await.result(future, 1) }
|
509
|
+
|
510
|
+
let(:future) { Fear.future { raise error }.and_then {} }
|
511
|
+
let!(:error) { StandardError.new }
|
512
|
+
|
513
|
+
it "returns result of future" do
|
514
|
+
is_expected.to eq(Fear.failure(error))
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
context "callback is failing" do
|
519
|
+
subject { Fear::Await.result(future, 1) }
|
520
|
+
|
521
|
+
let(:future) do
|
522
|
+
Fear.future { raise error }
|
523
|
+
.and_then { raise ArgumentError }
|
524
|
+
end
|
525
|
+
let!(:error) { StandardError.new }
|
526
|
+
|
527
|
+
it "returns result of future" do
|
528
|
+
is_expected.to eq(Fear.failure(error))
|
529
|
+
end
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
context "multiple callbacks" do
|
535
|
+
context "on Future with Success" do
|
536
|
+
it "ensure callbacks are called" do
|
537
|
+
expect do |first|
|
538
|
+
expect do |second|
|
539
|
+
Fear::Future.successful(5)
|
540
|
+
.and_then { |m| m.success(&first) }
|
541
|
+
.and_then { |m| m.success(&second) }
|
542
|
+
end.to yield_with_args(5)
|
543
|
+
end.to yield_with_args(5)
|
544
|
+
end
|
545
|
+
|
546
|
+
it "ensure callbacks called in specified order" do
|
547
|
+
# REVIEW: could not write failing test
|
548
|
+
last_called = nil
|
549
|
+
Fear.future { 5 }.and_then do
|
550
|
+
sleep 1
|
551
|
+
expect(last_called).to eq(nil)
|
552
|
+
last_called = :first
|
553
|
+
end.and_then do
|
554
|
+
expect(last_called).to(
|
555
|
+
eq(:first), "second callback called before first"
|
556
|
+
)
|
557
|
+
last_called = :second
|
558
|
+
end
|
559
|
+
|
560
|
+
sleep 2
|
561
|
+
|
562
|
+
expect(last_called).to eq(:second)
|
563
|
+
end
|
564
|
+
|
565
|
+
context "first callback is not failing" do
|
566
|
+
context "and second callback is not failing" do
|
567
|
+
subject { Fear::Await.result(future, 1) }
|
568
|
+
|
569
|
+
let(:future) do
|
570
|
+
Fear.future { 5 }
|
571
|
+
.and_then {}
|
572
|
+
.and_then {}
|
573
|
+
end
|
574
|
+
|
575
|
+
it { is_expected.to eq(Fear.success(5)) }
|
576
|
+
end
|
577
|
+
|
578
|
+
context "and second callback is failing" do
|
579
|
+
subject { Fear::Await.result(future, 1) }
|
580
|
+
|
581
|
+
let(:future) do
|
582
|
+
Fear.future { 5 }
|
583
|
+
.and_then {}
|
584
|
+
.and_then { raise }
|
585
|
+
end
|
586
|
+
|
587
|
+
it { is_expected.to eq(Fear.success(5)) }
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
context "first callback is failing" do
|
592
|
+
it "calls second callback" do
|
593
|
+
expect do |callback|
|
594
|
+
Fear::Future.successful(5).and_then { raise error }.and_then { |m| m.success(&callback) }
|
595
|
+
end.to yield_with_args(5)
|
596
|
+
end
|
597
|
+
|
598
|
+
context "and second callback is not failing" do
|
599
|
+
subject { Fear::Await.result(future, 1) }
|
600
|
+
|
601
|
+
let(:future) do
|
602
|
+
Fear.future { 5 }
|
603
|
+
.and_then { raise }
|
604
|
+
.and_then {}
|
605
|
+
end
|
606
|
+
|
607
|
+
it { is_expected.to eq(Fear.success(5)) }
|
608
|
+
end
|
609
|
+
|
610
|
+
context "and second callback is failing" do
|
611
|
+
subject { Fear::Await.result(future, 1) }
|
612
|
+
|
613
|
+
let(:future) do
|
614
|
+
Fear.future { 5 }
|
615
|
+
.and_then { raise }
|
616
|
+
.and_then { raise ArgumentError }
|
617
|
+
end
|
618
|
+
|
619
|
+
it { is_expected.to eq(Fear.success(5)) }
|
620
|
+
end
|
621
|
+
end
|
622
|
+
end
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
context ".successful" do
|
627
|
+
it "returns already succeed Future" do
|
628
|
+
future = described_class.successful(5)
|
629
|
+
|
630
|
+
future_value = future.value
|
631
|
+
|
632
|
+
expect(future_value).to eq Fear.some(Fear.success(5))
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
context ".failed" do
|
637
|
+
let(:error) { StandardError.new }
|
638
|
+
|
639
|
+
it "returns already failed Future" do
|
640
|
+
value = described_class.failed(error).value
|
641
|
+
|
642
|
+
expect(value).to eq Fear.some(Fear.failure(error))
|
643
|
+
end
|
644
|
+
end
|
645
|
+
|
646
|
+
describe Fear::Awaitable do
|
647
|
+
describe "#result" do
|
648
|
+
context "managed to complete within timeout" do
|
649
|
+
subject { Fear::Await.result(Fear.future { 5 }, 0.01) }
|
650
|
+
|
651
|
+
it { is_expected.to eq(Fear.success(5)) }
|
652
|
+
end
|
653
|
+
|
654
|
+
context "managed to complete within timeout with error" do
|
655
|
+
subject { Fear::Await.result(Fear.future { raise error }, 0.01) }
|
656
|
+
|
657
|
+
let!(:error) { StandardError.new }
|
658
|
+
|
659
|
+
it { is_expected.to eq(Fear.failure(error)) }
|
660
|
+
end
|
661
|
+
|
662
|
+
context "did not manage to complete within timeout" do
|
663
|
+
subject do
|
664
|
+
proc do
|
665
|
+
Fear::Await.result(Fear.future { sleep(1) }, 0.01)
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
it { is_expected.to raise_error(Timeout::Error) }
|
670
|
+
end
|
671
|
+
end
|
672
|
+
|
673
|
+
describe "#ready" do
|
674
|
+
context "managed to complete within timeout" do
|
675
|
+
subject { Fear::Await.ready(Fear.future { 5 }, 0.01).value }
|
676
|
+
|
677
|
+
it { is_expected.to eq(Fear.some(Fear.success(5))) }
|
678
|
+
end
|
679
|
+
|
680
|
+
context "did not manage to complete within timeout" do
|
681
|
+
subject do
|
682
|
+
proc do
|
683
|
+
Fear::Await.ready(Fear.future { sleep(1) }, 0.01)
|
684
|
+
end
|
685
|
+
end
|
686
|
+
|
687
|
+
it { is_expected.to raise_error(Timeout::Error) }
|
688
|
+
end
|
689
|
+
end
|
690
|
+
end
|
691
|
+
end
|