fear 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +27 -0
  3. data/.github/workflows/rubocop.yml +39 -0
  4. data/.github/workflows/spec.yml +42 -0
  5. data/.rubocop.yml +4 -60
  6. data/.simplecov +17 -0
  7. data/CHANGELOG.md +29 -1
  8. data/Gemfile +5 -5
  9. data/Gemfile.lock +86 -50
  10. data/README.md +240 -209
  11. data/Rakefile +72 -65
  12. data/examples/pattern_extracting.rb +10 -8
  13. data/examples/pattern_matching_binary_tree_set.rb +7 -2
  14. data/examples/pattern_matching_number_in_words.rb +48 -42
  15. data/fear.gemspec +33 -34
  16. data/lib/dry/types/fear/option.rb +125 -0
  17. data/lib/dry/types/fear.rb +8 -0
  18. data/lib/fear/await.rb +33 -0
  19. data/lib/fear/awaitable.rb +28 -0
  20. data/lib/fear/either.rb +15 -4
  21. data/lib/fear/either_api.rb +4 -0
  22. data/lib/fear/either_pattern_match.rb +9 -5
  23. data/lib/fear/empty_partial_function.rb +3 -1
  24. data/lib/fear/failure.rb +7 -7
  25. data/lib/fear/failure_pattern_match.rb +4 -0
  26. data/lib/fear/for.rb +4 -2
  27. data/lib/fear/for_api.rb +5 -1
  28. data/lib/fear/future.rb +157 -82
  29. data/lib/fear/future_api.rb +17 -4
  30. data/lib/fear/left.rb +3 -9
  31. data/lib/fear/left_pattern_match.rb +2 -0
  32. data/lib/fear/none.rb +28 -10
  33. data/lib/fear/none_pattern_match.rb +2 -0
  34. data/lib/fear/option.rb +30 -2
  35. data/lib/fear/option_api.rb +4 -0
  36. data/lib/fear/option_pattern_match.rb +8 -3
  37. data/lib/fear/partial_function/and_then.rb +4 -2
  38. data/lib/fear/partial_function/any.rb +2 -0
  39. data/lib/fear/partial_function/combined.rb +3 -1
  40. data/lib/fear/partial_function/empty.rb +6 -0
  41. data/lib/fear/partial_function/guard/and.rb +2 -0
  42. data/lib/fear/partial_function/guard/and3.rb +2 -0
  43. data/lib/fear/partial_function/guard/or.rb +2 -0
  44. data/lib/fear/partial_function/guard.rb +8 -6
  45. data/lib/fear/partial_function/lifted.rb +2 -0
  46. data/lib/fear/partial_function/or_else.rb +5 -1
  47. data/lib/fear/partial_function.rb +18 -9
  48. data/lib/fear/partial_function_class.rb +3 -1
  49. data/lib/fear/pattern_match.rb +3 -11
  50. data/lib/fear/pattern_matching_api.rb +6 -28
  51. data/lib/fear/promise.rb +7 -5
  52. data/lib/fear/right.rb +3 -9
  53. data/lib/fear/right_biased.rb +5 -3
  54. data/lib/fear/right_pattern_match.rb +4 -0
  55. data/lib/fear/some.rb +35 -8
  56. data/lib/fear/some_pattern_match.rb +2 -0
  57. data/lib/fear/struct.rb +237 -0
  58. data/lib/fear/success.rb +7 -8
  59. data/lib/fear/success_pattern_match.rb +4 -0
  60. data/lib/fear/try.rb +8 -2
  61. data/lib/fear/try_api.rb +4 -0
  62. data/lib/fear/try_pattern_match.rb +9 -5
  63. data/lib/fear/unit.rb +6 -2
  64. data/lib/fear/utils.rb +14 -2
  65. data/lib/fear/version.rb +4 -1
  66. data/lib/fear.rb +26 -44
  67. data/spec/dry/types/fear/option/constrained_spec.rb +22 -0
  68. data/spec/dry/types/fear/option/core_spec.rb +77 -0
  69. data/spec/dry/types/fear/option/default_spec.rb +21 -0
  70. data/spec/dry/types/fear/option/hash_spec.rb +58 -0
  71. data/spec/dry/types/fear/option/option_spec.rb +97 -0
  72. data/spec/fear/awaitable_spec.rb +19 -0
  73. data/spec/fear/done_spec.rb +7 -5
  74. data/spec/fear/either/mixin_spec.rb +4 -2
  75. data/spec/fear/either_pattern_match_spec.rb +10 -8
  76. data/spec/fear/either_pattern_matching_spec.rb +28 -0
  77. data/spec/fear/either_spec.rb +26 -0
  78. data/spec/fear/failure_spec.rb +57 -70
  79. data/spec/fear/for/mixin_spec.rb +15 -0
  80. data/spec/fear/for_spec.rb +19 -17
  81. data/spec/fear/future_spec.rb +477 -237
  82. data/spec/fear/guard_spec.rb +136 -24
  83. data/spec/fear/left_spec.rb +57 -70
  84. data/spec/fear/none_spec.rb +39 -43
  85. data/spec/fear/option/mixin_spec.rb +9 -7
  86. data/spec/fear/option_pattern_match_spec.rb +10 -8
  87. data/spec/fear/option_pattern_matching_spec.rb +34 -0
  88. data/spec/fear/option_spec.rb +142 -0
  89. data/spec/fear/partial_function/any_spec.rb +25 -0
  90. data/spec/fear/partial_function/empty_spec.rb +12 -10
  91. data/spec/fear/partial_function_and_then_spec.rb +39 -37
  92. data/spec/fear/partial_function_composition_spec.rb +46 -44
  93. data/spec/fear/partial_function_or_else_spec.rb +92 -90
  94. data/spec/fear/partial_function_spec.rb +91 -61
  95. data/spec/fear/pattern_match_spec.rb +19 -51
  96. data/spec/fear/pattern_matching_api_spec.rb +31 -0
  97. data/spec/fear/promise_spec.rb +23 -23
  98. data/spec/fear/right_biased/left.rb +28 -26
  99. data/spec/fear/right_biased/right.rb +51 -49
  100. data/spec/fear/right_spec.rb +48 -68
  101. data/spec/fear/some_spec.rb +30 -40
  102. data/spec/fear/success_spec.rb +40 -60
  103. data/spec/fear/try/mixin_spec.rb +19 -3
  104. data/spec/fear/try_api_spec.rb +23 -0
  105. data/spec/fear/try_pattern_match_spec.rb +10 -8
  106. data/spec/fear/try_pattern_matching_spec.rb +34 -0
  107. data/spec/fear/utils_spec.rb +16 -14
  108. data/spec/spec_helper.rb +13 -7
  109. data/spec/struct_pattern_matching_spec.rb +36 -0
  110. data/spec/struct_spec.rb +194 -0
  111. data/spec/support/dry_types.rb +6 -0
  112. metadata +128 -87
  113. data/.travis.yml +0 -13
  114. data/lib/fear/extractor/anonymous_array_splat_matcher.rb +0 -8
  115. data/lib/fear/extractor/any_matcher.rb +0 -15
  116. data/lib/fear/extractor/array_head_matcher.rb +0 -34
  117. data/lib/fear/extractor/array_matcher.rb +0 -38
  118. data/lib/fear/extractor/array_splat_matcher.rb +0 -14
  119. data/lib/fear/extractor/empty_list_matcher.rb +0 -18
  120. data/lib/fear/extractor/extractor_matcher.rb +0 -42
  121. data/lib/fear/extractor/grammar.rb +0 -201
  122. data/lib/fear/extractor/grammar.treetop +0 -129
  123. data/lib/fear/extractor/identifier_matcher.rb +0 -16
  124. data/lib/fear/extractor/matcher/and.rb +0 -36
  125. data/lib/fear/extractor/matcher.rb +0 -54
  126. data/lib/fear/extractor/named_array_splat_matcher.rb +0 -15
  127. data/lib/fear/extractor/pattern.rb +0 -55
  128. data/lib/fear/extractor/typed_identifier_matcher.rb +0 -24
  129. data/lib/fear/extractor/value_matcher.rb +0 -17
  130. data/lib/fear/extractor.rb +0 -108
  131. data/lib/fear/extractor_api.rb +0 -33
  132. data/spec/fear/extractor/array_matcher_spec.rb +0 -228
  133. data/spec/fear/extractor/extractor_matcher_spec.rb +0 -151
  134. data/spec/fear/extractor/grammar_array_spec.rb +0 -23
  135. data/spec/fear/extractor/identified_matcher_spec.rb +0 -47
  136. data/spec/fear/extractor/identifier_matcher_spec.rb +0 -66
  137. data/spec/fear/extractor/pattern_spec.rb +0 -32
  138. data/spec/fear/extractor/typed_identifier_matcher_spec.rb +0 -62
  139. data/spec/fear/extractor/value_matcher_number_spec.rb +0 -77
  140. data/spec/fear/extractor/value_matcher_string_spec.rb +0 -86
  141. data/spec/fear/extractor/value_matcher_symbol_spec.rb +0 -69
  142. data/spec/fear/extractor_api_spec.rb +0 -113
  143. data/spec/fear/extractor_spec.rb +0 -59
