fear 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -60
  3. data/.travis.yml +8 -4
  4. data/CHANGELOG.md +7 -1
  5. data/Gemfile +5 -3
  6. data/Gemfile.lock +18 -20
  7. data/README.md +28 -14
  8. data/Rakefile +61 -60
  9. data/examples/pattern_extracting.rb +8 -6
  10. data/examples/pattern_matching_binary_tree_set.rb +4 -2
  11. data/examples/pattern_matching_number_in_words.rb +46 -42
  12. data/fear.gemspec +29 -27
  13. data/lib/fear.rb +44 -37
  14. data/lib/fear/await.rb +33 -0
  15. data/lib/fear/awaitable.rb +28 -0
  16. data/lib/fear/either.rb +2 -0
  17. data/lib/fear/either_api.rb +2 -0
  18. data/lib/fear/either_pattern_match.rb +2 -0
  19. data/lib/fear/empty_partial_function.rb +3 -1
  20. data/lib/fear/extractor.rb +30 -28
  21. data/lib/fear/extractor/anonymous_array_splat_matcher.rb +2 -0
  22. data/lib/fear/extractor/any_matcher.rb +2 -0
  23. data/lib/fear/extractor/array_head_matcher.rb +2 -0
  24. data/lib/fear/extractor/array_matcher.rb +2 -0
  25. data/lib/fear/extractor/array_splat_matcher.rb +2 -0
  26. data/lib/fear/extractor/empty_list_matcher.rb +2 -0
  27. data/lib/fear/extractor/extractor_matcher.rb +5 -3
  28. data/lib/fear/extractor/grammar.rb +5 -3
  29. data/lib/fear/extractor/identifier_matcher.rb +2 -0
  30. data/lib/fear/extractor/matcher.rb +5 -3
  31. data/lib/fear/extractor/matcher/and.rb +3 -1
  32. data/lib/fear/extractor/named_array_splat_matcher.rb +2 -0
  33. data/lib/fear/extractor/pattern.rb +7 -5
  34. data/lib/fear/extractor/typed_identifier_matcher.rb +2 -0
  35. data/lib/fear/extractor/value_matcher.rb +2 -0
  36. data/lib/fear/extractor_api.rb +2 -0
  37. data/lib/fear/failure.rb +2 -0
  38. data/lib/fear/failure_pattern_match.rb +2 -0
  39. data/lib/fear/for.rb +4 -2
  40. data/lib/fear/for_api.rb +3 -1
  41. data/lib/fear/future.rb +141 -64
  42. data/lib/fear/future_api.rb +2 -0
  43. data/lib/fear/left.rb +3 -1
  44. data/lib/fear/left_pattern_match.rb +2 -0
  45. data/lib/fear/none.rb +4 -2
  46. data/lib/fear/none_pattern_match.rb +2 -0
  47. data/lib/fear/option.rb +3 -1
  48. data/lib/fear/option_api.rb +2 -0
  49. data/lib/fear/option_pattern_match.rb +2 -0
  50. data/lib/fear/partial_function.rb +10 -8
  51. data/lib/fear/partial_function/and_then.rb +4 -2
  52. data/lib/fear/partial_function/any.rb +2 -0
  53. data/lib/fear/partial_function/combined.rb +3 -1
  54. data/lib/fear/partial_function/empty.rb +2 -0
  55. data/lib/fear/partial_function/guard.rb +7 -5
  56. data/lib/fear/partial_function/guard/and.rb +2 -0
  57. data/lib/fear/partial_function/guard/and3.rb +2 -0
  58. data/lib/fear/partial_function/guard/or.rb +2 -0
  59. data/lib/fear/partial_function/lifted.rb +2 -0
  60. data/lib/fear/partial_function/or_else.rb +3 -1
  61. data/lib/fear/partial_function_class.rb +3 -1
  62. data/lib/fear/pattern_match.rb +3 -1
  63. data/lib/fear/pattern_matching_api.rb +3 -1
  64. data/lib/fear/promise.rb +11 -3
  65. data/lib/fear/right.rb +3 -1
  66. data/lib/fear/right_biased.rb +4 -2
  67. data/lib/fear/right_pattern_match.rb +2 -0
  68. data/lib/fear/some.rb +2 -0
  69. data/lib/fear/some_pattern_match.rb +2 -0
  70. data/lib/fear/struct.rb +235 -0
  71. data/lib/fear/success.rb +2 -0
  72. data/lib/fear/success_pattern_match.rb +2 -0
  73. data/lib/fear/try.rb +2 -0
  74. data/lib/fear/try_api.rb +2 -0
  75. data/lib/fear/try_pattern_match.rb +2 -0
  76. data/lib/fear/unit.rb +6 -2
  77. data/lib/fear/utils.rb +4 -2
  78. data/lib/fear/version.rb +4 -1
  79. data/spec/fear/done_spec.rb +7 -5
  80. data/spec/fear/either/mixin_spec.rb +4 -2
  81. data/spec/fear/either_pattern_match_spec.rb +10 -8
  82. data/spec/fear/extractor/array_matcher_spec.rb +65 -63
  83. data/spec/fear/extractor/extractor_matcher_spec.rb +64 -62
  84. data/spec/fear/extractor/grammar_array_spec.rb +5 -3
  85. data/spec/fear/extractor/identified_matcher_spec.rb +18 -16
  86. data/spec/fear/extractor/identifier_matcher_spec.rb +26 -24
  87. data/spec/fear/extractor/pattern_spec.rb +17 -15
  88. data/spec/fear/extractor/typed_identifier_matcher_spec.rb +23 -21
  89. data/spec/fear/extractor/value_matcher_number_spec.rb +29 -27
  90. data/spec/fear/extractor/value_matcher_string_spec.rb +27 -25
  91. data/spec/fear/extractor/value_matcher_symbol_spec.rb +24 -22
  92. data/spec/fear/extractor_api_spec.rb +70 -68
  93. data/spec/fear/extractor_spec.rb +23 -21
  94. data/spec/fear/failure_spec.rb +59 -57
  95. data/spec/fear/for_spec.rb +19 -17
  96. data/spec/fear/future_spec.rb +456 -240
  97. data/spec/fear/guard_spec.rb +26 -24
  98. data/spec/fear/left_spec.rb +60 -58
  99. data/spec/fear/none_spec.rb +36 -34
  100. data/spec/fear/option/mixin_spec.rb +9 -7
  101. data/spec/fear/option_pattern_match_spec.rb +10 -8
  102. data/spec/fear/partial_function/empty_spec.rb +12 -10
  103. data/spec/fear/partial_function_and_then_spec.rb +39 -37
  104. data/spec/fear/partial_function_composition_spec.rb +46 -44
  105. data/spec/fear/partial_function_or_else_spec.rb +92 -90
  106. data/spec/fear/partial_function_spec.rb +46 -44
  107. data/spec/fear/pattern_match_spec.rb +31 -29
  108. data/spec/fear/promise_spec.rb +19 -17
  109. data/spec/fear/right_biased/left.rb +28 -26
  110. data/spec/fear/right_biased/right.rb +51 -49
  111. data/spec/fear/right_spec.rb +58 -56
  112. data/spec/fear/some_spec.rb +30 -28
  113. data/spec/fear/success_spec.rb +50 -48
  114. data/spec/fear/try/mixin_spec.rb +5 -3
  115. data/spec/fear/try_pattern_match_spec.rb +10 -8
  116. data/spec/fear/utils_spec.rb +16 -14
  117. data/spec/spec_helper.rb +7 -5
  118. data/spec/struct_spec.rb +226 -0
  119. metadata +18 -13
