fear 0.10.0 → 0.11.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 (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