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