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.
- checksums.yaml +4 -4
- data/.rubocop.yml +30 -4
- data/.travis.yml +2 -3
- data/Appraisals +5 -9
- data/CHANGELOG.md +9 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +1 -1
- data/README.md +255 -85
- data/Rakefile +393 -0
- data/fear.gemspec +13 -6
- data/gemfiles/dry_equalizer_0.1.0.gemfile +1 -0
- data/gemfiles/dry_equalizer_0.1.0.gemfile.lock +31 -27
- data/gemfiles/dry_equalizer_0.2.1.gemfile +1 -0
- data/gemfiles/dry_equalizer_0.2.1.gemfile.lock +31 -27
- data/lib/fear/either.rb +49 -14
- data/lib/fear/either_pattern_match.rb +48 -0
- data/lib/fear/empty_partial_function.rb +36 -0
- data/lib/fear/failure.rb +5 -4
- data/lib/fear/failure_pattern_match.rb +8 -0
- data/lib/fear/for.rb +46 -51
- data/lib/fear/left.rb +7 -1
- data/lib/fear/left_pattern_match.rb +9 -0
- data/lib/fear/none.rb +37 -2
- data/lib/fear/none_pattern_match.rb +12 -0
- data/lib/fear/option.rb +65 -31
- data/lib/fear/option_pattern_match.rb +45 -0
- data/lib/fear/partial_function/and_then.rb +48 -0
- data/lib/fear/partial_function/any.rb +26 -0
- data/lib/fear/partial_function/combined.rb +51 -0
- data/lib/fear/partial_function/empty.rb +6 -0
- data/lib/fear/partial_function/guard/and.rb +36 -0
- data/lib/fear/partial_function/guard/and3.rb +39 -0
- data/lib/fear/partial_function/guard/or.rb +36 -0
- data/lib/fear/partial_function/guard.rb +90 -0
- data/lib/fear/partial_function/lifted.rb +20 -0
- data/lib/fear/partial_function/or_else.rb +62 -0
- data/lib/fear/partial_function.rb +171 -0
- data/lib/fear/partial_function_class.rb +26 -0
- data/lib/fear/pattern_match.rb +102 -0
- data/lib/fear/pattern_matching_api.rb +110 -0
- data/lib/fear/right.rb +7 -1
- data/lib/fear/right_biased.rb +2 -12
- data/lib/fear/right_pattern_match.rb +9 -0
- data/lib/fear/some.rb +5 -2
- data/lib/fear/some_pattern_match.rb +11 -0
- data/lib/fear/success.rb +5 -4
- data/lib/fear/success_pattern_match.rb +10 -0
- data/lib/fear/try.rb +56 -16
- data/lib/fear/try_pattern_match.rb +28 -0
- data/lib/fear/utils.rb +24 -14
- data/lib/fear/version.rb +1 -1
- data/lib/fear.rb +21 -4
- data/spec/fear/either_pattern_match_spec.rb +37 -0
- data/spec/fear/failure_spec.rb +41 -3
- data/spec/fear/for_spec.rb +17 -29
- data/spec/fear/guard_spec.rb +101 -0
- data/spec/fear/left_spec.rb +38 -0
- data/spec/fear/none_spec.rb +80 -0
- data/spec/fear/option_pattern_match_spec.rb +35 -0
- data/spec/fear/partial_function/empty_spec.rb +36 -0
- data/spec/fear/partial_function_and_then_spec.rb +145 -0
- data/spec/fear/partial_function_composition_spec.rb +80 -0
- data/spec/fear/partial_function_or_else_spec.rb +274 -0
- data/spec/fear/partial_function_spec.rb +165 -0
- data/spec/fear/pattern_match_spec.rb +59 -0
- data/spec/fear/right_biased/left.rb +1 -6
- data/spec/fear/right_biased/right.rb +0 -5
- data/spec/fear/right_spec.rb +38 -0
- data/spec/fear/some_spec.rb +37 -0
- data/spec/fear/success_spec.rb +41 -4
- data/spec/fear/try_pattern_match_spec.rb +37 -0
- metadata +97 -23
- 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
|