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
@@ -1,76 +1,78 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Fear::Right do
2
4
  it_behaves_like Fear::RightBiased::Right do
3
- let(:right) { Right('value') }
5
+ let(:right) { Fear.right("value") }
4
6
  end
5
7
 
6
- let(:right) { Right('value') }
8
+ let(:right) { Fear.right("value") }
7
9
 
8
- describe '#right?' do
10
+ describe "#right?" do
9
11
  subject { right }
10
12
  it { is_expected.to be_right }
11
13
  end
12
14
 
13
- describe '#left?' do
15
+ describe "#left?" do
14
16
  subject { right }
15
17
  it { is_expected.not_to be_left }
16
18
  end
17
19
 
18
- describe '#select_or_else' do
20
+ describe "#select_or_else" do
19
21
  subject { right.select_or_else(default, &predicate) }
20
22
 
21
- context 'predicate evaluates to true' do
22
- let(:predicate) { ->(v) { v == 'value' } }
23
+ context "predicate evaluates to true" do
24
+ let(:predicate) { ->(v) { v == "value" } }
23
25
  let(:default) { -1 }
24
26
  it { is_expected.to eq(right) }
25
27
  end
26
28
 
27
- context 'predicate evaluates to false and default is a proc' do
28
- let(:predicate) { ->(v) { v != 'value' } }
29
+ context "predicate evaluates to false and default is a proc" do
30
+ let(:predicate) { ->(v) { v != "value" } }
29
31
  let(:default) { -> { -1 } }
30
- it { is_expected.to eq(Left(-1)) }
32
+ it { is_expected.to eq(Fear.left(-1)) }
31
33
  end
32
34
 
33
- context 'predicate evaluates to false and default is not a proc' do
34
- let(:predicate) { ->(v) { v != 'value' } }
35
+ context "predicate evaluates to false and default is not a proc" do
36
+ let(:predicate) { ->(v) { v != "value" } }
35
37
  let(:default) { -1 }
36
- it { is_expected.to eq(Left(-1)) }
38
+ it { is_expected.to eq(Fear.left(-1)) }
37
39
  end
38
40
  end
39
41
 
40
- describe '#select' do
42
+ describe "#select" do
41
43
  subject { right.select(&predicate) }
42
44
 
43
- context 'predicate evaluates to true' do
44
- let(:predicate) { ->(v) { v == 'value' } }
45
+ context "predicate evaluates to true" do
46
+ let(:predicate) { ->(v) { v == "value" } }
45
47
  it { is_expected.to eq(right) }
46
48
  end
47
49
 
48
- context 'predicate evaluates to false' do
49
- let(:predicate) { ->(v) { v != 'value' } }
50
- it { is_expected.to eq(Left('value')) }
50
+ context "predicate evaluates to false" do
51
+ let(:predicate) { ->(v) { v != "value" } }
52
+ it { is_expected.to eq(Fear.left("value")) }
51
53
  end
52
54
  end
53
55
 
54
- describe '#reject' do
56
+ describe "#reject" do
55
57
  subject { right.reject(&predicate) }
56
58
 
57
- context 'predicate evaluates to true' do
58
- let(:predicate) { ->(v) { v == 'value' } }
59
- it { is_expected.to eq(Left('value')) }
59
+ context "predicate evaluates to true" do
60
+ let(:predicate) { ->(v) { v == "value" } }
61
+ it { is_expected.to eq(Fear.left("value")) }
60
62
  end
61
63
 
62
- context 'predicate evaluates to false' do
63
- let(:predicate) { ->(v) { v != 'value' } }
64
+ context "predicate evaluates to false" do
65
+ let(:predicate) { ->(v) { v != "value" } }
64
66
  it { is_expected.to eq(right) }
65
67
  end
66
68
  end
67
69
 
68
- describe '#swap' do
70
+ describe "#swap" do
69
71
  subject { right.swap }
