fear 0.11.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +0 -1
  3. data/.rubocop.yml +18 -0
  4. data/.travis.yml +0 -3
  5. data/CHANGELOG.md +12 -1
  6. data/Gemfile +1 -0
  7. data/{gemfiles/dry_equalizer_0.2.1.gemfile.lock → Gemfile.lock} +21 -12
  8. data/README.md +594 -241
  9. data/Rakefile +166 -219
  10. data/benchmarks/README.md +1 -0
  11. data/benchmarks/dry_do_vs_fear_for.txt +11 -0
  12. data/benchmarks/dry_some_fmap_vs_fear_some_map.txt +11 -0
  13. data/benchmarks/factorial.txt +16 -0
  14. data/benchmarks/fear_gaurd_and1_vs_new.txt +13 -0
  15. data/benchmarks/fear_gaurd_and2_vs_and.txt +13 -0
  16. data/benchmarks/fear_gaurd_and3_vs_and_and.txt +13 -0
  17. data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +11 -0
  18. data/benchmarks/fear_pattern_matching_construction_vs_execution.txt +13 -0
  19. data/benchmarks/pattern_matching_dry_vs_qo_vs_fear_try.txt +14 -0
  20. data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +11 -0
  21. data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +11 -0
  22. data/examples/pattern_extracting.rb +15 -0
  23. data/examples/pattern_matching_binary_tree_set.rb +96 -0
  24. data/examples/pattern_matching_number_in_words.rb +54 -0
  25. data/fear.gemspec +4 -2
  26. data/lib/fear.rb +21 -4
  27. data/lib/fear/either.rb +77 -59
  28. data/lib/fear/either_api.rb +21 -0
  29. data/lib/fear/empty_partial_function.rb +1 -1
  30. data/lib/fear/extractor.rb +108 -0
  31. data/lib/fear/extractor/anonymous_array_splat_matcher.rb +8 -0
  32. data/lib/fear/extractor/any_matcher.rb +15 -0
  33. data/lib/fear/extractor/array_head_matcher.rb +34 -0
  34. data/lib/fear/extractor/array_matcher.rb +38 -0
  35. data/lib/fear/extractor/array_splat_matcher.rb +14 -0
  36. data/lib/fear/extractor/empty_list_matcher.rb +18 -0
  37. data/lib/fear/extractor/extractor_matcher.rb +42 -0
  38. data/lib/fear/extractor/grammar.rb +201 -0
  39. data/lib/fear/extractor/grammar.treetop +129 -0
  40. data/lib/fear/extractor/identifier_matcher.rb +16 -0
  41. data/lib/fear/extractor/matcher.rb +54 -0
  42. data/lib/fear/extractor/matcher/and.rb +36 -0
  43. data/lib/fear/extractor/named_array_splat_matcher.rb +15 -0
  44. data/lib/fear/extractor/pattern.rb +55 -0
  45. data/lib/fear/extractor/typed_identifier_matcher.rb +24 -0
  46. data/lib/fear/extractor/value_matcher.rb +17 -0
  47. data/lib/fear/extractor_api.rb +33 -0
  48. data/lib/fear/failure.rb +32 -10
  49. data/lib/fear/for.rb +14 -69
  50. data/lib/fear/for_api.rb +66 -0
  51. data/lib/fear/future.rb +414 -0
  52. data/lib/fear/future_api.rb +19 -0
  53. data/lib/fear/left.rb +8 -0
  54. data/lib/fear/none.rb +17 -8
  55. data/lib/fear/option.rb +55 -49
  56. data/lib/fear/option_api.rb +38 -0
  57. data/lib/fear/partial_function.rb +9 -12
  58. data/lib/fear/partial_function/empty.rb +1 -1
  59. data/lib/fear/partial_function/guard.rb +8 -20
  60. data/lib/fear/partial_function/lifted.rb +1 -0
  61. data/lib/fear/partial_function_class.rb +10 -0
  62. data/lib/fear/pattern_match.rb +10 -0
  63. data/lib/fear/pattern_matching_api.rb +35 -11
  64. data/lib/fear/promise.rb +87 -0
  65. data/lib/fear/right.rb +8 -0
  66. data/lib/fear/some.rb +22 -3
  67. data/lib/fear/success.rb +22 -1
  68. data/lib/fear/try.rb +82 -67
  69. data/lib/fear/try_api.rb +31 -0
  70. data/lib/fear/unit.rb +28 -0
  71. data/lib/fear/version.rb +1 -1
  72. data/spec/fear/done_spec.rb +3 -3
  73. data/spec/fear/either/mixin_spec.rb +15 -0
  74. data/spec/fear/either_pattern_match_spec.rb +10 -12
  75. data/spec/fear/extractor/array_matcher_spec.rb +228 -0
  76. data/spec/fear/extractor/extractor_matcher_spec.rb +151 -0
  77. data/spec/fear/extractor/grammar_array_spec.rb +23 -0
  78. data/spec/fear/extractor/identified_matcher_spec.rb +47 -0
  79. data/spec/fear/extractor/identifier_matcher_spec.rb +66 -0
  80. data/spec/fear/extractor/pattern_spec.rb +32 -0
  81. data/spec/fear/extractor/typed_identifier_matcher_spec.rb +62 -0
  82. data/spec/fear/extractor/value_matcher_number_spec.rb +77 -0
  83. data/spec/fear/extractor/value_matcher_string_spec.rb +86 -0
  84. data/spec/fear/extractor/value_matcher_symbol_spec.rb +69 -0
  85. data/spec/fear/extractor_api_spec.rb +113 -0
  86. data/spec/fear/extractor_spec.rb +59 -0
  87. data/spec/fear/failure_spec.rb +73 -13
  88. data/spec/fear/for_spec.rb +35 -35
  89. data/spec/fear/future_spec.rb +466 -0
  90. data/spec/fear/guard_spec.rb +4 -4
  91. data/spec/fear/left_spec.rb +40 -14
  92. data/spec/fear/none_spec.rb +28 -12
  93. data/spec/fear/option/mixin_spec.rb +37 -0
  94. data/spec/fear/option_pattern_match_spec.rb +7 -9
  95. data/spec/fear/partial_function_spec.rb +25 -3
  96. data/spec/fear/pattern_match_spec.rb +33 -1
  97. data/spec/fear/promise_spec.rb +94 -0
  98. data/spec/fear/right_spec.rb +37 -9
  99. data/spec/fear/some_spec.rb +32 -6
  100. data/spec/fear/success_spec.rb +32 -4
  101. data/spec/fear/try/mixin_spec.rb +17 -0
  102. data/spec/fear/try_pattern_match_spec.rb +8 -10
  103. data/spec/spec_helper.rb +1 -1
  104. metadata +115 -20
  105. data/Appraisals +0 -32
  106. data/gemfiles/dry_equalizer_0.1.0.gemfile +0 -8
  107. data/gemfiles/dry_equalizer_0.1.0.gemfile.lock +0 -82
  108. data/gemfiles/dry_equalizer_0.2.1.gemfile +0 -8
  109. data/lib/fear/done.rb +0 -22
  110. data/spec/fear/option_spec.rb +0 -15