@@ -1,273 +1,275 @@
1
- RSpec.describe Fear::PartialFunction, '#or_else' do
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Fear::PartialFunction, "#or_else" do
2
4
  subject(:first_or_else_second) { first.or_else(second) }
3
5
 
4
6
  let(:first) { Fear.case(->(x) { x.even? }) { |x| "first: #{x}" } }
5
7
  let(:second) { Fear.case(->(x) { x % 3 == 0 }) { |x| "second: #{x}" } }
6
8
 
7
- describe '#defined_at?' do
8
- context 'first defined, second not' do
9
+ describe "#defined_at?" do
10
+ context "first defined, second not" do
9
11
  subject { first_or_else_second.defined_at?(4) }
10
12
 
11
13
  it { is_expected.to eq(true) }
12
14
  end
13
15
 
14
- context 'first not defined, second defined' do
16
+ context "first not defined, second defined" do
15
17
  subject { first_or_else_second.defined_at?(9) }
16
18
 
17
19
  it { is_expected.to eq(true) }
18
20
  end
19
21
 
20
- context 'first not defined, second not defined' do
22
+ context "first not defined, second not defined" do
21
23
  subject { first_or_else_second.defined_at?(5) }
22
24
 
23
25
  it { is_expected.to eq(false) }
24
26
  end