@@ -1,66 +1,166 @@
1
- RSpec.describe Fear::Future do
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
- context '#on_complete' do
10
- it 'run callback with value' do
3
+ RSpec.describe Fear::Future do
4
+ context "#on_complete" do
5
+ it "run callback with value" do
11
6
  expect do |callback|
12
- future { value }.on_complete(&callback)
13
- end.to yield_with_args(Fear.success(value))
7
+ Fear::Future.successful(5).on_complete(&callback)
8
+ end.to yield_with_args(Fear.success(5))
14
9
  end
15
10
 
16
- it 'run callback with error' do
11
+ let(:error) { StandardError.new }
12
+
13
+ it "run callback with error" do
17
14
  expect do |callback|
18
- future { raise error }.on_complete(&callback)
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 '#on_success' do
24
- it 'run callback if no error' do
25
- expect do |callback|
26
- future { value }.on_success(&callback)
27
- end.to yield_with_args(value)
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
- it 'do not run callback if error occurred' do
31
- expect do |callback|
32
- future { raise error }.on_success(&callback)
33
- end.not_to yield_with_args
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
- specify 'call all registered callbacks' do
37
- expect do |second|
38
- expect do |first|
39
- future { value }
40
- .on_success(&first)
41
- .on_success(&second)
42
- end.to yield_with_args(value)
43
- end.to yield_with_args(value)
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
- context '#on_failure' do
48
- it 'do not run callback if no error' do
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
- future { value }.on_failure(&callback)
150
+ Fear::Future.successful(5).on_failure(&callback)
51
151
  end.not_to yield_with_args
