fear 1.0.0 → 2.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 (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