25
27
 
26
- context 'first and second defined' do
28
+ context "first and second defined" do
27
29
  subject { first_or_else_second.defined_at?(6) }
28
30
 
29
31
  it { is_expected.to eq(true) }
30
32
  end
31
33
  end
32
34
 
33
- describe '#call' do
34
- context 'first defined, second not' do
35
- subject { first_or_else_second.call(4) }
35
+ describe "#call" do
36
+ context "first defined, second not" do
37
+ subject { first_or_else_second.(4) }
36
38
 
37
- it { is_expected.to eq('first: 4') }
39
+ it { is_expected.to eq("first: 4") }
38
40
  end
39
41
 
40
- context 'first not defined, second defined' do
41
- subject { first_or_else_second.call(9) }
42
+ context "first not defined, second defined" do
43
+ subject { first_or_else_second.(9) }
42
44
 
43
- it { is_expected.to eq('second: 9') }
45
+ it { is_expected.to eq("second: 9") }
44
46
  end
45
47
 
46
- context 'first not defined, second not defined' do
47
- subject { -> { first_or_else_second.call(5) } }
48
+ context "first not defined, second not defined" do
49
+ subject { -> { first_or_else_second.(5) } }
48
50
 
49
- it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 5') }
51
+ it { is_expected.to raise_error(Fear::MatchError, "partial function not defined at: 5") }
50
52
  end
51
53
 
52
- context 'first and second defined' do
53
- subject { first_or_else_second.call(6) }
54
+ context "first and second defined" do
55
+ subject { first_or_else_second.(6) }
54
56
 
55
- it { is_expected.to eq('first: 6') }
57
+ it { is_expected.to eq("first: 6") }
56
58
  end
57
59
  end
58
60
 
59
- describe '#call_or_else' do
61
+ describe "#call_or_else" do
60
62
  let(:fallback) { ->(x) { "fallback: #{x}" } }
61
63
 
62
- context 'first defined, second not' do
64
+ context "first defined, second not" do
63
65
  subject { first_or_else_second.call_or_else(4, &fallback) }