@@ -15,13 +15,13 @@ RSpec.describe Fear::PartialFunction::Guard do
15
15
 
16
16
  context 'Symbol' do
17
17
  context 'match' do
18
- subject { Fear::PartialFunction::Guard.new(:even?) === 4 }
18
+ subject { Fear::PartialFunction::Guard.new(:even?) === :even? }
19
19
 
20
20
  it { is_expected.to eq(true) }
21
21
  end
22
22
 
23
23
  context 'not match' do
24
- subject { Fear::PartialFunction::Guard.new(:even?) === 3 }
24
+ subject { Fear::PartialFunction::Guard.new(:even?) === 4 }
25
25
 
26
26
  it { is_expected.to eq(false) }
27
27
  end
@@ -44,14 +44,14 @@ RSpec.describe Fear::PartialFunction::Guard do
44
44
  describe '.and' do
45
45
  context 'match' do
46
46
  subject { guard === 4 }
47
- let(:guard) { Fear::PartialFunction::Guard.and([Integer, :even?, ->(x) { x.even? }]) }
47
+ let(:guard) { Fear::PartialFunction::Guard.and([Integer, :even?.to_proc, ->(x) { x.even? }]) }
48
48
 
49
49
  it { is_expected.to eq(true) }
50
50
  end
51
51
 
52
52
  context 'not match' do
53
53
  subject { guard === 3 }
