fear 0.11.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|