52
152
  end
53
153
 
54
- it 'run callback if error occurred' do
154
+ it "run callback if error occurred" do
55
155
  expect do |callback|
56
- future { raise error }.on_failure(&callback)
156
+ Fear::Future.failed(error).on_failure(&callback)
57
157
  end.to yield_with_args(error)
58
158
  end
59
159
 
60
- specify 'call all registered callbacks' do
160
+ specify "call all registered callbacks" do
61
161
  expect do |second|
62
162
  expect do |first|
63
- future { raise error }
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 '#completed?' do
72
- it 'completed with value' do
73
- completed_future = future { value }
74
-
75
- expect(completed_future).to be_completed
76
- end
77
-
78
- it 'completed with error' do
79
- completed_future = future { raise error }
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
- expect(completed_future).to be_completed
182
+ it { is_expected.to yield_with_args(error) }
82
183
  end
83
184
 
84
- it 'not completed with value' do
85
- not_completed_future =
86
- Fear.future do
87
- sleep 1
88
- value
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
- expect(not_completed_future).not_to be_completed
195
+ it { is_expected.not_to yield_control }
92
196
  end
93
197
 
94
- it 'not completed with error' do
95
- not_completed_future =
96
- Fear.future do
97
- sleep 1
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
- expect(not_completed_future).not_to be_completed
205
+ it { is_expected.not_to yield_control }
102
206
  end
103
207
  end
104
208
 
105
- context '#value' do
106
- it 'None if not completed' do
107
- not_completed_future =
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
- future_value = not_completed_future.value
114
-
115
- expect(future_value).to eq(Fear.none)
218
+ it { is_expected.not_to be_completed }
116
219
  end
117
220
 
118
- it 'Some of Success if completed with result' do
119
- future_value = future { value }.value
221
+ context "completed with error" do
222
+ subject { Fear::Await.ready(Fear.future { raise StandardError }, 1) }
120
223
 
121
- expect(future_value).to eq Fear.some(Fear.success(value))
224
+ it { is_expected.to be_completed }
122
225
  end
123
226
 
124
- it 'Some of Failure if completed with error' do
125
- value = future { raise error }.value
227
+ context "completed with value" do
228
+ subject { Fear::Await.ready(Fear.future { 5 }, 0.5) }
126
229
 
127
- expect(value).to eq Fear.some(Fear.failure(error))
230
+ it { is_expected.to be_completed }
128
231
  end
129
232
  end
130
233
 
131
- context '#transform' do
132
- let(:failure) { ->(e) { e.message } }
133
- let(:success) { ->(v) { v * 2 } }
234
+ context "#value" do
235
+ subject { future.value }
134
236
 
135
- it 'call first callback if successful' do
136
- value = future { 2 }.transform(success, failure).value
237
+ context "future returns nil" do
238
+ let(:future) { Fear::Future.successful(nil) }
137
239
 
138
- expect(value).to eq Fear.some(Fear.success(4))
240
+ it { is_expected.to eq(Fear.some(Fear.success(nil))) }
139
241
  end
140
242
 
141
- it 'call second callback if failed' do
142
- value = future { raise error }.transform(success, failure).value
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
- expect(value).to eq Fear.some(Fear.failure('something went wrong'))
251
+ it { is_expected.to eq(Fear.none) }
145
252
  end
146
- end
147
253
 
148
- context '#map' do
149
- it 'successful result' do
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
- expect(result).to eq Fear.some(Fear.success(10))
257
+ it { is_expected.to eq(Fear.some(Fear.success(5))) }
153
258
  end
154
259
 