54
- let(:guard) { Fear::PartialFunction::Guard.and([Integer, :even?, ->(x) { x.even? }]) }
54
+ let(:guard) { Fear::PartialFunction::Guard.and([Integer, :even?.to_proc, ->(x) { x.even? }]) }
55
55
 
56
56
  it { is_expected.to eq(false) }
57
57
  end
@@ -1,11 +1,9 @@
1
1
  RSpec.describe Fear::Left do
2
- include Fear::Either::Mixin
3
-
4
2
  it_behaves_like Fear::RightBiased::Left do
5
- let(:left) { Left('value') }
3
+ let(:left) { Fear.left('value') }
6
4
  end
7
5
 
8
- let(:left) { Left('value') }
6
+ let(:left) { Fear.left('value') }
9
7
 
10
8
  describe '#right?' do
11
9
  subject { left }
@@ -41,7 +39,7 @@ RSpec.describe Fear::Left do
41
39
 
42
40
  describe '#or_else' do
43
41
  subject { left.or_else { alternative } }
44
- let(:alternative) { Left(42) }
42
+ let(:alternative) { Fear.left(42) }
45
43
 
46
44
  it 'returns alternative' do
47
45
  is_expected.to eq(alternative)
@@ -70,7 +68,7 @@ RSpec.describe Fear::Left do
70
68
 
71
69
  describe '#swap' do
72
70
  subject { left.swap }
73
- it { is_expected.to eq(Right('value')) }
71
+ it { is_expected.to eq(Fear.right('value')) }
74
72
  end
75
73
 
76
74
  describe '#reduce' do
@@ -88,12 +86,12 @@ RSpec.describe Fear::Left do
88
86
  subject(:join_right) { either.join_right }
89
87
 
90
88
  context 'value is Either' do
91
- let(:either) { described_class.new(Left('error')) }
89
+ let(:either) { described_class.new(Fear.left('error')) }
92
90
  it { is_expected.to eq(either) }
93
91
  end
94
92
 
95
93
  context 'value s not Either' do
96
- let(:either) { Left('error') }
94
+ let(:either) { Fear.left('error') }
97
95
  it { is_expected.to eq(either) }
98
96
  end
99
97
  end
@@ -102,10 +100,10 @@ RSpec.describe Fear::Left do
102
100
  context 'value is Either' do
103
101
  subject { either.join_left }
104
102
  let(:either) { described_class.new(value) }
105
- let(:value) { Left('error') }
103
+ let(:value) { Fear.left('error') }
106
104
 
107
105
  it 'returns value' do
108
- is_expected.to eq(Left('error'))
106
+ is_expected.to eq(Fear.left('error'))
109
107
  end
110
108
  end
111
109
 
@@ -122,22 +120,22 @@ RSpec.describe Fear::Left do
122
120
  subject { match === left }
123
121
 
124
122
  context 'matches erectly' do
125
- let(:match) { Left('value') }
123
+ let(:match) { Fear.left('value') }
126
124
  it { is_expected.to eq(true) }
127
125
  end
128
126
 
129
127
  context 'value does not match' do
130
- let(:match) { Left('error') }
128
+ let(:match) { Fear.left('error') }
131
129
  it { is_expected.to eq(false) }
132
130
  end
133
131
 
134
132
  context 'matches by class' do
135
- let(:match) { Left(String) }
133
+ let(:match) { Fear.left(String) }
136
134
  it { is_expected.to eq(true) }
137
135
  end
138
136
 
139
137
  context 'does not matches by class' do
140
- let(:match) { Left(Integer) }
138
+ let(:match) { Fear.left(Integer) }
141
139
  it { is_expected.to eq(false) }
142
140
  end
143
141
  end
@@ -179,4 +177,32 @@ RSpec.describe Fear::Left do
179
177
  it { is_expected.to eq(:default) }
180
178
  end
181
179
  end
180
+
181
+ describe '#to_s' do
182
+ subject { left.to_s }
183
+
184
+ it { is_expected.to eq('#<Fear::Left value="value">') }
185
+ end
186
+
187
+ describe 'pattern matching' do
188
+ subject { Fear.xcase('Left(v : Integer)') { |v:| "matched #{v}" }.call_or_else(var) { 'nothing' } }
189
+
190
+ context 'left of int' do
191
+ let(:var) { Fear.left(42) }
192
+
193
+ it { is_expected.to eq('matched 42') }
194
+ end
195
+
196
+ context 'left of string' do
197
+ let(:var) { Fear.left('42') }
198
+
199
+ it { is_expected.to eq('nothing') }
200
+ end
201
+
202
+ context 'not left' do
203
+ let(:var) { '42' }
204
+
205
+ it { is_expected.to eq('nothing') }
206
+ end
207
+ end
182
208
  end
