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.
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