70
- it { is_expected.to eq(Left('value')) }
72
+ it { is_expected.to eq(Fear.left("value")) }
71
73
  end
72
74
 
73
- describe '#reduce' do
75
+ describe "#reduce" do
74
76
  subject do
75
77
  right.reduce(
76
78
  ->(left) { "Left: #{left}" },
@@ -78,40 +80,106 @@ RSpec.describe Fear::Right do
78
80
  )
79
81
  end
80
82
 
81
- it { is_expected.to eq('Right: value') }
83
+ it { is_expected.to eq("Right: value") }
82
84
  end
83
85
 
84
- describe '#join_right' do
85
- context 'value is Either' do
86
+ describe "#join_right" do
87
+ context "value is Either" do
86
88
  subject { described_class.new(value).join_right }
87
- let(:value) { Left('error') }
89
+ let(:value) { Fear.left("error") }
88
90
 
89
- it 'returns value' do
91
+ it "returns value" do
90
92
  is_expected.to eq(value)
91
93
  end
92
94
  end
93
95
 
94
- context 'value is not Either' do
95
- subject { proc { described_class.new('35').join_right } }
96
+ context "value is not Either" do
97
+ subject { proc { described_class.new("35").join_right } }
96
98
 
97
- it 'fails with type error' do
99
+ it "fails with type error" do
98
100
  is_expected.to raise_error(TypeError)
99
101
  end
100
102
  end
101
103
  end
102
104
 
103
- describe '#join_left' do
104
- context 'value is Either' do
105
+ describe "#join_left" do
106
+ context "value is Either" do
105
107
  subject { either.join_left }
106
- let(:either) { described_class.new(Left('error')) }
108
+ let(:either) { described_class.new(Fear.left("error")) }
107
109
 
108
110
  it { is_expected.to eq(either) }
109
111
  end
110
112
 
111
- context 'value is not Either' do
113
+ context "value is not Either" do
112
114
  subject { either.join_left }
113
- let(:either) { described_class.new('result') }
115
+ let(:either) { described_class.new("result") }
114
116
  it { is_expected.to eq(either) }
115
117
  end
116
118
  end
119
+
120
+ describe "#match" do
121
+ context "matched" do
122
+ subject do
123
+ right.match do |m|
124
+ m.right(->(x) { x.length < 2 }) { |x| "Right: #{x}" }
125
+ m.right(->(x) { x.length > 2 }) { |x| "Right: #{x}" }
126
+ m.left(->(x) { x.length > 2 }) { |x| "Left: #{x}" }
127
+ end
128
+ end
129
+
130
+ it { is_expected.to eq("Right: value") }
131
+ end
132
+
133
+ context "nothing matched and no else given" do
134
+ subject do
135
+ proc do
136
+ right.match do |m|
137
+ m.right(->(x) { x.length < 2 }) { |x| "Right: #{x}" }
138
+ m.left { |_| "noop" }
139
+ end
140
+ end
141
+ end
142
+
143
+ it { is_expected.to raise_error(Fear::MatchError) }
144
+ end
145
+
146
+ context "nothing matched and else given" do
147
+ subject do
148
+ right.match do |m|
149
+ m.right(->(x) { x.length < 2 }) { |x| "Right: #{x}" }
150
+ m.else { :default }
151
+ end
152
+ end
153
+
154
+ it { is_expected.to eq(:default) }
155
+ end
156
+ end
157
+
158
+ describe "#to_s" do
159
+ subject { right.to_s }
160
+
161
+ it { is_expected.to eq('#<Fear::Right value="value">') }
162
+ end
163
+
164
+ describe "pattern matching" do
165
+ subject { Fear.xcase("Right(v : Integer)") { |v:| "matched #{v}" }.call_or_else(var) { "nothing" } }
166
+
167
+ context "right of int" do
168
+ let(:var) { Fear.right(42) }
169
+
170
+ it { is_expected.to eq("matched 42") }
171
+ end
172
+
173
+ context "right of string" do
174
+ let(:var) { Fear.right("42") }
175
+
176
+ it { is_expected.to eq("nothing") }
177
+ end
178
+
179
+ context "not right" do
180
+ let(:var) { "42" }
181
+
182
+ it { is_expected.to eq("nothing") }
183
+ end
184
+ end
117
185
  end
