fear 0.11.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +0 -1
- data/.rubocop.yml +18 -0
- data/.travis.yml +0 -3
- data/CHANGELOG.md +12 -1
- data/Gemfile +1 -0
- data/{gemfiles/dry_equalizer_0.2.1.gemfile.lock → Gemfile.lock} +21 -12
- data/README.md +594 -241
- data/Rakefile +166 -219
- data/benchmarks/README.md +1 -0
- data/benchmarks/dry_do_vs_fear_for.txt +11 -0
- data/benchmarks/dry_some_fmap_vs_fear_some_map.txt +11 -0
- data/benchmarks/factorial.txt +16 -0
- data/benchmarks/fear_gaurd_and1_vs_new.txt +13 -0
- data/benchmarks/fear_gaurd_and2_vs_and.txt +13 -0
- data/benchmarks/fear_gaurd_and3_vs_and_and.txt +13 -0
- data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +11 -0
- data/benchmarks/fear_pattern_matching_construction_vs_execution.txt +13 -0
- data/benchmarks/pattern_matching_dry_vs_qo_vs_fear_try.txt +14 -0
- data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +11 -0
- data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +11 -0
- data/examples/pattern_extracting.rb +15 -0
- data/examples/pattern_matching_binary_tree_set.rb +96 -0
- data/examples/pattern_matching_number_in_words.rb +54 -0
- data/fear.gemspec +4 -2
- data/lib/fear.rb +21 -4
- data/lib/fear/either.rb +77 -59
- data/lib/fear/either_api.rb +21 -0
- data/lib/fear/empty_partial_function.rb +1 -1
- data/lib/fear/extractor.rb +108 -0
- data/lib/fear/extractor/anonymous_array_splat_matcher.rb +8 -0
- data/lib/fear/extractor/any_matcher.rb +15 -0
- data/lib/fear/extractor/array_head_matcher.rb +34 -0
- data/lib/fear/extractor/array_matcher.rb +38 -0
- data/lib/fear/extractor/array_splat_matcher.rb +14 -0
- data/lib/fear/extractor/empty_list_matcher.rb +18 -0
- data/lib/fear/extractor/extractor_matcher.rb +42 -0
- data/lib/fear/extractor/grammar.rb +201 -0
- data/lib/fear/extractor/grammar.treetop +129 -0
- data/lib/fear/extractor/identifier_matcher.rb +16 -0
- data/lib/fear/extractor/matcher.rb +54 -0
- data/lib/fear/extractor/matcher/and.rb +36 -0
- data/lib/fear/extractor/named_array_splat_matcher.rb +15 -0
- data/lib/fear/extractor/pattern.rb +55 -0
- data/lib/fear/extractor/typed_identifier_matcher.rb +24 -0
- data/lib/fear/extractor/value_matcher.rb +17 -0
- data/lib/fear/extractor_api.rb +33 -0
- data/lib/fear/failure.rb +32 -10
- data/lib/fear/for.rb +14 -69
- data/lib/fear/for_api.rb +66 -0
- data/lib/fear/future.rb +414 -0
- data/lib/fear/future_api.rb +19 -0
- data/lib/fear/left.rb +8 -0
- data/lib/fear/none.rb +17 -8
- data/lib/fear/option.rb +55 -49
- data/lib/fear/option_api.rb +38 -0
- data/lib/fear/partial_function.rb +9 -12
- data/lib/fear/partial_function/empty.rb +1 -1
- data/lib/fear/partial_function/guard.rb +8 -20
- data/lib/fear/partial_function/lifted.rb +1 -0
- data/lib/fear/partial_function_class.rb +10 -0
- data/lib/fear/pattern_match.rb +10 -0
- data/lib/fear/pattern_matching_api.rb +35 -11
- data/lib/fear/promise.rb +87 -0
- data/lib/fear/right.rb +8 -0
- data/lib/fear/some.rb +22 -3
- data/lib/fear/success.rb +22 -1
- data/lib/fear/try.rb +82 -67
- data/lib/fear/try_api.rb +31 -0
- data/lib/fear/unit.rb +28 -0
- data/lib/fear/version.rb +1 -1
- data/spec/fear/done_spec.rb +3 -3
- data/spec/fear/either/mixin_spec.rb +15 -0
- data/spec/fear/either_pattern_match_spec.rb +10 -12
- data/spec/fear/extractor/array_matcher_spec.rb +228 -0
- data/spec/fear/extractor/extractor_matcher_spec.rb +151 -0
- data/spec/fear/extractor/grammar_array_spec.rb +23 -0
- data/spec/fear/extractor/identified_matcher_spec.rb +47 -0
- data/spec/fear/extractor/identifier_matcher_spec.rb +66 -0
- data/spec/fear/extractor/pattern_spec.rb +32 -0
- data/spec/fear/extractor/typed_identifier_matcher_spec.rb +62 -0
- data/spec/fear/extractor/value_matcher_number_spec.rb +77 -0
- data/spec/fear/extractor/value_matcher_string_spec.rb +86 -0
- data/spec/fear/extractor/value_matcher_symbol_spec.rb +69 -0
- data/spec/fear/extractor_api_spec.rb +113 -0
- data/spec/fear/extractor_spec.rb +59 -0
- data/spec/fear/failure_spec.rb +73 -13
- data/spec/fear/for_spec.rb +35 -35
- data/spec/fear/future_spec.rb +466 -0
- data/spec/fear/guard_spec.rb +4 -4
- data/spec/fear/left_spec.rb +40 -14
- data/spec/fear/none_spec.rb +28 -12
- data/spec/fear/option/mixin_spec.rb +37 -0
- data/spec/fear/option_pattern_match_spec.rb +7 -9
- data/spec/fear/partial_function_spec.rb +25 -3
- data/spec/fear/pattern_match_spec.rb +33 -1
- data/spec/fear/promise_spec.rb +94 -0
- data/spec/fear/right_spec.rb +37 -9
- data/spec/fear/some_spec.rb +32 -6
- data/spec/fear/success_spec.rb +32 -4
- data/spec/fear/try/mixin_spec.rb +17 -0
- data/spec/fear/try_pattern_match_spec.rb +8 -10
- data/spec/spec_helper.rb +1 -1
- metadata +115 -20
- data/Appraisals +0 -32
- data/gemfiles/dry_equalizer_0.1.0.gemfile +0 -8
- data/gemfiles/dry_equalizer_0.1.0.gemfile.lock +0 -82
- data/gemfiles/dry_equalizer_0.2.1.gemfile +0 -8
- data/lib/fear/done.rb +0 -22
- data/spec/fear/option_spec.rb +0 -15
data/lib/fear/try_api.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Fear
|
2
|
+
module TryApi
|
3
|
+
# Constructs a +Try+ using the block. This
|
4
|
+
# method ensures any non-fatal exception is caught and a
|
5
|
+
# +Failure+ object is returned.
|
6
|
+
# @return [Fear::Try]
|
7
|
+
# @example
|
8
|
+
# Fear.try { 4/0 } #=> #<Fear::Failure exception=#<ZeroDivisionError: divided by 0>>
|
9
|
+
# Fear.try { 4/2 } #=> #<Fear::Success value=2>
|
10
|
+
#
|
11
|
+
def try
|
12
|
+
success(yield)
|
13
|
+
rescue StandardError => error
|
14
|
+
failure(error)
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param exception [StandardError]
|
18
|
+
# @return [Fear::Failure]
|
19
|
+
#
|
20
|
+
def failure(exception)
|
21
|
+
Fear::Failure.new(exception)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param value [any]
|
25
|
+
# @return [Fear::Success]
|
26
|
+
#
|
27
|
+
def success(value)
|
28
|
+
Fear::Success.new(value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/fear/unit.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Fear
|
2
|
+
# Represents lack of value. It's typically returned when function completed without a value.
|
3
|
+
#
|
4
|
+
# @example
|
5
|
+
# if user.valid?
|
6
|
+
# Fear.right(Fear::Unit)
|
7
|
+
# else
|
8
|
+
# Fear.left(user.errors)
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# def sent_notifications(user)
|
13
|
+
# # ...
|
14
|
+
# Fear::Unit
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
Unit = Object.new.tap do |unit|
|
18
|
+
# @return [String]
|
19
|
+
def unit.to_s
|
20
|
+
'#<Fear::Unit>'
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [String]
|
24
|
+
def unit.inspect
|
25
|
+
'#<Fear::Unit>'
|
26
|
+
end
|
27
|
+
end.freeze
|
28
|
+
end
|
data/lib/fear/version.rb
CHANGED
data/spec/fear/done_spec.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
RSpec.describe Fear::
|
1
|
+
RSpec.describe Fear::Unit do
|
2
2
|
describe '#to_s' do
|
3
3
|
subject { described_class.to_s }
|
4
4
|
|
5
|
-
it { is_expected.to eq('
|
5
|
+
it { is_expected.to eq('#<Fear::Unit>') }
|
6
6
|
end
|
7
7
|
|
8
8
|
describe '#inspect' do
|
9
9
|
subject { described_class.inspect }
|
10
10
|
|
11
|
-
it { is_expected.to eq('
|
11
|
+
it { is_expected.to eq('#<Fear::Unit>') }
|
12
12
|
end
|
13
13
|
|
14
14
|
describe '#==' do
|
@@ -0,0 +1,15 @@
|
|
1
|
+
RSpec.describe Fear::Either::Mixin do
|
2
|
+
include Fear::Either::Mixin
|
3
|
+
|
4
|
+
describe 'Left()' do
|
5
|
+
subject { Left(42) }
|
6
|
+
|
7
|
+
it { is_expected.to eq(Fear::Left.new(42)) }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'Right()' do
|
11
|
+
subject { Right(42) }
|
12
|
+
|
13
|
+
it { is_expected.to eq(Fear::Right.new(42)) }
|
14
|
+
end
|
15
|
+
end
|
@@ -1,19 +1,17 @@
|
|
1
1
|
RSpec.describe Fear::EitherPatternMatch do
|
2
|
-
include Fear::Either::Mixin
|
3
|
-
|
4
2
|
context 'Right' do
|
5
3
|
let(:matcher) do
|
6
4
|
described_class.new do |m|
|
7
|
-
m.right(:even
|
8
|
-
m.right(:odd
|
5
|
+
m.right(:even?.to_proc) { |x| "#{x} is even" }
|
6
|
+
m.right(:odd?.to_proc) { |x| "#{x} is odd" }
|
9
7
|
end
|
10
8
|
end
|
11
9
|
|
12
10
|
it do
|
13
|
-
expect(matcher.call(
|
14
|
-
expect(matcher.call(
|
11
|
+
expect(matcher.call(Fear.right(4))).to eq('4 is even')
|
12
|
+
expect(matcher.call(Fear.right(3))).to eq('3 is odd')
|
15
13
|
expect do
|
16
|
-
matcher.call(
|
14
|
+
matcher.call(Fear.left(44))
|
17
15
|
end.to raise_error(Fear::MatchError)
|
18
16
|
end
|
19
17
|
end
|
@@ -21,16 +19,16 @@ RSpec.describe Fear::EitherPatternMatch do
|
|
21
19
|
context 'Left' do
|
22
20
|
let(:matcher) do
|
23
21
|
described_class.new do |m|
|
24
|
-
m.left(:even
|
25
|
-
m.left(:odd
|
22
|
+
m.left(:even?.to_proc) { |x| "#{x} is even" }
|
23
|
+
m.left(:odd?.to_proc) { |x| "#{x} is odd" }
|
26
24
|
end
|
27
25
|
end
|
28
26
|
|
29
27
|
it do
|
30
|
-
expect(matcher.call(
|
31
|
-
expect(matcher.call(
|
28
|
+
expect(matcher.call(Fear.left(4))).to eq('4 is even')
|
29
|
+
expect(matcher.call(Fear.left(3))).to eq('3 is odd')
|
32
30
|
expect do
|
33
|
-
matcher.call(
|
31
|
+
matcher.call(Fear.right(44))
|
34
32
|
end.to raise_error(Fear::MatchError)
|
35
33
|
end
|
36
34
|
end
|
@@ -0,0 +1,228 @@
|
|
1
|
+
RSpec.describe Fear::Extractor::ArrayMatcher do
|
2
|
+
let(:parser) { Fear::Extractor::GrammarParser.new }
|
3
|
+
let(:matcher) { parser.parse(pattern).to_matcher }
|
4
|
+
|
5
|
+
describe '#defined_at?' do
|
6
|
+
subject { matcher }
|
7
|
+
|
8
|
+
context 'empty array' do
|
9
|
+
let(:pattern) { '[]' }
|
10
|
+
|
11
|
+
it { is_expected.to be_defined_at([]) }
|
12
|
+
it { is_expected.not_to be_defined_at([1]) }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'empty array with splat' do
|
16
|
+
let(:pattern) { '[*]' }
|
17
|
+
|
18
|
+
it { is_expected.to be_defined_at([]) }
|
19
|
+
it { is_expected.to be_defined_at([1]) }
|
20
|
+
it { is_expected.to be_defined_at([1, 2]) }
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'empty array with named splat' do
|
24
|
+
let(:pattern) { '[*var]' }
|
25
|
+
|
26
|
+
it { is_expected.to be_defined_at([]) }
|
27
|
+
it { is_expected.to be_defined_at([1]) }
|
28
|
+
it { is_expected.to be_defined_at([1, 2]) }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'one element array' do
|
32
|
+
let(:pattern) { '[1]' }
|
33
|
+
|
34
|
+
it { is_expected.not_to be_defined_at([]) }
|
35
|
+
it { is_expected.to be_defined_at([1]) }
|
36
|
+
it { is_expected.not_to be_defined_at([1, 2]) }
|
37
|
+
it { is_expected.not_to be_defined_at([2, 1]) }
|
38
|
+
|
39
|
+
context 'identifier' do
|
40
|
+
let(:pattern) { '[var]' }
|
41
|
+
|
42
|
+
it { is_expected.not_to be_defined_at([]) }
|
43
|
+
it { is_expected.to be_defined_at([1]) }
|
44
|
+
it { is_expected.to be_defined_at([[1]]) }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'two elements array with nested matcher' do
|
49
|
+
let(:pattern) { '[[1, *], 1]' }
|
50
|
+
|
51
|
+
it { is_expected.not_to be_defined_at([]) }
|
52
|
+
it { is_expected.to be_defined_at([[1], 1]) }
|
53
|
+
it { is_expected.to be_defined_at([[1, 2], 1]) }
|
54
|
+
it { is_expected.not_to be_defined_at([[1, 2], 2]) }
|
55
|
+
it { is_expected.not_to be_defined_at([2, 1]) }
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'one element array with splat' do
|
59
|
+
let(:pattern) { '[1, *]' }
|
60
|
+
|
61
|
+
it { is_expected.not_to be_defined_at([]) }
|
62
|
+
it { is_expected.to be_defined_at([1]) }
|
63
|
+
it { is_expected.to be_defined_at([1, 2]) }
|
64
|
+
it { is_expected.to be_defined_at([1, 2, 3]) }
|
65
|
+
it { is_expected.not_to be_defined_at([2, 1]) }
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'one element array with named splat' do
|
69
|
+
let(:pattern) { '[1, *var]' }
|
70
|
+
|
71
|
+
it { is_expected.not_to be_defined_at([]) }
|
72
|
+
it { is_expected.to be_defined_at([1]) }
|
73
|
+
it { is_expected.to be_defined_at([1, 2]) }
|
74
|
+
it { is_expected.to be_defined_at([1, 2, 3]) }
|
75
|
+
it { is_expected.not_to be_defined_at([2, 1]) }
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'three elements array' do
|
79
|
+
context 'with identifier in the middle' do
|
80
|
+
let(:pattern) { '[1, var, 2]' }
|
81
|
+
|
82
|
+
it { is_expected.not_to be_defined_at([]) }
|
83
|
+
it { is_expected.to be_defined_at([1, 3, 2]) }
|
84
|
+
it { is_expected.not_to be_defined_at([1, 2, 3]) }
|
85
|
+
it { is_expected.not_to be_defined_at([1, 2, 3, 4]) }
|
86
|
+
it { is_expected.not_to be_defined_at([1]) }
|
87
|
+
it { is_expected.not_to be_defined_at([2]) }
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'head and tail' do
|
91
|
+
let(:pattern) { '[head, *tail]' }
|
92
|
+
|
93
|
+
it { is_expected.not_to be_defined_at([]) }
|
94
|
+
it { is_expected.to be_defined_at([1, 3, 2]) }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'two element array' do
|
99
|
+
let(:pattern) { '[ 1, 2 ]' }
|
100
|
+
|
101
|
+
it { is_expected.not_to be_defined_at([]) }
|
102
|
+
it { is_expected.to be_defined_at([1, 2]) }
|
103
|
+
it { is_expected.not_to be_defined_at([1]) }
|
104
|
+
it { is_expected.not_to be_defined_at([2]) }
|
105
|
+
it { is_expected.not_to be_defined_at([1, 3]) }
|
106
|
+
it { is_expected.not_to be_defined_at([2, 2]) }
|
107
|
+
it { is_expected.not_to be_defined_at([1, 2, 3]) }
|
108
|
+
|
109
|
+
context 'with identifier at the beginning' do
|
110
|
+
let(:pattern) { '[var, 2]' }
|
111
|
+
|
112
|
+
it { is_expected.not_to be_defined_at([]) }
|
113
|
+
it { is_expected.to be_defined_at([1, 2]) }
|
114
|
+
it { is_expected.not_to be_defined_at([1, 3]) }
|
115
|
+
it { is_expected.not_to be_defined_at([1]) }
|
116
|
+
it { is_expected.not_to be_defined_at([2]) }
|
117
|
+
it { is_expected.not_to be_defined_at([1, 2, 3]) }
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe '#call' do
|
123
|
+
subject { matcher.call(other) }
|
124
|
+
|
125
|
+
context 'on the same array' do
|
126
|
+
let(:other) { [1] }
|
127
|
+
let(:pattern) { '[1]' }
|
128
|
+
|
129
|
+
it { is_expected.to eq({}) }
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'with splat on another array' do
|
133
|
+
let(:other) { [2, 1] }
|
134
|
+
let(:pattern) { '[2, *]' }
|
135
|
+
|
136
|
+
it { is_expected.to eq({}) }
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'with identifier at the middle of an array' do
|
140
|
+
let(:other) { [2, 1, 3] }
|
141
|
+
let(:pattern) { '[2, var, 3]' }
|
142
|
+
|
143
|
+
it { is_expected.to eq(var: 1) }
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'with identifier at the end of an array' do
|
147
|
+
let(:other) { [2, 1, 3] }
|
148
|
+
let(:pattern) { '[2, 1, var]' }
|
149
|
+
|
150
|
+
it { is_expected.to eq(var: 3) }
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'with named splat matching all the array' do
|
154
|
+
let(:other) { [2, 1, 3, 4] }
|
155
|
+
let(:pattern) { '[*var]' }
|
156
|
+
|
157
|
+
it { is_expected.to eq(var: [2, 1, 3, 4]) }
|
158
|
+
end
|
159
|
+
|
160
|
+
context 'with named splat matching tail of an array' do
|
161
|
+
let(:other) { [2, 1, 3, 4] }
|
162
|
+
let(:pattern) { '[2, 1, *var]' }
|
163
|
+
|
164
|
+
it { is_expected.to eq(var: [3, 4]) }
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'with named splat at the end of an array' do
|
168
|
+
let(:other) { [2, 1] }
|
169
|
+
let(:pattern) { '[2, 1, *var]' }
|
170
|
+
|
171
|
+
it { is_expected.to eq(var: []) }
|
172
|
+
end
|
173
|
+
|
174
|
+
context 'with several identifiers in an array' do
|
175
|
+
let(:other) { [2, 1, 3] }
|
176
|
+
let(:pattern) { '[a, 1, b]' }
|
177
|
+
|
178
|
+
it { is_expected.to eq(a: 2, b: 3) }
|
179
|
+
end
|
180
|
+
|
181
|
+
context 'head and tail' do
|
182
|
+
let(:other) { [2, 1, 3] }
|
183
|
+
let(:pattern) { '[head, *tail]' }
|
184
|
+
|
185
|
+
it { is_expected.to eq(head: 2, tail: [1, 3]) }
|
186
|
+
end
|
187
|
+
|
188
|
+
context 'ignore head, capture tail' do
|
189
|
+
let(:other) { [2, 1, 3] }
|
190
|
+
let(:pattern) { '[_, *tail]' }
|
191
|
+
|
192
|
+
it { is_expected.to eq(tail: [1, 3]) }
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe '#failure_reason' do
|
197
|
+
subject { matcher.failure_reason(other) }
|
198
|
+
|
199
|
+
context 'on the same array' do
|
200
|
+
let(:other) { [1] }
|
201
|
+
let(:pattern) { '[1]' }
|
202
|
+
|
203
|
+
it { is_expected.to eq(Fear.none) }
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'on another array' do
|
207
|
+
let(:other) { [2, 1] }
|
208
|
+
let(:pattern) { '[2, 2]' }
|
209
|
+
|
210
|
+
it { is_expected.to eq(Fear.some(<<-ERROR.strip)) }
|
211
|
+
Expected `1` to match:
|
212
|
+
[2, 2]
|
213
|
+
~~~~^
|
214
|
+
ERROR
|
215
|
+
end
|
216
|
+
|
217
|
+
context 'element type mismatch' do
|
218
|
+
let(:other) { [2, 1] }
|
219
|
+
let(:pattern) { '[[2], 1]' }
|
220
|
+
|
221
|
+
it { is_expected.to eq(Fear.some(<<-ERROR.strip)) }
|
222
|
+
Expected `2` to match:
|
223
|
+
[[2], 1]
|
224
|
+
~~^
|
225
|
+
ERROR
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
RSpec.describe Fear::Extractor::ExtractorMatcher do
|
2
|
+
let(:parser) { Fear::Extractor::GrammarParser.new }
|
3
|
+
let(:matcher) { parser.parse(pattern).to_matcher }
|
4
|
+
|
5
|
+
describe '#defined_at?' do
|
6
|
+
subject { matcher }
|
7
|
+
|
8
|
+
context 'boolean extractor' do
|
9
|
+
let(:pattern) { 'IsEven()' }
|
10
|
+
|
11
|
+
it { is_expected.to be_defined_at(42) }
|
12
|
+
it { is_expected.not_to be_defined_at(43) }
|
13
|
+
it { is_expected.not_to be_defined_at('foo') }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'single argument extractor' do
|
17
|
+
let(:pattern) { 'Fear::Some(a : Integer)' }
|
18
|
+
|
19
|
+
it { is_expected.to be_defined_at(Fear.some(42)) }
|
20
|
+
it { is_expected.not_to be_defined_at('foo') }
|
21
|
+
it { is_expected.not_to be_defined_at(Fear.some('foo')) }
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'single argument extractor with array as an argument' do
|
25
|
+
let(:pattern) { 'Fear::Some([1, 2])' }
|
26
|
+
|
27
|
+
it { is_expected.to be_defined_at(Fear.some([1, 2])) }
|
28
|
+
it { is_expected.not_to be_defined_at(Fear.some([1, 1])) }
|
29
|
+
it { is_expected.not_to be_defined_at(Fear.some('foo')) }
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'multiple arguments extractor' do
|
33
|
+
let(:pattern) { 'Date(2017, month, _)' }
|
34
|
+
|
35
|
+
it { is_expected.to be_defined_at(Date.parse('2017-02-15')) }
|
36
|
+
it { is_expected.not_to be_defined_at(Date.parse('2018-02-15')) }
|
37
|
+
it { is_expected.not_to be_defined_at('foo') }
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'Struct' do
|
41
|
+
StructDate = Struct.new(:year, :month, :day)
|
42
|
+
|
43
|
+
let(:pattern) { 'StructDate(2017, month, _)' }
|
44
|
+
|
45
|
+
it { is_expected.to be_defined_at(StructDate.new(2017, 2, 15)) }
|
46
|
+
it { is_expected.not_to be_defined_at(StructDate.new(2018, 2, 15)) }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#call' do
|
51
|
+
subject { matcher.call(other) }
|
52
|
+
|
53
|
+
context 'single argument extractor' do
|
54
|
+
let(:pattern) { 'Fear::Some(a : Integer)' }
|
55
|
+
let(:other) { Fear.some(42) }
|
56
|
+
|
57
|
+
it { is_expected.to eq(a: 42) }
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'multiple arguments extractor' do
|
61
|
+
let(:pattern) { 'Date(2017, month, day)' }
|
62
|
+
let(:other) { Date.parse('2017-02-15') }
|
63
|
+
|
64
|
+
it { is_expected.to eq(month: 2, day: 15) }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#failure_reason' do
|
69
|
+
subject { matcher.failure_reason(other) }
|
70
|
+
|
71
|
+
context 'no argument extractor' do
|
72
|
+
let(:pattern) { 'IsEven()' }
|
73
|
+
|
74
|
+
context 'defined' do
|
75
|
+
let(:other) { 42 }
|
76
|
+
|
77
|
+
it { is_expected.to eq(Fear.none) }
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'not defined' do
|
81
|
+
let(:other) { 43 }
|
82
|
+
|
83
|
+
it { is_expected.to eq(Fear.some(<<-MSG.strip)) }
|
84
|
+
Expected `43` to match:
|
85
|
+
IsEven()
|
86
|
+
^
|
87
|
+
MSG
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'single argument extractor' do
|
92
|
+
let(:pattern) { 'Fear::Some(a : Integer)' }
|
93
|
+
|
94
|
+
context 'defined' do
|
95
|
+
let(:other) { Fear.some(42) }
|
96
|
+
|
97
|
+
it { is_expected.to eq(Fear.none) }
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'not defined' do
|
101
|
+
let(:other) { Fear.some('42') }
|
102
|
+
|
103
|
+
it { is_expected.to eq(Fear.some(<<-MSG.strip)) }
|
104
|
+
Expected `"42"` to match:
|
105
|
+
Fear::Some(a : Integer)
|
106
|
+
~~~~~~~~~~~~~~~^
|
107
|
+
MSG
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'single argument extractor, array argument' do
|
112
|
+
let(:pattern) { 'Fear::Some([1, 2])' }
|
113
|
+
|
114
|
+
context 'defined' do
|
115
|
+
let(:other) { Fear.some([1, 2]) }
|
116
|
+
|
117
|
+
it { is_expected.to eq(Fear.none) }
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'not defined' do
|
121
|
+
let(:other) { Fear.some([1, 1]) }
|
122
|
+
|
123
|
+
it { is_expected.to eq(Fear.some(<<-MSG.strip)) }
|
124
|
+
Expected `1` to match:
|
125
|
+
Fear::Some([1, 2])
|
126
|
+
~~~~~~~~~~~~~~~^
|
127
|
+
MSG
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'multiple arguments extractor' do
|
132
|
+
let(:pattern) { 'Date(year, 02, day)' }
|
133
|
+
|
134
|
+
context 'defined' do
|
135
|
+
let(:other) { Date.parse('2017-02-15') }
|
136
|
+
|
137
|
+
it { is_expected.to eq(Fear.none) }
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'not defined' do
|
141
|
+
let(:other) { Date.parse('2017-04-15') }
|
142
|
+
|
143
|
+
it { is_expected.to eq(Fear.some(<<-MSG.strip)) }
|
144
|
+
Expected `4` to match:
|
145
|
+
Date(year, 02, day)
|
146
|
+
~~~~~~~~~~~^
|
147
|
+
MSG
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|