fear 0.9.0 → 1.2.0

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