64
66
 
65
- it { is_expected.to eq('first: 4') }
67
+ it { is_expected.to eq("first: 4") }
66
68
  end
67
69
 
68
- context 'first not defined, second defined' do
70
+ context "first not defined, second defined" do
69
71
  subject { first_or_else_second.call_or_else(9, &fallback) }
70
72
 
71
- it { is_expected.to eq('second: 9') }
73
+ it { is_expected.to eq("second: 9") }
72
74
  end
73
75
 
74
- context 'first not defined, second not defined' do
76
+ context "first not defined, second not defined" do
75
77
  subject { first_or_else_second.call_or_else(5, &fallback) }
76
78
 
77
- it { is_expected.to eq('fallback: 5') }
79
+ it { is_expected.to eq("fallback: 5") }
78
80
  end
79
81
 
80
- context 'first and second defined' do
82
+ context "first and second defined" do
81
83
  subject { first_or_else_second.call_or_else(6, &fallback) }
82
84
 
83
- it { is_expected.to eq('first: 6') }
85
+ it { is_expected.to eq("first: 6") }
84
86
  end
85
87
  end
86
88
 
87
- describe '#or_else' do
89
+ describe "#or_else" do
88
90
  let(:first_or_else_second_or_else_third) { first_or_else_second.or_else(third) }
89
91
  let(:third) { Fear.case(->(x) { x % 7 == 0 }) { |x| "third: #{x}" } }
90
92
 
91
- describe '#defined_at?' do
92
- context 'first defined, second not' do
93
+ describe "#defined_at?" do
94
+ context "first defined, second not" do
93
95
  subject { first_or_else_second_or_else_third.defined_at?(4) }
94
96
 
95
97
  it { is_expected.to eq(true) }
96
98
  end
97
99
 
98
- context 'first not defined, second defined' do
100
+ context "first not defined, second defined" do
99
101
  subject { first_or_else_second_or_else_third.defined_at?(9) }
100
102
 
101
103
  it { is_expected.to eq(true) }
102
104
  end
103
105
 
104
- context 'first not defined, second not defined, third defined' do
106
+ context "first not defined, second not defined, third defined" do
105
107
  subject { first_or_else_second_or_else_third.defined_at?(7) }
106
108
 
107
109
  it { is_expected.to eq(true) }
108
110
  end
109
111
 
110
- context 'first not defined, second not defined, third not defined' do
112
+ context "first not defined, second not defined, third not defined" do
111
113
  subject { first_or_else_second_or_else_third.defined_at?(1) }
112
114
 
113
115
  it { is_expected.to eq(false) }
114
116
  end
115
117
 
116
- context 'first, second and third defined' do
118
+ context "first, second and third defined" do
117
119
  subject { first_or_else_second.defined_at?(42) }
118
120
 
119
121
  it { is_expected.to eq(true) }
120
122
  end
121
123
  end
122
124
 
123
- describe '#call' do
124
- context 'first defined, second not' do
125
- subject { first_or_else_second_or_else_third.call(4) }
125
+ describe "#call" do
126
+ context "first defined, second not" do
127
+ subject { first_or_else_second_or_else_third.(4) }
126
128
 
127
- it { is_expected.to eq('first: 4') }
129
+ it { is_expected.to eq("first: 4") }
128
130
  end
129
131
 
130
- context 'first not defined, second defined' do
131
- subject { first_or_else_second_or_else_third.call(9) }
132
+ context "first not defined, second defined" do
133
+ subject { first_or_else_second_or_else_third.(9) }
132
134
 
133
- it { is_expected.to eq('second: 9') }
135
+ it { is_expected.to eq("second: 9") }
134
136
  end
135
137
 
136
- context 'first not defined, second not defined, third defined' do
137
- subject { first_or_else_second_or_else_third.call(7) }
138
+ context "first not defined, second not defined, third defined" do
139
+ subject { first_or_else_second_or_else_third.(7) }
138
140
 
139
- it { is_expected.to eq('third: 7') }
141
+ it { is_expected.to eq("third: 7") }
140
142
  end
141
143
 