@@ -1,11 +1,9 @@
1
1
  RSpec.describe Fear::None do
2
- include Fear::Option::Mixin
3
-
4
2
  it_behaves_like Fear::RightBiased::Left do
5
- let(:left) { None() }
3
+ let(:left) { Fear.none }
6
4
  end
7
5
 
8
- subject(:none) { None() }
6
+ subject(:none) { Fear.none }
9
7
 
10
8
  describe '#get' do
11
9
  subject { proc { none.get } }
@@ -19,7 +17,7 @@ RSpec.describe Fear::None do
19
17
 
20
18
  describe '#or_else' do
21
19
  subject { none.or_else { alternative } }
22
- let(:alternative) { Some(42) }
20
+ let(:alternative) { Fear.some(42) }
23
21
 
24
22
  it 'returns alternative' do
25
23
  is_expected.to eq(alternative)
@@ -35,7 +33,7 @@ RSpec.describe Fear::None do
35
33
  subject { none.select { |value| value > 42 } }
36
34
 
37
35
  it 'always return None' do
38
- is_expected.to eq(None())
36
+ is_expected.to eq(Fear.none)
39
37
  end
40
38
  end
41
39
 
@@ -43,7 +41,7 @@ RSpec.describe Fear::None do
43
41
  subject { none.reject { |value| value > 42 } }
44
42
 
45
43
  it 'always return None' do
46
- is_expected.to eq(None())
44
+ is_expected.to eq(Fear.none)
47
45
  end
48
46
  end
49
47
 
@@ -54,21 +52,23 @@ RSpec.describe Fear::None do
54
52
  end
55
53
 
56
54
  describe '.inherited' do
57
- subject { -> { Class.new(Fear::None.class) } }
55
+ subject { -> { Class.new(Fear.none.class) } }
58
56
 
59
- it { is_expected.to raise_error }
57
+ it 'raises error' do
58
+ is_expected.to raise_error(RuntimeError, 'you are not allowed to inherit from NoneClass, use Fear::None instead')
59
+ end
60
60
  end
61
61
 
62
62
  describe '#to_s' do
63
63
  subject { none.to_s }
64
64
 
65
- it { is_expected.to eq('Fear::None') }
65
+ it { is_expected.to eq('#<Fear::NoneClass>') }
66
66
  end
67
67
 
68
68
  describe '#inspect' do
69
69
  subject { none.inspect }
70
70
 
71
- it { is_expected.to eq('Fear::None') }
71
+ it { is_expected.to eq('#<Fear::NoneClass>') }
72
72
  end
73
73
 
74
74
  describe '#===' do
@@ -79,7 +79,7 @@ RSpec.describe Fear::None do
79
79
  end
80
80
 
81
81
  context 'Fear::Some' do
82
- subject { Fear::None === Some(4) }
82
+ subject { Fear::None === Fear.some(4) }
83
83
 
84
84
  it { is_expected.to eq(false) }
85
85
  end
@@ -126,4 +126,20 @@ RSpec.describe Fear::None do
126
126
  it { is_expected.to eq(:default) }
127
127
  end
128
128
  end
129
+
130
+ describe 'pattern matching' do
131
+ subject { Fear.xcase('None()') { 'matched' }.call_or_else(var) { 'nothing' } }
132
+
133
+ context 'none' do
134
+ let(:var) { Fear.none }
135
+
136
+ it { is_expected.to eq('matched') }
137
+ end
138
+
139
+ context 'not none' do
140
+ let(:var) { '42' }
141
+
142
+ it { is_expected.to eq('nothing') }
143
+ end
144
+ end
129
145
  end