155
- it 'failed result' do
156
- result = future { raise error }.map { |r| r * 2 }.value
260
+ context "completed with failure" do
261
+ let(:future) { Fear::Future.failed(error) }
262
+ let(:error) { StandardError.new }
157
263
 
158
- expect(result).to eq Fear.some(Fear.failure(error))
264
+ it { is_expected.to eq(Fear.some(Fear.failure(error))) }
159
265
  end
160
266
  end
161
267
 
162
- context '#flat_map' do
163
- it 'successful result' do
164
- result = future { value }.flat_map { |r| future { r * 2 } }.value
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
- expect(result).to eq Fear.some(Fear.success(10))
274
+ it { is_expected.to eq(Fear.success(4)) }
167
275
  end
168
276
 
169
- it 'failed result' do
170
- result = future { raise error }.flat_map { |r| future { r * 2 } }.value
277
+ context "failed" do
278
+ subject { Fear::Await.result(future, 1) }
171
279
 
172
- expect(result).to eq Fear.some(Fear.failure(error))
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
- it 'failed callback future' do
176
- result = future { value }.flat_map { future { raise error } }.value
290
+ context "successful" do
291
+ let(:future) { Fear.future { 5 } }
177
292
 
178
- expect(result).to eq Fear.some(Fear.failure(error))
293
+ it { is_expected.to eq(Fear.success(10)) }
179
294
  end
180
295
 
181
- it 'failured callback' do
182
- result = future { value }.flat_map { raise error }.value
296
+ context "failed" do
297
+ let(:future) { Fear.future { raise error } }
298
+ let!(:error) { StandardError.new("foo") }
183
299
 
184
- expect(result).to eq Fear.some(Fear.failure(error))
300
+ it { is_expected.to eq(Fear.failure(error)) }
185
301
  end
186
302
  end
187
303
 
188
- context '#each' do
189
- it 'successful result' do
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
- it 'failed result' do
196
- expect do |callback|
197
- future { raise error }.each(&callback)
198
- end.not_to yield_with_args
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
- context '#select' do
203
- it 'satisfy predicate' do
204
- value = future { 2 }.select(&:even?).value
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
- expect(value).to eq Fear.some(Fear.success(2))
317
+ it { is_expected.to eq(Fear.failure(error)) }
207
318
  end
208
319
 
209
- it 'does not satisfy predicate' do
210
- value = future { 3 }.select(&:even?).value
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
- expect(value.get.exception).to be_kind_of(Fear::NoSuchElementError)
324
+ it { is_expected.to eq(Fear.failure(error)) }
213
325
  end
214
326
 
215
- it 'failure' do
216
- value = future { raise error }.select(&:even?).value
327
+ context "failed callback" do
328
+ let(:future) { Fear.future { 5 }.flat_map { raise error } }
329
+ let!(:error) { StandardError.new("foo") }
217
330
 
218
- expect(value.get.exception).to eq error
331
+ it { is_expected.to eq(Fear.failure(error)) }
219
332
  end
220
333
  end
221
334
 
222
- context '#recover' do
223
- it 'success' do
224
- value = future { 2 / 1 }.recover do |m|
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
- expect(value).to eq Fear.some(Fear.success(2))
339
+ let(:future) { Fear.future { 2 }.select(&:even?) }
340
+
341
+ it { is_expected.to eq(Fear.success(2)) }
229
342
  end
230
343
 
231
- it 'failure and error case covered by pattern match' do
232
- value = future { 2 / 0 }.recover do |m|
233
- m.case(RuntimeError, &:message)
234
- m.case(ZeroDivisionError) { 0 }
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
- expect(value).to eq Fear.some(Fear.success(0))
349
+ it { is_expected.to be_kind_of(Fear::NoSuchElementError) }
238
350
  end
239
351
 
240
- it 'failure and error case not covered by pattern match' do
241
- value = future { 2 / 0 }.recover do |m|
242
- m.case(RuntimeError, &:message)
243
- end.value
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
- expect(value.get).to be_kind_of(Fear::Failure)
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 '#zip' do
251
- it 'success' do
252
- this = future { 1 }
253
- that = future { 2 }
362
+ context "#recover" do
363
+ subject { Fear::Await.result(future, 1) }
254
364
 
255
- value = this.zip(that).value
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
- expect(value).to eq Fear.some(Fear.success([1, 2]))
372
+ it { is_expected.to eq(Fear.success(2)) }
258
373
  end