142
- context 'first not defined, second not defined, third not defined' do
143
- subject { -> { first_or_else_second_or_else_third.call(1) } }
144
+ context "first not defined, second not defined, third not defined" do
145
+ subject { -> { first_or_else_second_or_else_third.(1) } }
144
146
 
145
- it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 1') }
147
+ it { is_expected.to raise_error(Fear::MatchError, "partial function not defined at: 1") }
146
148
  end
147
149
 
148
- context 'first, second and third defined' do
149
- subject { first_or_else_second.call(42) }
150
+ context "first, second and third defined" do
151
+ subject { first_or_else_second.(42) }
150
152
 
151
- it { is_expected.to eq('first: 42') }
153
+ it { is_expected.to eq("first: 42") }
152
154
  end
153
155
  end
154
156
 
155
- describe '#call_or_else' do
157
+ describe "#call_or_else" do
156
158
  let(:fallback) { ->(x) { "fallback: #{x}" } }
157
159
 
158
- context 'first defined, second not' do
160
+ context "first defined, second not" do
159
161
  subject { first_or_else_second_or_else_third.call_or_else(4, &fallback) }
160
162
 
161
- it { is_expected.to eq('first: 4') }
163
+ it { is_expected.to eq("first: 4") }
162
164
  end
163
165
 
164
- context 'first not defined, second defined' do
166
+ context "first not defined, second defined" do
165
167
  subject { first_or_else_second_or_else_third.call_or_else(9, &fallback) }
166
168
 
167
- it { is_expected.to eq('second: 9') }
169
+ it { is_expected.to eq("second: 9") }
168
170
  end
169
171
 
170
- context 'first not defined, second not defined, third defined' do
172
+ context "first not defined, second not defined, third defined" do
171
173
  subject { first_or_else_second_or_else_third.call_or_else(7, &fallback) }
172
174
 
173
- it { is_expected.to eq('third: 7') }
175
+ it { is_expected.to eq("third: 7") }
174
176
  end
175
177
 
176
- context 'first not defined, second not defined, third not defined' do
178
+ context "first not defined, second not defined, third not defined" do
177
179
  subject { first_or_else_second_or_else_third.call_or_else(1, &fallback) }
178
180
 
179
- it { is_expected.to eq('fallback: 1') }
181
+ it { is_expected.to eq("fallback: 1") }
180
182
  end
181
183
 
182
- context 'first, second and third defined' do
184
+ context "first, second and third defined" do
183
185
  subject { first_or_else_second_or_else_third.call_or_else(42, &fallback) }
184
186
 
185
- it { is_expected.to eq('first: 42') }
187
+ it { is_expected.to eq("first: 42") }
186
188
  end
187
189
  end
188
190
  end
189
191
 
190
- describe '#and_then' do
192
+ describe "#and_then" do
191
193
  let(:first_or_else_second_and_then_function) { first_or_else_second.and_then(&function) }
192
194
  let(:function) { ->(x) { "f: #{x}" } }
193
195
 
194
- describe '#defined_at?' do
195
- context 'first defined, second not' do
196
+ describe "#defined_at?" do
197
+ context "first defined, second not" do
196
198
  subject { first_or_else_second_and_then_function.defined_at?(2) }
197
199
 
198
200
  it { is_expected.to eq(true) }
199
201
  end
200
202
 
201
- context 'first not defined, second defined' do
203
+ context "first not defined, second defined" do
202
204
  subject { first_or_else_second_and_then_function.defined_at?(3) }
203
205
 
204
206
  it { is_expected.to eq(true) }
205
207
  end
206
208
 
207
- context 'first not defined, second not defined' do
209
+ context "first not defined, second not defined" do
208
210
  subject { first_or_else_second_and_then_function.defined_at?(5) }
209
211
 
210
212
  it { is_expected.to eq(false) }
211
213
  end
212
214
 
213
- context 'first defined, second defined' do
215
+ context "first defined, second defined" do
214
216
  subject { first_or_else_second_and_then_function.defined_at?(6) }
215
217
 
216
218
  it { is_expected.to eq(true) }
217
219
  end
218
220
  end
219
221
 
220
- describe '#call' do
221
- context 'first defined, second not' do
222
- subject { first_or_else_second_and_then_function.call(2) }
222
+ describe "#call" do
223
+ context "first defined, second not" do
224
+ subject { first_or_else_second_and_then_function.(2) }
223
225
 