@@ -0,0 +1,37 @@
1
+ RSpec.describe Fear::Option::Mixin do
2
+ include Fear::Option::Mixin
3
+
4
+ describe 'Option()' do
5
+ context 'value is nil' do
6
+ subject { Option(nil) }
7
+
8
+ it { is_expected.to eq(Fear.none) }
9
+ end
10
+
11
+ context 'value is not nil' do
12
+ subject { Option(42) }
13
+
14
+ it { is_expected.to eq(Fear.some(42)) }
15
+ end
16
+ end
17
+
18
+ describe 'Some()' do
19
+ context 'value is nil' do
20
+ subject { Some(nil) }
21
+
22
+ it { is_expected.to eq(Fear::Some.new(nil)) }
23
+ end
24
+
25
+ context 'value is not nil' do
26
+ subject { Option(42) }
27
+
28
+ it { is_expected.to eq(Fear::Some.new(42)) }
29
+ end
30
+ end
31
+
32
+ describe 'None()' do
33
+ subject { None() }
34
+
35
+ it { is_expected.to eq(Fear::None) }
36
+ end
37
+ end
@@ -1,19 +1,17 @@
1
1
  RSpec.describe Fear::OptionPatternMatch do
2
- include Fear::Option::Mixin
3
-
4
2
  context 'Some' do
5
3
  let(:matcher) do
6
4
  described_class.new do |m|
7
- m.some(:even?) { |x| "#{x} is even" }
8
- m.some(:odd?) { |x| "#{x} is odd" }
5
+ m.some(:even?.to_proc) { |x| "#{x} is even" }
6
+ m.some(:odd?.to_proc) { |x| "#{x} is odd" }
9
7
  end
10
8
  end
11
9
 
12
10
  it do
13
- expect(matcher.call(Some(4))).to eq('4 is even')
14
- expect(matcher.call(Some(3))).to eq('3 is odd')
11
+ expect(matcher.call(Fear.some(4))).to eq('4 is even')
12
+ expect(matcher.call(Fear.some(3))).to eq('3 is odd')
15
13
  expect do
16
- matcher.call(None())
14
+ matcher.call(Fear.none)
17
15
  end.to raise_error(Fear::MatchError)
18
16
  end
19
17
  end
@@ -26,9 +24,9 @@ RSpec.describe Fear::OptionPatternMatch do
26
24
  end
27
25
 
28
26
  it do
29
- expect(matcher.call(None())).to eq('nil')
27
+ expect(matcher.call(Fear.none)).to eq('nil')
30
28
  expect do
31
- matcher.call(Some(3))
29
+ matcher.call(Fear.some(3))
32
30
  end.to raise_error(Fear::MatchError)
33
31
  end
34
32
  end
@@ -1,10 +1,22 @@
1
1
  RSpec.describe Fear::PartialFunction do
2
2
  describe 'Fear.case()' do
3
+ context 'condition is extractor' do
4
+ subject do
5
+ Fear.xcase('[1, [2, second_of_second, *], 3, *rest]') do |second_of_second:, rest:|
6
+ [second_of_second, rest]
7
+ end
8
+ end
9
+
10
+ it { is_expected.to be_defined_at([1, [2, 2, 3, 4], 3, 6, 7]) }
11
+ it { is_expected.not_to be_defined_at([1, [1, 3, 3, 4], 3, 6, 7]) }
12
+ it { is_expected.not_to be_defined_at([1, [1, 2, 3, 4], 4, 6, 7]) }
13
+ end
14
+
3
15
  context 'condition as symbol' do
4
16
  subject { Fear.case(:even?) { |x| x } }
5
17
 
6
- it 'converted to proc' do
7
- is_expected.to be_defined_at(4)
18
+ it 'matches against the same symbol' do
19
+ is_expected.to be_defined_at(:even?)
8
20
  is_expected.not_to be_defined_at(3)
9
21
  end
10
22
  end
@@ -28,7 +40,7 @@ RSpec.describe Fear::PartialFunction do
28
40
  end
29
41
 
30
42
  context 'multiple condition' do
31
- subject { Fear.case(Integer, :even?, ->(x) { x % 3 == 0 }) { |x| x } }
43
+ subject { Fear.case(Integer, :even?.to_proc, ->(x) { x % 3 == 0 }) { |x| x } }
32
44
 
33
45
  it do
34
46
  is_expected.to be_defined_at(12)
@@ -93,6 +105,16 @@ RSpec.describe Fear::PartialFunction do
93
105
 
94
106
  it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 0') }
95
107
  end
108
+
109
+ context 'defined and condition is extractor' do
110
+ subject { partial_function.call([1, 2, 3, 4, 5]) }
111
+
112
+ let(:partial_function) do
113
+ Fear.xcase('[1, second, 3, *rest]') { |second:, rest:| [second, rest] }
114
+ end
115
+
116
+ it { is_expected.to eq([2, [4, 5]]) }
117
+ end
96
118
  end