@@ -1,52 +1,117 @@
1
- RSpec.describe Fear::Some do
2
- include Fear::Option::Mixin
1
+ # frozen_string_literal: true
3
2
 
3
+ RSpec.describe Fear::Some do
4
4
  it_behaves_like Fear::RightBiased::Right do
5
- let(:right) { Some('value') }
5
+ let(:right) { Fear.some("value") }
6
6
  end
7
7
 
8
- subject(:some) { Some(42) }
8
+ subject(:some) { Fear.some(42) }
9
9
 
10
- describe '#select' do
10
+ describe "#select" do
11
11
  subject { some.select(&predicate) }
12
12
 
13
- context 'predicate evaluates to true' do
13
+ context "predicate evaluates to true" do
14
14
  let(:predicate) { ->(v) { v > 40 } }
15
15
  it { is_expected.to eq(some) }
16
16
  end
17
17
 
18
- context 'predicate evaluates to false' do
18
+ context "predicate evaluates to false" do
19
19
  let(:predicate) { ->(v) { v < 40 } }
20
- it { is_expected.to eq(None()) }
20
+ it { is_expected.to eq(Fear.none) }
21
21
  end
22
22
  end
23
23
 
24
- describe '#reject' do
24
+ describe "#reject" do
25
25
  subject { some.reject(&predicate) }
26
26
 
27
- context 'predicate evaluates to true' do
27
+ context "predicate evaluates to true" do
28
28
  let(:predicate) { ->(v) { v > 40 } }
29
- it { is_expected.to eq(None()) }
29
+ it { is_expected.to eq(Fear.none) }
30
30
  end
31
31
 
32
- context 'predicate evaluates to false' do
32
+ context "predicate evaluates to false" do
33
33
  let(:predicate) { ->(v) { v < 40 } }
34
34
  it { is_expected.to eq(some) }
35
35
  end
36
36
  end
37
37
 
38
- describe '#get' do
38
+ describe "#get" do
39
39
  subject { some.get }
40
40
  it { is_expected.to eq(42) }
41
41
  end
42
42
 
43
- describe '#or_nil' do
43
+ describe "#or_nil" do
44
44
  subject { some.or_nil }
45
45
  it { is_expected.to eq(42) }
46
46
  end
47
47
 
48
- describe '#empty?' do
48
+ describe "#empty?" do
49
49
  subject { some.empty? }
50
50
  it { is_expected.to eq(false) }
51
51
  end
52
+
53
+ describe "#match" do
54
+ context "matched" do
55
+ subject do
56
+ some.match do |m|
57
+ m.some(->(x) { x > 2 }) { |x| x * 2 }
58
+ m.none { "noop" }
59
+ end
60
+ end
61
+
62
+ it { is_expected.to eq(84) }
63
+ end
64
+
65
+ context "nothing matched and no else given" do
66
+ subject do
67
+ proc do
68
+ some.match do |m|
69
+ m.some(->(x) { x < 2 }) { |x| x * 2 }
70
+ m.none { "noop" }
71
+ end
72
+ end
73
+ end
74
+
75
+ it { is_expected.to raise_error(Fear::MatchError) }
76
+ end
77
+
78
+ context "nothing matched and else given" do
79
+ subject do
80
+ some.match do |m|
81
+ m.none { |x| x * 2 }
82
+ m.else { :default }
83
+ end
84
+ end
85
+
86
+ it { is_expected.to eq(:default) }
87
+ end
88
+ end
89
+
90
+ describe "#to_s" do
91
+ subject { some.to_s }
92
+
93
+ it { is_expected.to eq("#<Fear::Some get=42>") }
94
+ end
95
+
96
+ describe "pattern matching" do
97
+ subject { Fear.xcase("Some(v : Integer)") { |v:| "matched #{v}" }.call_or_else(var) { "nothing" } }
98
+
99
+ context "some of int" do
100
+ let(:var) { Fear.some(42) }
101
+
102
+ it { is_expected.to eq("matched 42") }
103
+ end
104
+
105
+ context "some of string" do
106
+ let(:var) { Fear.some("42") }
107
+
108
+ it { is_expected.to eq("nothing") }
109
+ end
110
+
111
+ context "not some" do
112
+ let(:var) { "42" }
113
+
114
+ it { is_expected.to eq("nothing") }
115
+ end
116
+ end
52
117
  end