224
- it { is_expected.to eq('f: first: 2') }
226
+ it { is_expected.to eq("f: first: 2") }
225
227
  end
226
228
 
227
- context 'first not defined, second defined' do
228
- subject { first_or_else_second_and_then_function.call(3) }
229
+ context "first not defined, second defined" do
230
+ subject { first_or_else_second_and_then_function.(3) }
229
231
 
230
- it { is_expected.to eq('f: second: 3') }
232
+ it { is_expected.to eq("f: second: 3") }
231
233
  end
232
234
 
233
- context 'first not defined, second not defined' do
234
- subject { -> { first_or_else_second_and_then_function.call(5) } }
235
+ context "first not defined, second not defined" do
236
+ subject { -> { first_or_else_second_and_then_function.(5) } }
235
237
 
236
- it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 5') }
238
+ it { is_expected.to raise_error(Fear::MatchError, "partial function not defined at: 5") }
237
239
  end
238
240
 
239
- context 'first defined, second defined' do
240
- subject { first_or_else_second_and_then_function.call(6) }
241
+ context "first defined, second defined" do
242
+ subject { first_or_else_second_and_then_function.(6) }
241
243
 
242
- it { is_expected.to eq('f: first: 6') }
244
+ it { is_expected.to eq("f: first: 6") }
243
245
  end
244
246
  end
245
247
 
246
- describe '#call_or_else' do
248
+ describe "#call_or_else" do
247
249
  let(:fallback) { ->(x) { "fallback: #{x}" } }
248
250
 
249
- context 'first defined, second not' do
251
+ context "first defined, second not" do
250
252
  subject { first_or_else_second_and_then_function.call_or_else(2, &fallback) }
251
253
 
252
- it { is_expected.to eq('f: first: 2') }
254
+ it { is_expected.to eq("f: first: 2") }
253
255
  end
254
256
 
255
- context 'first not defined, second defined' do
257
+ context "first not defined, second defined" do
256
258
  subject { first_or_else_second_and_then_function.call_or_else(3, &fallback) }
257
259
 
258
- it { is_expected.to eq('f: second: 3') }
260
+ it { is_expected.to eq("f: second: 3") }
259
261
  end
260
262
 
261
- context 'first not defined, second not defined' do
263
+ context "first not defined, second not defined" do
262
264
  subject { first_or_else_second_and_then_function.call_or_else(5, &fallback) }
263
265
 
264
- it { is_expected.to eq('fallback: 5') }
266
+ it { is_expected.to eq("fallback: 5") }
265
267
  end
266
268
 
267
- context 'first defined, second defined' do
269
+ context "first defined, second defined" do
268
270
  subject { first_or_else_second_and_then_function.call_or_else(6, &fallback) }
269
271
 
270
- it { is_expected.to eq('f: first: 6') }
272
+ it { is_expected.to eq("f: first: 6") }
271
273
  end
272
274
  end
273
275
  end
@@ -1,36 +1,26 @@
1
- RSpec.describe Fear::PartialFunction do
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
1
+ # frozen_string_literal: true
14
2
 
15
- context 'condition as symbol' do
3
+ RSpec.describe Fear::PartialFunction do
4
+ describe "Fear.case()" do
5
+ context "condition as symbol" do
16
6
  subject { Fear.case(:even?) { |x| x } }
17
7
 
18
- it 'matches against the same symbol' do
8
+ it "matches against the same symbol" do
19
9
  is_expected.to be_defined_at(:even?)
20
10
  is_expected.not_to be_defined_at(3)
21
11
  end
22
12
  end
23
13
 
24
- context 'condition as Class' do
14
+ context "condition as Class" do
25
15
  subject { Fear.case(Integer) { |x| x } }
26
16
 
27
17
  it do
28
18
  is_expected.to be_defined_at(4)
29
- is_expected.not_to be_defined_at('3')
19
+ is_expected.not_to be_defined_at("3")
30
20
  end
31
21
  end
32
22
 
33
- context 'condition as Proc' do
23
+ context "condition as Proc" do
34
24
  subject { Fear.case(->(x) { x.even? }) { |x| x } }