97
119
 
98
120
  describe '#to_proc', '#call' do
@@ -1,5 +1,37 @@
1
1
  RSpec.describe Fear::PatternMatch do
2
- include Fear::Option::Mixin
2
+ context 'extracting' do
3
+ let(:matcher) do
4
+ described_class.new do |m|
5
+ m.xcase('Date(year, 2, 29)', ->(year:) { year < 2000 }) do |year:|
6
+ "#{year} is a leap year before Millennium"
7
+ end
8
+ m.xcase('Date(year, 2, 29)') do |year:|
9
+ "#{year} is a leap year after Millennium"
10
+ end
11
+ m.case(Date) do |date|
12
+ "#{date.year} is not a leap year"
13
+ end
14
+ end
15
+ end
16
+
17
+ context 'before Millennium' do
18
+ subject { matcher.call(Date.parse('1996-02-29')) }
19
+
20
+ it { is_expected.to eq('1996 is a leap year before Millennium') }
21
+ end
22
+
23
+ context 'after Millennium' do
24
+ subject { matcher.call(Date.parse('2004-02-29')) }
25
+
26
+ it { is_expected.to eq('2004 is a leap year after Millennium') }
27
+ end
28
+
29
+ context 'not leap' do
30
+ subject { matcher.call(Date.parse('2003-01-24')) }
31
+
32
+ it { is_expected.to eq('2003 is not a leap year') }
33
+ end
34
+ end
3
35
 
4
36
  context 'else at the end' do
5
37
  let(:matcher) do
@@ -0,0 +1,94 @@
1
+ RSpec.describe Fear::Promise do
2
+ let(:value) { 42 }
3
+ let(:error) { StandardError.new('something went wrong') }
4
+
5
+ def not_completed_promise
6
+ Fear::Promise.new(executor: Concurrent::ImmediateExecutor.new)
7
+ end
8
+
9
+ context 'not completed' do
10
+ it '#success! returns self' do
11
+ completed_promise = not_completed_promise.success!(value)
12
+
13
+ expect(completed_promise).to eq completed_promise
14
+ end
15
+
16
+ it '#success returns true' do
17
+ completed = not_completed_promise.success(value)
18
+
19
+ expect(completed).to be true
20
+ end
21
+
22
+ it '#failure! returns self' do
23
+ completed_promise = not_completed_promise.failure!(error)
24
+
25
+ expect(completed_promise).to eq completed_promise
26
+ end
27
+
28
+ it '#failure returns true' do
29
+ completed = not_completed_promise.failure(error)
30
+
31
+ expect(completed).to be true
32
+ end
33
+
34
+ it '#completed? returns true' do
35
+ expect(not_completed_promise).not_to be_completed
36
+ end
37
+
38
+ it '#future returns not completed future' do
39
+ future = not_completed_promise.to_future
40
+
41
+ expect(future).not_to be_completed
42
+ end
43
+ end
44
+
45
+ context 'completed' do
46
+ def completed_promise
47
+ not_completed_promise.success!(value)
48
+ end
49
+
50
+ it '#success! fails with exception' do
51
+ expect do
52
+ completed_promise.success!(value)
53
+ end.to raise_exception(Fear::IllegalStateException)
54
+ end
55
+
56
+ it '#success returns false' do
57
+ completed = completed_promise.success(value)
58
+
59
+ expect(completed).to be false
60
+ end
61
+
62
+ it '#failure! fails with exception' do
63
+ expect do
64
+ completed_promise.failure!(error)
65
+ end.to raise_exception(Fear::IllegalStateException)
66
+ end
67
+
68
+ it '#failure returns false' do
69
+ completed = completed_promise.success(error)
70
+
71
+ expect(completed).to be false
72
+ end
73
+
74
+ it '#completed? returns true' do
75
+ expect(completed_promise).to be_completed
76
+ end
77
+
78
+ context '#future' do
79
+ subject(:future) do
80
+ completed_promise.to_future
81
+ end
82
+
83
+ it 'is completed' do
84
+ expect(future).to be_completed
85
+ end
86
+
87
+ it 'completed with value' do
88
+ future_value = future.value
89
+
90
+ expect(future_value).to eq Fear.some(Fear.success(value))
91
+ end
92
+ end
93
+ end
94
+ end