@@ -1,93 +1,160 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Fear::Success do
2
- let(:success) { Success('value') }
4
+ let(:success) { Fear.success("value") }
3
5
 
4
6
  it_behaves_like Fear::RightBiased::Right do
5
7
  let(:right) { success }
6
8
 
7
- describe '#map', 'block fails' do
8
- subject(:map) { right.map { fail 'unexpected error' } }
9
+ describe "#map", "block fails" do
10
+ subject(:map) { right.map { raise "unexpected error" } }
9
11
 
10
12
  it { is_expected.to be_kind_of(Fear::Failure) }
11
- it { expect { map.get }.to raise_error(RuntimeError, 'unexpected error') }
13
+ it { expect { map.get }.to raise_error(RuntimeError, "unexpected error") }
12
14
  end
13
15
 
14
- describe '#flat_map', 'block fails' do
15
- subject(:flat_map) { right.flat_map { fail 'unexpected error' } }
16
+ describe "#flat_map", "block fails" do
17
+ subject(:flat_map) { right.flat_map { raise "unexpected error" } }
16
18
 
17
19
  it { is_expected.to be_kind_of(Fear::Failure) }
18
- it { expect { flat_map.get }.to raise_error(RuntimeError, 'unexpected error') }
20
+ it { expect { flat_map.get }.to raise_error(RuntimeError, "unexpected error") }
19
21
  end
20
22
  end
21
23
 
22
- describe '#get' do
24
+ describe "#get" do
23
25
  subject { success.get }
24
- it { is_expected.to eq('value') }
26
+ it { is_expected.to eq("value") }
25
27
  end
26
28
 
27
- describe '#success?' do
29
+ describe "#success?" do
28
30
  subject { success }
29
31
  it { is_expected.to be_success }
30
32
  end
31
33
 
32
- describe '#failure?' do
34
+ describe "#failure?" do
33
35
  subject { success }
34
36
  it { is_expected.not_to be_failure }
35
37
  end
36
38
 
37
- describe '#or_else' do
38
- subject { success.or_else { described_class.new('another value') } }
39
+ describe "#or_else" do
40
+ subject { success.or_else { described_class.new("another value") } }
39
41
  it { is_expected.to eq(success) }
40
42
  end
41
43
 
42
- describe '#flatten' do
44
+ describe "#flatten" do
43
45
  subject { described_class.new(value).flatten }
44
46
 
45
- context 'value is a Success' do
47
+ context "value is a Success" do
46
48
  let(:value) { described_class.new(42) }
47
49
  it { is_expected.to eq(described_class.new(42)) }
48
50
  end
49
51
 
50
- context 'value is a Success of Success' do
52
+ context "value is a Success of Success" do
51
53
  let(:value) { described_class.new(described_class.new(42)) }
52
54
  it { is_expected.to eq(described_class.new(42)) }
53
55
  end
54
56
 
55
- context 'value is a Success of Failure' do
57
+ context "value is a Success of Failure" do
56
58
  let(:failure) { Fear::Failure.new(RuntimeError.new) }
57
59
  let(:value) { described_class.new(failure) }
58
60
  it { is_expected.to eq(failure) }
59
61
  end
60
62
  end
61
63
 