35
25
 
36
26
  it do
@@ -39,19 +29,19 @@ RSpec.describe Fear::PartialFunction do
39
29
  end
40
30
  end
41
31
 
42
- context 'multiple condition' do
32
+ context "multiple condition" do
43
33
  subject { Fear.case(Integer, :even?.to_proc, ->(x) { x % 3 == 0 }) { |x| x } }
44
34
 
45
35
  it do
46
36
  is_expected.to be_defined_at(12)
47
37
  is_expected.not_to be_defined_at(12.0)
48
- is_expected.not_to be_defined_at('3')
38
+ is_expected.not_to be_defined_at("3")
49
39
  is_expected.not_to be_defined_at(3)
50
40
  is_expected.not_to be_defined_at(4)
51
41
  end
52
42
  end
53
43
 
54
- context 'multiple condition 2' do
44
+ context "multiple condition 2" do
55
45
  subject { Fear.case(Integer, 4) { |x| x } }
56
46
 
57
47
  it do
@@ -61,127 +51,167 @@ RSpec.describe Fear::PartialFunction do
61
51
  end
62
52
  end
63
53
 
64
- describe '#lift' do
54
+ describe ".or" do
55
+ subject { described_class.or(guard_1, guard_2, &:itself) }
56
+
57
+ let(:guard_1) { ->(x) { x == 42 } }
58
+ let(:guard_2) { ->(x) { x == 21 } }
59
+
60
+ it { is_expected.to be_defined_at(42) }
61
+ it { is_expected.to be_defined_at(21) }
62
+ it { is_expected.not_to be_defined_at(20) }
63
+ end
64
+
65
+ describe ".and" do
66
+ subject { described_class.and(guard_1, guard_2, &:itself) }
67
+
68
+ let(:guard_1) { ->(x) { x % 5 == 0 } }
69
+ let(:guard_2) { ->(x) { x % 2 == 0 } }
70
+
71
+ it { is_expected.to be_defined_at(10) }
72
+ it { is_expected.not_to be_defined_at(5) }
73
+ it { is_expected.not_to be_defined_at(2) }
74
+ it { is_expected.not_to be_defined_at(3) }
75
+ end
76
+
77
+ describe "#lift" do
65
78
  let(:lifted) { partial_function.lift }
66
79
 
67
80
  let(:partial_function) { Fear.case(->(v) { v != 0 }) { |x| 4 / x } }
68
81
 
69
- context 'defined' do
70
- subject { lifted.call(2) }
82
+ context "defined" do
83
+ subject { lifted.(2) }
71
84
 
72
85
  it { is_expected.to eq(Fear::Some.new(2)) }
73
86
  end
74
87
 
75
- context 'not defined' do
76
- subject { lifted.call(0) }
88
+ context "not defined" do
89
+ subject { lifted.(0) }
77
90
 
78
91
  it { is_expected.to eq(Fear::None) }
79
92
  end
80
93
  end
81
94
 
82
- describe '#defined_at?' do
95
+ describe "#defined_at?" do
83
96
  let(:partial_function) { Fear.case(->(v) { v == 42 }) {} }
84
97
 
85
- it 'defined at' do
98
+ it "defined at" do
86
99
  expect(partial_function.defined_at?(42)).to eq(true)
87
100
  end
88
101
 
89
- it 'not defined at' do
102
+ it "not defined at" do
90
103
  expect(partial_function.defined_at?(24)).to eq(false)
91
104
  end
92
105
  end
93
106
 
94
- describe '#call' do
107
+ describe "#call" do
95
108
  let(:partial_function) { Fear.case(->(v) { v != 0 }) { |x| 4 / x } }
96
109
 
97
- context 'defined' do
98
- subject { partial_function.call(2) }
110
+ context "defined" do
111
+ subject { partial_function.(2) }
99
112
 
100
113
  it { is_expected.to eq(2) }
101
114
  end
102
115
 
103
- context 'not defined' do
104
- subject { -> { partial_function.call(0) } }
116
+ context "not defined" do
117
+ subject { -> { partial_function.(0) } }
105
118
 
106
- it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 0') }
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]]) }
119
+ it { is_expected.to raise_error(Fear::MatchError, "partial function not defined at: 0") }
117
120
  end
