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