fear 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +30 -4
  3. data/.travis.yml +2 -3
  4. data/Appraisals +5 -9
  5. data/CHANGELOG.md +9 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE.txt +1 -1
  8. data/README.md +255 -85
  9. data/Rakefile +393 -0
  10. data/fear.gemspec +13 -6
  11. data/gemfiles/dry_equalizer_0.1.0.gemfile +1 -0
  12. data/gemfiles/dry_equalizer_0.1.0.gemfile.lock +31 -27
  13. data/gemfiles/dry_equalizer_0.2.1.gemfile +1 -0
  14. data/gemfiles/dry_equalizer_0.2.1.gemfile.lock +31 -27
  15. data/lib/fear/either.rb +49 -14
  16. data/lib/fear/either_pattern_match.rb +48 -0
  17. data/lib/fear/empty_partial_function.rb +36 -0
  18. data/lib/fear/failure.rb +5 -4
  19. data/lib/fear/failure_pattern_match.rb +8 -0
  20. data/lib/fear/for.rb +46 -51
  21. data/lib/fear/left.rb +7 -1
  22. data/lib/fear/left_pattern_match.rb +9 -0
  23. data/lib/fear/none.rb +37 -2
  24. data/lib/fear/none_pattern_match.rb +12 -0
  25. data/lib/fear/option.rb +65 -31
  26. data/lib/fear/option_pattern_match.rb +45 -0
  27. data/lib/fear/partial_function/and_then.rb +48 -0
  28. data/lib/fear/partial_function/any.rb +26 -0
  29. data/lib/fear/partial_function/combined.rb +51 -0
  30. data/lib/fear/partial_function/empty.rb +6 -0
  31. data/lib/fear/partial_function/guard/and.rb +36 -0
  32. data/lib/fear/partial_function/guard/and3.rb +39 -0
  33. data/lib/fear/partial_function/guard/or.rb +36 -0
  34. data/lib/fear/partial_function/guard.rb +90 -0
  35. data/lib/fear/partial_function/lifted.rb +20 -0
  36. data/lib/fear/partial_function/or_else.rb +62 -0
  37. data/lib/fear/partial_function.rb +171 -0
  38. data/lib/fear/partial_function_class.rb +26 -0
  39. data/lib/fear/pattern_match.rb +102 -0
  40. data/lib/fear/pattern_matching_api.rb +110 -0
  41. data/lib/fear/right.rb +7 -1
  42. data/lib/fear/right_biased.rb +2 -12
  43. data/lib/fear/right_pattern_match.rb +9 -0
  44. data/lib/fear/some.rb +5 -2
  45. data/lib/fear/some_pattern_match.rb +11 -0
  46. data/lib/fear/success.rb +5 -4
  47. data/lib/fear/success_pattern_match.rb +10 -0
  48. data/lib/fear/try.rb +56 -16
  49. data/lib/fear/try_pattern_match.rb +28 -0
  50. data/lib/fear/utils.rb +24 -14
  51. data/lib/fear/version.rb +1 -1
  52. data/lib/fear.rb +21 -4
  53. data/spec/fear/either_pattern_match_spec.rb +37 -0
  54. data/spec/fear/failure_spec.rb +41 -3
  55. data/spec/fear/for_spec.rb +17 -29
  56. data/spec/fear/guard_spec.rb +101 -0
  57. data/spec/fear/left_spec.rb +38 -0
  58. data/spec/fear/none_spec.rb +80 -0
  59. data/spec/fear/option_pattern_match_spec.rb +35 -0
  60. data/spec/fear/partial_function/empty_spec.rb +36 -0
  61. data/spec/fear/partial_function_and_then_spec.rb +145 -0
  62. data/spec/fear/partial_function_composition_spec.rb +80 -0
  63. data/spec/fear/partial_function_or_else_spec.rb +274 -0
  64. data/spec/fear/partial_function_spec.rb +165 -0
  65. data/spec/fear/pattern_match_spec.rb +59 -0
  66. data/spec/fear/right_biased/left.rb +1 -6
  67. data/spec/fear/right_biased/right.rb +0 -5
  68. data/spec/fear/right_spec.rb +38 -0
  69. data/spec/fear/some_spec.rb +37 -0
  70. data/spec/fear/success_spec.rb +41 -4
  71. data/spec/fear/try_pattern_match_spec.rb +37 -0
  72. metadata +97 -23
  73. data/lib/fear/for/evaluation_context.rb +0 -91