62
- describe '#select' do
63
- context 'predicate holds for value' do
64
- subject { success.select { |v| v == 'value' } }
64
+ describe "#select" do
65
+ context "predicate holds for value" do
66
+ subject { success.select { |v| v == "value" } }
65
67
  it { is_expected.to eq(success) }
66
68
  end
67
69
 
68
- context 'predicate does not hold for value' do
69
- subject { proc { success.select { |v| v != 'value' }.get } }
70
- it { is_expected.to raise_error(Fear::NoSuchElementError, 'Predicate does not hold for `value`') }
70
+ context "predicate does not hold for value" do
71
+ subject { proc { success.select { |v| v != "value" }.get } }
72
+ it { is_expected.to raise_error(Fear::NoSuchElementError, "Predicate does not hold for `value`") }
71
73
  end
72
74
 
73
- context 'predicate fails with error' do
74
- subject { proc { success.select { fail 'foo' }.get } }
75
- it { is_expected.to raise_error(RuntimeError, 'foo') }
75
+ context "predicate fails with error" do
76
+ subject { proc { success.select { raise "foo" }.get } }
77
+ it { is_expected.to raise_error(RuntimeError, "foo") }
76
78
  end
77
79
  end
78
80
 
79
- describe '#recover_with' do
80
- subject { success.recover_with { |v| Success(v * 2) } }
81
+ describe "#recover_with" do
82
+ subject { success.recover_with { |v| Fear.success(v * 2) } }
81
83
  it { is_expected.to eq(success) }
82
84
  end
83
85
 
84
- describe '#recover' do
85
- subject { success.recover { |v| v * 2 } }
86
+ describe "#recover" do
87
+ subject { success.recover { |m| m.case { |v| v * 2 } } }
86
88
  it { is_expected.to eq(success) }
87
89
  end
88
90
 
89
- describe '#to_either' do
91
+ describe "#to_either" do
90
92
  subject { success.to_either }
91
- it { is_expected.to eq(Right('value')) }
93
+ it { is_expected.to eq(Fear.right("value")) }
94
+ end
95
+
96
+ describe "#match" do
97
+ context "matched" do
98
+ subject do
99
+ success.match do |m|
100
+ m.success(->(x) { x.length > 2 }) { |x| x * 2 }
101
+ m.failure { "noop" }
102
+ end
103
+ end
104
+
105
+ it { is_expected.to eq("valuevalue") }
106
+ end
107
+
108
+ context "nothing matched and no else given" do
109
+ subject do
110
+ proc do
111
+ success.match do |m|
112
+ m.success(->(x) { x.length < 2 }) { |x| x * 2 }
113
+ m.failure { "noop" }
114
+ end
115
+ end
116
+ end
117
+
118
+ it { is_expected.to raise_error(Fear::MatchError) }
119
+ end
120
+
121
+ context "nothing matched and else given" do
122
+ subject do
123
+ success.match do |m|
124
+ m.failure { |x| x * 2 }
125
+ m.else { :default }
126
+ end
127
+ end
128
+
129
+ it { is_expected.to eq(:default) }
130
+ end
131
+ end
132
+
133
+ describe "#to_s" do
134
+ subject { success.to_s }
135
+
136
+ it { is_expected.to eq('#<Fear::Success value="value">') }
137
+ end
138
+
139
+ describe "pattern matching" do
140
+ subject { Fear.xcase("Success(v : Integer)") { |v:| "matched #{v}" }.call_or_else(var) { "nothing" } }
141
+
142
+ context "success of int" do
143
+ let(:var) { Fear.success(42) }
144
+
145
+ it { is_expected.to eq("matched 42") }
146
+ end
147
+
148
+ context "success of string" do
149
+ let(:var) { Fear.success("42") }
150
+
151
+ it { is_expected.to eq("nothing") }
152
+ end
153
+
154
+ context "not success" do
155
+ let(:var) { "42" }
156
+
157
+ it { is_expected.to eq("nothing") }
158
+ end
92
159
  end
93
160
  end