118
121
  end
119
122
 
120
- describe '#to_proc', '#call' do
123
+ describe "#to_proc", "#call" do
121
124
  let(:partial_function) { Fear.case(->(v) { v != 0 }) { |x| 4 / x }.to_proc }
122
125
 
123
- context 'defined' do
124
- subject { partial_function.call(2) }
126
+ context "defined" do
127
+ subject { partial_function.(2) }
125
128
 
126
129
  it { is_expected.to eq(2) }
127
130
  end
128
131
 
129
- context 'not defined' do
130
- subject { -> { partial_function.call(0) } }
132
+ context "not defined" do
133
+ subject { -> { partial_function.(0) } }
131
134
 
132
- it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 0') }
135
+ it { is_expected.to raise_error(Fear::MatchError, "partial function not defined at: 0") }
133
136
  end
134
137
  end
135
138
 
136
- describe '#call_or_else' do
139
+ describe "#call_or_else" do
137
140
  let(:default) { ->(x) { "division by #{x} impossible" } }
138
141
  let(:partial_function) { Fear.case(->(x) { x != 0 }) { |x| 4 / x } }
139
142
 
140
- context 'defined' do
143
+ context "defined" do
141
144
  subject { partial_function.call_or_else(2, &default) }
142
145
 
143
146
  it { is_expected.to eq(2) }
144
147
  end
145
148
 
146
- context 'not defined' do
149
+ context "not defined" do
147
150
  subject { partial_function.call_or_else(0, &default) }
148
151
 
149
- it { is_expected.to eq('division by 0 impossible') }
152
+ it { is_expected.to eq("division by 0 impossible") }
150
153
  end
151
154
  end
152
155
 
153
- describe '#and_then' do
156
+ describe "#and_then" do
154
157
  let(:partial_function) { Fear.case(->(v) { v == 42 }) {} }
155
158
  let(:and_then) { ->(x) { x } }
156
159
 
157
- context 'block given, arguments not given' do
160
+ context "block given, arguments not given" do
158
161
  subject { -> { partial_function.and_then(&and_then) } }
159
162
 
160
163
  it { is_expected.not_to raise_error }
161
164
  end
162
165
 
163
- context 'block given, argument given' do
166
+ context "block given, argument given" do
164
167
  subject { -> { partial_function.and_then(and_then, &and_then) } }
165
168
 
166
169
  it { is_expected.to raise_error(ArgumentError) }
167
170
  end
168
171
 
169
- context 'block given, arguments given' do
172
+ context "block given, arguments given" do
170
173
  subject { -> { partial_function.and_then(and_then, 42, &and_then) } }
171
174
 
172
175
  it { is_expected.to raise_error(ArgumentError) }
173
176
  end
174
177
 
175
- context 'block not given, arguments not given' do
178
+ context "block not given, arguments not given" do
176
179
  subject { -> { partial_function.and_then } }
177
180
 
178
181
  it { is_expected.to raise_error(ArgumentError) }
179
182
  end
180
183
 
181
- context 'block net given, arguments given' do
184
+ context "block net given, arguments given" do
182
185
  subject { -> { partial_function.and_then(and_then) } }
183
186
 
184
187
  it { is_expected.not_to raise_error }
185
188
  end
186
189
  end
190
+
191
+ shared_examples "#or_else" do |method_name|
192
+ subject { is_even.__send__(method_name, is_odd).(value) }
193
+
194
+ let(:is_even) { Fear.case(:even?.to_proc) { |x| "#{x} is even" } }
195
+ let(:is_odd) { Fear.case(:odd?.to_proc) { |x| "#{x} is odd" } }
196
+
197
+ context "when left side is defined" do
198
+ let(:value) { 42 }
199
+
200
+ it { is_expected.to eq("42 is even") }
201
+ end
202
+
203
+ context "when left side is not defined" do
204
+ let(:value) { 21 }
205
+
206
+ it { is_expected.to eq("21 is odd") }
207
+ end
208
+ end
209
+
210
+ describe "#or_else" do
211
+ include_examples "#or_else", :or_else
212
+ end
213
+
214
+ describe "#|" do
215
+ include_examples "#or_else", :|
216
+ end
187
217
  end