259
374
 
260
- it 'self fails' do
261
- this = future { raise error }
262
- that = future { 2 }
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
- value = this.zip(that).value
383
+ it { is_expected.to eq(Fear.success(Float::INFINITY)) }
384
+ end
265
385
 
266
- expect(value).to eq Fear.some(Fear.failure(error))
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
- it 'other fails' do
270
- this = future { 1 }
271
- that = future { raise error }
397
+ context "#zip" do
398
+ subject { Fear::Await.result(future, 1) }
272
399
 
273
- value = this.zip(that).value
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
- expect(value).to eq Fear.some(Fear.failure(error))
405
+ it { is_expected.to eq(Fear.success([1, 2])) }
276
406
  end
277
407
 
278
- it 'both fail' do
279
- this = future { raise error }
280
- that = future { raise ArgumentError }
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
- value = this.zip(that).value
414
+ it { is_expected.to eq(Fear.failure(error)) }
415
+ end
283
416
 
284
- expect(value).to eq Fear.some(Fear.failure(error))
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 '#fallback_to' do
289
- it 'success' do
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
- expect(value).to eq Fear.some(Fear.success(2))
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
- it 'failure' do
297
- fallback = future { 42 }
298
- value = future { raise error }.fallback_to(fallback).value
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
- expect(value).to eq Fear.some(Fear.success(42))
442
+ it { is_expected.to eq(Fear.success(42)) }
301
443
  end
302
444
 
303
- it 'failure with failed fallback' do
304
- fallback = future { raise ArumentError }
305
- value = future { raise error }.fallback_to(fallback).value
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
- expect(value).to eq Fear.some(Fear.failure(error))
450
+ it { is_expected.to eq(Fear.failure(error)) }
308
451
  end
309
452
  end
310
453
 
311
- context '#and_then' do
312
- context 'single callback' do
313
- context 'callback is called' do
314
- it 'returns result of future' do
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
- future { 5 }.and_then do |m|
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 'future with Success' do
324
- context 'callback is not failing' do
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
- expect(value).to eq Fear.some(Fear.success(5))
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 'callback is failing' do
333
- it 'returns result of future' do
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
- expect(value).to eq Fear.some(Fear.success(5))
337
- end
483
+ it { is_expected.to eq(Fear.success(5)) }
338
484
  end
339
485
  end
340
486
 
341
- context 'future with Failure' do
342
- it 'ensure callback is called' do
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
- future { raise error }.and_then do |m|
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 'callback is not failing' do
351
- it 'returns result of future' do
352
- value = future { raise error }.and_then {}.value
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
- expect(value).to eq Fear.some(Fear.failure(error))
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 'callback is failing' do
359
- it 'returns result of future' do
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
- expect(value).to eq Fear.some(Fear.failure(error))
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 'multiple callbacks' do
369
- context 'on Future with Success' do
370
- it 'ensure callbacks are called' do
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
- future { 5 }.and_then { |m| m.success(&first) }.and_then { |m| m.success(&second) }
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
- # rubocop: disable Style/MultilineBlockChain
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), 'second callback called before 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 'first callback is not failing' do
400
- context 'and second callback is not failing' do
401
- it 'returns result of the Future' do
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
- expect(value).to eq Fear.some(Fear.success(5))
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 'and second callback is failing' do
409
- it 'returns result of the Future' do
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
- expect(value).to eq Fear.some(Fear.success(5))
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 'first callback is failing' do
420
- it 'calls second callback' do
582
+ context "first callback is failing" do
583
+ it "calls second callback" do
421
584
  expect do |callback|
422
- future { 5 }.and_then { raise error }.and_then { |m| m.success(&callback) }
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 'and second callback is not failing' do
427
- it 'returns result of the Future' do
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
- expect(value).to eq Fear.some(Fear.success(5))
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 'and second callback is failing' do
435
- it 'returns result of the Future' do
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
- expect(value).to eq Fear.some(Fear.success(5))
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 '.successful' do
450
- it 'returns already succeed Future' do
451
- future = described_class.successful(value)
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(value))
623
+ expect(future_value).to eq Fear.some(Fear.success(5))
456
624
  end
457
625
  end
458
626
 
459
- context '.failed' do
460
- it 'returns already failed Future' do
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