@@ -0,0 +1,145 @@
1
+ RSpec.describe Fear::PartialFunction, '#and_then' do
2
+ context 'proc' do
3
+ subject(:pf_and_f) { partial_function.and_then(&function) }
4
+
5
+ let(:partial_function) { Fear.case(->(x) { x.even? }) { |x| "pf: #{x}" } }
6
+ let(:function) { ->(x) { "f: #{x}" } }
7
+
8
+ describe '#defined_at?' do
9
+ context 'defined' do
10
+ subject { pf_and_f.defined_at?(4) }
11
+
12
+ it { is_expected.to eq(true) }
13
+ end
14
+
15
+ context 'not defined' do
16
+ subject { pf_and_f.defined_at?(3) }
17
+
18
+ it { is_expected.to eq(false) }
19
+ end
20
+ end
21
+
22
+ describe '#call' do
23
+ context 'defined' do
24
+ subject { pf_and_f.call(4) }
25
+
26
+ it { is_expected.to eq('f: pf: 4') }
27
+ end
28
+
29
+ context 'not defined' do
30
+ subject { -> { pf_and_f.call(3) } }
31
+
32
+ it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 3') }
33
+ end
34
+ end
35
+
36
+ describe '#call_or_else' do
37
+ let(:fallback) { ->(x) { "fallback: #{x}" } }
38
+
39
+ context 'defined' do
40
+ subject { pf_and_f.call_or_else(4, &fallback) }
41
+
42
+ it { is_expected.to eq('f: pf: 4') }
43
+ end
44
+
45
+ context 'not defined' do
46
+ subject { pf_and_f.call_or_else(3, &fallback) }
47
+
48
+ it { is_expected.to eq('fallback: 3') }
49
+ end
50
+ end
51
+ end
52
+
53
+ context 'partial function' do
54
+ subject(:first_and_then_second) { first.and_then(second) }
55
+
56
+ describe '#defined_at?' do
57
+ context 'first defined, second defined on result of first' do
58
+ subject { first_and_then_second.defined_at?(6) }
59
+
60
+ let(:first) { Fear.case(->(x) { x.even? }) { |x| x / 2 } }
61
+ let(:second) { Fear.case(->(x) { x % 3 == 0 }) { |x| x / 3 } }
62
+
63
+ it { is_expected.to eq(true) }
64
+ end
65
+
66
+ context 'first defined, second not defined on result of first' do
67
+ subject { first_and_then_second.defined_at?(4) }
68
+
69
+ let(:first) { Fear.case(->(x) { x.even? }) { |x| x / 2 } }
70
+ let(:second) { Fear.case(->(x) { x % 3 == 0 }) { |x| x / 3 } }
71
+
72
+ it { is_expected.to eq(false) }
73
+ end
74
+
75
+ context 'first not defined' do
76
+ subject { first_and_then_second.defined_at?(3) }
77
+
78
+ let(:first) { Fear.case(->(x) { x.even? }) { |x| "first: #{x}" } }
79
+ let(:second) { Fear.case(->(x) { x % 3 == 0 }) { |x| "second: #{x}" } }
80
+
81
+ it { is_expected.to eq(false) }
82
+ end
83
+ end
84
+
85
+ describe '#call' do
86
+ context 'first defined, second defined on result of first' do
87
+ subject { first_and_then_second.call(6) }
88
+
89
+ let(:first) { Fear.case(->(x) { x.even? }) { |x| x / 2 } }
90
+ let(:second) { Fear.case(->(x) { x % 3 == 0 }) { |x| x / 3 } }
91
+
92
+ it { is_expected.to eq(1) }
93
+ end
94
+
95
+ context 'first defined, second not defined on result of first' do
96
+ subject { -> { first_and_then_second.call(4) } }
97
+
98
+ let(:first) { Fear.case(->(x) { x.even? }) { |x| x / 2 } }
99
+ let(:second) { Fear.case(->(x) { x % 3 == 0 }) { |x| x / 3 } }
100
+
101
+ it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 2') }
102
+ end
103
+
104
+ context 'first not defined' do
105
+ subject { -> { first_and_then_second.call(3) } }
106
+
107
+ let(:first) { Fear.case(->(x) { x.even? }) { |x| "first: #{x}" } }
108
+ let(:second) { Fear.case(->(x) { x % 3 == 0 }) { |x| "second: #{x}" } }
109
+
110
+ it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 3') }
111
+ end
112
+ end
113
+
114
+ describe '#call_or_else' do
115
+ let(:fallback) { ->(x) { "fallback: #{x}" } }
116
+
117
+ context 'first defined, second defined on result of first' do
118
+ subject { first_and_then_second.call_or_else(6, &fallback) }
119
+
120
+ let(:first) { Fear.case(->(x) { x.even? }) { |x| x / 2 } }
121
+ let(:second) { Fear.case(->(x) { x % 3 == 0 }) { |x| x / 3 } }
122
+
123
+ it { is_expected.to eq(1) }
124
+ end
125
+
126
+ context 'first defined, second not defined on result of first' do
127
+ subject { first_and_then_second.call_or_else(4, &fallback) }
128
+
129
+ let(:first) { Fear.case(->(x) { x.even? }) { |x| x / 2 } }
130
+ let(:second) { Fear.case(->(x) { x % 3 == 0 }) { |x| x / 3 } }
131
+
132
+ it { is_expected.to eq('fallback: 4') }
133
+ end
134
+
135
+ context 'first not defined' do
136
+ subject { first_and_then_second.call_or_else(3, &fallback) }
137
+
138
+ let(:first) { Fear.case(->(x) { x.even? }) { |x| "first: #{x}" } }
139
+ let(:second) { Fear.case { |x| "second: #{x}" } }
140
+
141
+ it { is_expected.to eq('fallback: 3') }
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,80 @@
1
+ # This file contains tests from
2
+ # https://github.com/scala/scala/blob/2.13.x/test/junit/scala/PartialFunctionCompositionTest.scala
3
+ RSpec.describe Fear::PartialFunction do
4
+ let(:fallback_fun) { ->(_) { 'fallback' } }
5
+ let(:pass_all) { Fear.case(proc { true }) { |x| x } }
6
+ let(:pass_short) { Fear.case(->(x) { x.length < 5 }) { |x| x } }
7
+ let(:pass_pass) { Fear.case(->(x) { x.include?('pass') }) { |x| x } }
8
+
9
+ let(:all_and_then_short) { pass_all & pass_short }
10
+ let(:short_and_then_all) { pass_short & pass_all }
11
+ let(:all_and_then_pass) { pass_all & pass_pass }
12
+ let(:pass_and_then_all) { pass_pass & pass_all }
13
+ let(:pass_and_then_short) { pass_pass & pass_short }
14
+ let(:short_and_then_pass) { pass_short & pass_pass }
15
+
16
+ it '#and_then' do
17
+ expect(all_and_then_short.call_or_else('pass', &fallback_fun)).to eq('pass')
18
+ expect(short_and_then_all.call_or_else('pass', &fallback_fun)).to eq('pass')
19
+ expect(all_and_then_short.defined_at?('pass')).to eq(true)
20
+ expect(short_and_then_all.defined_at?('pass')).to eq(true)
21
+
22
+ expect(all_and_then_pass.call_or_else('pass', &fallback_fun)).to eq('pass')
23
+ expect(pass_and_then_all.call_or_else('pass', &fallback_fun)).to eq('pass')
24
+ expect(all_and_then_pass.defined_at?('pass')).to eq(true)
25
+ expect(pass_and_then_all.defined_at?('pass')).to eq(true)
26
+
27
+ expect(all_and_then_pass.call_or_else('longpass', &fallback_fun)).to eq('longpass')
28
+ expect(pass_and_then_all.call_or_else('longpass', &fallback_fun)).to eq('longpass')
29
+ expect(all_and_then_pass.defined_at?('longpass')).to eq(true)
30
+ expect(pass_and_then_all.defined_at?('longpass')).to eq(true)
31
+
32
+ expect(all_and_then_short.call_or_else('longpass', &fallback_fun)).to eq('fallback')
33
+ expect(short_and_then_all.call_or_else('longpass', &fallback_fun)).to eq('fallback')
34
+ expect(all_and_then_short.defined_at?('longpass')).to eq(false)
35
+ expect(short_and_then_all.defined_at?('longpass')).to eq(false)
36
+
37
+ expect(all_and_then_pass.call_or_else('longstr', &fallback_fun)).to eq('fallback')
38
+ expect(pass_and_then_all.call_or_else('longstr', &fallback_fun)).to eq('fallback')
39
+ expect(all_and_then_pass.defined_at?('longstr')).to eq(false)
40
+ expect(pass_and_then_all.defined_at?('longstr')).to eq(false)
41
+
42
+ expect(pass_and_then_short.call_or_else('pass', &fallback_fun)).to eq('pass')
43
+ expect(short_and_then_pass.call_or_else('pass', &fallback_fun)).to eq('pass')
44
+ expect(pass_and_then_short.defined_at?('pass')).to eq(true)
45
+ expect(short_and_then_pass.defined_at?('pass')).to eq(true)
46
+
47
+ expect(pass_and_then_short.call_or_else('longpass', &fallback_fun)).to eq('fallback')
48
+ expect(short_and_then_pass.call_or_else('longpass', &fallback_fun)).to eq('fallback')
49
+ expect(pass_and_then_short.defined_at?('longpass')).to eq(false)
50
+ expect(short_and_then_pass.defined_at?('longpass')).to eq(false)
51
+
52
+ expect(short_and_then_pass.call_or_else('longstr', &fallback_fun)).to eq('fallback')
53
+ expect(pass_and_then_short.call_or_else('longstr', &fallback_fun)).to eq('fallback')
54
+ expect(short_and_then_pass.defined_at?('longstr')).to eq(false)
55
+ expect(pass_and_then_short.defined_at?('longstr')).to eq(false)
56
+ end
57
+
58
+ it 'two branches' do
59
+ first_branch = Fear.case(Integer, &:itself).and_then(Fear.case(1) { 'one' })
60
+ second_branch = Fear.case(String, &:itself).and_then(
61
+ (Fear.case('zero') { 0 }).or_else(Fear.case('one') { 1 }),
62
+ )
63
+
64
+ full = first_branch.or_else(second_branch)
65
+ expect(full.call(1)).to eq('one')
66
+ expect(full.call('zero')).to eq(0)
67
+ expect(full.call('one')).to eq(1)
68
+ end
69
+
70
+ it 'or else anh then' do
71
+ f1 = Fear.case(->(x) { x < 5 }) { 1 }
72
+ f2 = Fear.case(->(x) { x > 10 }) { 10 }
73
+ f3 = Fear.case { |x| x * 2 }
74
+
75
+ f5 = f1.and_then(f3).or_else(f2)
76
+
77
+ expect(f5.call(11)).to eq(10)
78
+ expect(f5.call(3)).to eq(2)
79
+ end
80
+ end
@@ -0,0 +1,274 @@
1
+ RSpec.describe Fear::PartialFunction, '#or_else' do
2
+ subject(:first_or_else_second) { first.or_else(second) }
3
+
4
+ let(:first) { Fear.case(->(x) { x.even? }) { |x| "first: #{x}" } }
5
+ let(:second) { Fear.case(->(x) { x % 3 == 0 }) { |x| "second: #{x}" } }
6
+
7
+ describe '#defined_at?' do
8
+ context 'first defined, second not' do
9
+ subject { first_or_else_second.defined_at?(4) }
10
+
11
+ it { is_expected.to eq(true) }
12
+ end
13
+
14
+ context 'first not defined, second defined' do
15
+ subject { first_or_else_second.defined_at?(9) }
16
+
17
+ it { is_expected.to eq(true) }
18
+ end
19
+
20
+ context 'first not defined, second not defined' do
21
+ subject { first_or_else_second.defined_at?(5) }
22
+
23
+ it { is_expected.to eq(false) }
24
+ end
25
+
26
+ context 'first and second defined' do
27
+ subject { first_or_else_second.defined_at?(6) }
28
+
29
+ it { is_expected.to eq(true) }
30
+ end
31
+ end
32
+
33
+ describe '#call' do
34
+ context 'first defined, second not' do
35
+ subject { first_or_else_second.call(4) }
36
+
37
+ it { is_expected.to eq('first: 4') }
38
+ end
39
+
40
+ context 'first not defined, second defined' do
41
+ subject { first_or_else_second.call(9) }
42
+
43
+ it { is_expected.to eq('second: 9') }
44
+ end
45
+
46
+ context 'first not defined, second not defined' do
47
+ subject { -> { first_or_else_second.call(5) } }
48
+
49
+ it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 5') }
50
+ end
51
+
52
+ context 'first and second defined' do
53
+ subject { first_or_else_second.call(6) }
54
+
55
+ it { is_expected.to eq('first: 6') }
56
+ end
57
+ end
58
+
59
+ describe '#call_or_else' do
60
+ let(:fallback) { ->(x) { "fallback: #{x}" } }
61
+
62
+ context 'first defined, second not' do
63
+ subject { first_or_else_second.call_or_else(4, &fallback) }
64
+
65
+ it { is_expected.to eq('first: 4') }
66
+ end
67
+
68
+ context 'first not defined, second defined' do
69
+ subject { first_or_else_second.call_or_else(9, &fallback) }
70
+
71
+ it { is_expected.to eq('second: 9') }
72
+ end
73
+
74
+ context 'first not defined, second not defined' do
75
+ subject { first_or_else_second.call_or_else(5, &fallback) }
76
+
77
+ it { is_expected.to eq('fallback: 5') }
78
+ end
79
+
80
+ context 'first and second defined' do
81
+ subject { first_or_else_second.call_or_else(6, &fallback) }
82
+
83
+ it { is_expected.to eq('first: 6') }
84
+ end
85
+ end
86
+
87
+ describe '#or_else' do
88
+ let(:first_or_else_second_or_else_third) { first_or_else_second.or_else(third) }
89
+ let(:third) { Fear.case(->(x) { x % 7 == 0 }) { |x| "third: #{x}" } }
90
+
91
+ describe '#defined_at?' do
92
+ context 'first defined, second not' do
93
+ subject { first_or_else_second_or_else_third.defined_at?(4) }
94
+
95
+ it { is_expected.to eq(true) }
96
+ end
97
+
98
+ context 'first not defined, second defined' do
99
+ subject { first_or_else_second_or_else_third.defined_at?(9) }
100
+
101
+ it { is_expected.to eq(true) }
102
+ end
103
+
104
+ context 'first not defined, second not defined, third defined' do
105
+ subject { first_or_else_second_or_else_third.defined_at?(7) }
106
+
107
+ it { is_expected.to eq(true) }
108
+ end
109
+
110
+ context 'first not defined, second not defined, third not defined' do
111
+ subject { first_or_else_second_or_else_third.defined_at?(1) }
112
+
113
+ it { is_expected.to eq(false) }
114
+ end
115
+
116
+ context 'first, second and third defined' do
117
+ subject { first_or_else_second.defined_at?(42) }
118
+
119
+ it { is_expected.to eq(true) }
120
+ end
121
+ end
122
+
123
+ describe '#call' do
124
+ context 'first defined, second not' do
125
+ subject { first_or_else_second_or_else_third.call(4) }
126
+
127
+ it { is_expected.to eq('first: 4') }
128
+ end
129
+
130
+ context 'first not defined, second defined' do
131
+ subject { first_or_else_second_or_else_third.call(9) }
132
+
133
+ it { is_expected.to eq('second: 9') }
134
+ end
135
+
136
+ context 'first not defined, second not defined, third defined' do
137
+ subject { first_or_else_second_or_else_third.call(7) }
138
+
139
+ it { is_expected.to eq('third: 7') }
140
+ end
141
+
142
+ context 'first not defined, second not defined, third not defined' do
143
+ subject { -> { first_or_else_second_or_else_third.call(1) } }
144
+
145
+ it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 1') }
146
+ end
147
+
148
+ context 'first, second and third defined' do
149
+ subject { first_or_else_second.call(42) }
150
+
151
+ it { is_expected.to eq('first: 42') }
152
+ end
153
+ end
154
+
155
+ describe '#call_or_else' do
156
+ let(:fallback) { ->(x) { "fallback: #{x}" } }
157
+
158
+ context 'first defined, second not' do
159
+ subject { first_or_else_second_or_else_third.call_or_else(4, &fallback) }
160
+
161
+ it { is_expected.to eq('first: 4') }
162
+ end
163
+
164
+ context 'first not defined, second defined' do
165
+ subject { first_or_else_second_or_else_third.call_or_else(9, &fallback) }
166
+
167
+ it { is_expected.to eq('second: 9') }
168
+ end
169
+
170
+ context 'first not defined, second not defined, third defined' do
171
+ subject { first_or_else_second_or_else_third.call_or_else(7, &fallback) }
172
+
173
+ it { is_expected.to eq('third: 7') }
174
+ end
175
+
176
+ context 'first not defined, second not defined, third not defined' do
177
+ subject { first_or_else_second_or_else_third.call_or_else(1, &fallback) }
178
+
179
+ it { is_expected.to eq('fallback: 1') }
180
+ end
181
+
182
+ context 'first, second and third defined' do
183
+ subject { first_or_else_second_or_else_third.call_or_else(42, &fallback) }
184
+
185
+ it { is_expected.to eq('first: 42') }
186
+ end
187
+ end
188
+ end
189
+
190
+ describe '#and_then' do
191
+ let(:first_or_else_second_and_then_function) { first_or_else_second.and_then(&function) }
192
+ let(:function) { ->(x) { "f: #{x}" } }
193
+
194
+ describe '#defined_at?' do
195
+ context 'first defined, second not' do
196
+ subject { first_or_else_second_and_then_function.defined_at?(2) }
197
+
198
+ it { is_expected.to eq(true) }
199
+ end
200
+
201
+ context 'first not defined, second defined' do
202
+ subject { first_or_else_second_and_then_function.defined_at?(3) }
203
+
204
+ it { is_expected.to eq(true) }
205
+ end
206
+
207
+ context 'first not defined, second not defined' do
208
+ subject { first_or_else_second_and_then_function.defined_at?(5) }
209
+
210
+ it { is_expected.to eq(false) }
211
+ end
212
+
213
+ context 'first defined, second defined' do
214
+ subject { first_or_else_second_and_then_function.defined_at?(6) }
215
+
216
+ it { is_expected.to eq(true) }
217
+ end
218
+ end
219
+
220
+ describe '#call' do
221
+ context 'first defined, second not' do
222
+ subject { first_or_else_second_and_then_function.call(2) }
223
+
224
+ it { is_expected.to eq('f: first: 2') }
225
+ end
226
+
227
+ context 'first not defined, second defined' do
228
+ subject { first_or_else_second_and_then_function.call(3) }
229
+
230
+ it { is_expected.to eq('f: second: 3') }
231
+ end
232
+
233
+ context 'first not defined, second not defined' do
234
+ subject { -> { first_or_else_second_and_then_function.call(5) } }
235
+
236
+ it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 5') }
237
+ end
238
+
239
+ context 'first defined, second defined' do
240
+ subject { first_or_else_second_and_then_function.call(6) }
241
+
242
+ it { is_expected.to eq('f: first: 6') }
243
+ end
244
+ end
245
+
246
+ describe '#call_or_else' do
247
+ let(:fallback) { ->(x) { "fallback: #{x}" } }
248
+
249
+ context 'first defined, second not' do
250
+ subject { first_or_else_second_and_then_function.call_or_else(2, &fallback) }
251
+
252
+ it { is_expected.to eq('f: first: 2') }
253
+ end
254
+
255
+ context 'first not defined, second defined' do
256
+ subject { first_or_else_second_and_then_function.call_or_else(3, &fallback) }
257
+
258
+ it { is_expected.to eq('f: second: 3') }
259
+ end
260
+
261
+ context 'first not defined, second not defined' do
262
+ subject { first_or_else_second_and_then_function.call_or_else(5, &fallback) }
263
+
264
+ it { is_expected.to eq('fallback: 5') }
265
+ end
266
+
267
+ context 'first defined, second defined' do
268
+ subject { first_or_else_second_and_then_function.call_or_else(6, &fallback) }
269
+
270
+ it { is_expected.to eq('f: first: 6') }
271
+ end
272
+ end
273
+ end
274
+ end
@@ -0,0 +1,165 @@
1
+ RSpec.describe Fear::PartialFunction do
2
+ describe 'Fear.case()' do
3
+ context 'condition as symbol' do
4
+ subject { Fear.case(:even?) { |x| x } }
5
+
6
+ it 'converted to proc' do
7
+ is_expected.to be_defined_at(4)
8
+ is_expected.not_to be_defined_at(3)
9
+ end
10
+ end
11
+
12
+ context 'condition as Class' do
13
+ subject { Fear.case(Integer) { |x| x } }
14
+
15
+ it do
16
+ is_expected.to be_defined_at(4)
17
+ is_expected.not_to be_defined_at('3')
18
+ end
19
+ end
20
+
21
+ context 'condition as Proc' do
22
+ subject { Fear.case(->(x) { x.even? }) { |x| x } }
23
+
24
+ it do
25
+ is_expected.to be_defined_at(4)
26
+ is_expected.not_to be_defined_at(3)
27
+ end
28
+ end
29
+
30
+ context 'multiple condition' do
31
+ subject { Fear.case(Integer, :even?, ->(x) { x % 3 == 0 }) { |x| x } }
32
+
33
+ it do
34
+ is_expected.to be_defined_at(12)
35
+ is_expected.not_to be_defined_at(12.0)
36
+ is_expected.not_to be_defined_at('3')
37
+ is_expected.not_to be_defined_at(3)
38
+ is_expected.not_to be_defined_at(4)
39
+ end
40
+ end
41
+
42
+ context 'multiple condition 2' do
43
+ subject { Fear.case(Integer, 4) { |x| x } }
44
+
45
+ it do
46
+ is_expected.to be_defined_at(4)
47
+ is_expected.not_to be_defined_at(3)
48
+ end
49
+ end
50
+ end
51
+
52
+ describe '#lift' do
53
+ let(:lifted) { partial_function.lift }
54
+
55
+ let(:partial_function) { Fear.case(->(v) { v != 0 }) { |x| 4 / x } }
56
+
57
+ context 'defined' do
58
+ subject { lifted.call(2) }
59
+
60
+ it { is_expected.to eq(Fear::Some.new(2)) }
61
+ end
62
+
63
+ context 'not defined' do
64
+ subject { lifted.call(0) }
65
+
66
+ it { is_expected.to eq(Fear::None) }
67
+ end
68
+ end
69
+
70
+ describe '#defined_at?' do
71
+ let(:partial_function) { Fear.case(->(v) { v == 42 }) {} }
72
+
73
+ it 'defined at' do
74
+ expect(partial_function.defined_at?(42)).to eq(true)
75
+ end
76
+
77
+ it 'not defined at' do
78
+ expect(partial_function.defined_at?(24)).to eq(false)
79
+ end
80
+ end
81
+
82
+ describe '#call' do
83
+ let(:partial_function) { Fear.case(->(v) { v != 0 }) { |x| 4 / x } }
84
+
85
+ context 'defined' do
86
+ subject { partial_function.call(2) }
87
+
88
+ it { is_expected.to eq(2) }
89
+ end
90
+
91
+ context 'not defined' do
92
+ subject { -> { partial_function.call(0) } }
93
+
94
+ it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 0') }
95
+ end
96
+ end
97
+
98
+ describe '#to_proc', '#call' do
99
+ let(:partial_function) { Fear.case(->(v) { v != 0 }) { |x| 4 / x }.to_proc }
100
+
101
+ context 'defined' do
102
+ subject { partial_function.call(2) }
103
+
104
+ it { is_expected.to eq(2) }
105
+ end
106
+
107
+ context 'not defined' do
108
+ subject { -> { partial_function.call(0) } }
109
+
110
+ it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 0') }
111
+ end
112
+ end
113
+
114
+ describe '#call_or_else' do
115
+ let(:default) { ->(x) { "division by #{x} impossible" } }
116
+ let(:partial_function) { Fear.case(->(x) { x != 0 }) { |x| 4 / x } }
117
+
118
+ context 'defined' do
119
+ subject { partial_function.call_or_else(2, &default) }
120
+
121
+ it { is_expected.to eq(2) }
122
+ end
123
+
124
+ context 'not defined' do
125
+ subject { partial_function.call_or_else(0, &default) }
126
+
127
+ it { is_expected.to eq('division by 0 impossible') }
128
+ end
129
+ end
130
+
131
+ describe '#and_then' do
132
+ let(:partial_function) { Fear.case(->(v) { v == 42 }) {} }
133
+ let(:and_then) { ->(x) { x } }
134
+
135
+ context 'block given, arguments not given' do
136
+ subject { -> { partial_function.and_then(&and_then) } }
137
+
138
+ it { is_expected.not_to raise_error }
139
+ end
140
+
141
+ context 'block given, argument given' do
142
+ subject { -> { partial_function.and_then(and_then, &and_then) } }
143
+
144
+ it { is_expected.to raise_error(ArgumentError) }
145
+ end
146
+
147
+ context 'block given, arguments given' do
148
+ subject { -> { partial_function.and_then(and_then, 42, &and_then) } }
149
+
150
+ it { is_expected.to raise_error(ArgumentError) }
151
+ end
152
+
153
+ context 'block not given, arguments not given' do
154
+ subject { -> { partial_function.and_then } }
155
+
156
+ it { is_expected.to raise_error(ArgumentError) }
157
+ end
158
+
159
+ context 'block net given, arguments given' do
160
+ subject { -> { partial_function.and_then(and_then) } }
161
+
162
+ it { is_expected.not_to raise_error }
163
+ end
164
+ end
165
+ end