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.
Files changed (110) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +0 -1
  3. data/.rubocop.yml +18 -0
  4. data/.travis.yml +0 -3
  5. data/CHANGELOG.md +12 -1
  6. data/Gemfile +1 -0
  7. data/{gemfiles/dry_equalizer_0.2.1.gemfile.lock → Gemfile.lock} +21 -12
  8. data/README.md +594 -241
  9. data/Rakefile +166 -219
  10. data/benchmarks/README.md +1 -0
  11. data/benchmarks/dry_do_vs_fear_for.txt +11 -0
  12. data/benchmarks/dry_some_fmap_vs_fear_some_map.txt +11 -0
  13. data/benchmarks/factorial.txt +16 -0
  14. data/benchmarks/fear_gaurd_and1_vs_new.txt +13 -0
  15. data/benchmarks/fear_gaurd_and2_vs_and.txt +13 -0
  16. data/benchmarks/fear_gaurd_and3_vs_and_and.txt +13 -0
  17. data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +11 -0
  18. data/benchmarks/fear_pattern_matching_construction_vs_execution.txt +13 -0
  19. data/benchmarks/pattern_matching_dry_vs_qo_vs_fear_try.txt +14 -0
  20. data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +11 -0
  21. data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +11 -0
  22. data/examples/pattern_extracting.rb +15 -0
  23. data/examples/pattern_matching_binary_tree_set.rb +96 -0
  24. data/examples/pattern_matching_number_in_words.rb +54 -0
  25. data/fear.gemspec +4 -2
  26. data/lib/fear.rb +21 -4
  27. data/lib/fear/either.rb +77 -59
  28. data/lib/fear/either_api.rb +21 -0
  29. data/lib/fear/empty_partial_function.rb +1 -1
  30. data/lib/fear/extractor.rb +108 -0
  31. data/lib/fear/extractor/anonymous_array_splat_matcher.rb +8 -0
  32. data/lib/fear/extractor/any_matcher.rb +15 -0
  33. data/lib/fear/extractor/array_head_matcher.rb +34 -0
  34. data/lib/fear/extractor/array_matcher.rb +38 -0
  35. data/lib/fear/extractor/array_splat_matcher.rb +14 -0
  36. data/lib/fear/extractor/empty_list_matcher.rb +18 -0
  37. data/lib/fear/extractor/extractor_matcher.rb +42 -0
  38. data/lib/fear/extractor/grammar.rb +201 -0
  39. data/lib/fear/extractor/grammar.treetop +129 -0
  40. data/lib/fear/extractor/identifier_matcher.rb +16 -0
  41. data/lib/fear/extractor/matcher.rb +54 -0
  42. data/lib/fear/extractor/matcher/and.rb +36 -0
  43. data/lib/fear/extractor/named_array_splat_matcher.rb +15 -0
  44. data/lib/fear/extractor/pattern.rb +55 -0
  45. data/lib/fear/extractor/typed_identifier_matcher.rb +24 -0
  46. data/lib/fear/extractor/value_matcher.rb +17 -0
  47. data/lib/fear/extractor_api.rb +33 -0
  48. data/lib/fear/failure.rb +32 -10
  49. data/lib/fear/for.rb +14 -69
  50. data/lib/fear/for_api.rb +66 -0
  51. data/lib/fear/future.rb +414 -0
  52. data/lib/fear/future_api.rb +19 -0
  53. data/lib/fear/left.rb +8 -0
  54. data/lib/fear/none.rb +17 -8
  55. data/lib/fear/option.rb +55 -49
  56. data/lib/fear/option_api.rb +38 -0
  57. data/lib/fear/partial_function.rb +9 -12
  58. data/lib/fear/partial_function/empty.rb +1 -1
  59. data/lib/fear/partial_function/guard.rb +8 -20
  60. data/lib/fear/partial_function/lifted.rb +1 -0
  61. data/lib/fear/partial_function_class.rb +10 -0
  62. data/lib/fear/pattern_match.rb +10 -0
  63. data/lib/fear/pattern_matching_api.rb +35 -11
  64. data/lib/fear/promise.rb +87 -0
  65. data/lib/fear/right.rb +8 -0
  66. data/lib/fear/some.rb +22 -3
  67. data/lib/fear/success.rb +22 -1
  68. data/lib/fear/try.rb +82 -67
  69. data/lib/fear/try_api.rb +31 -0
  70. data/lib/fear/unit.rb +28 -0
  71. data/lib/fear/version.rb +1 -1
  72. data/spec/fear/done_spec.rb +3 -3
  73. data/spec/fear/either/mixin_spec.rb +15 -0
  74. data/spec/fear/either_pattern_match_spec.rb +10 -12
  75. data/spec/fear/extractor/array_matcher_spec.rb +228 -0
  76. data/spec/fear/extractor/extractor_matcher_spec.rb +151 -0
  77. data/spec/fear/extractor/grammar_array_spec.rb +23 -0
  78. data/spec/fear/extractor/identified_matcher_spec.rb +47 -0
  79. data/spec/fear/extractor/identifier_matcher_spec.rb +66 -0
  80. data/spec/fear/extractor/pattern_spec.rb +32 -0
  81. data/spec/fear/extractor/typed_identifier_matcher_spec.rb +62 -0
  82. data/spec/fear/extractor/value_matcher_number_spec.rb +77 -0
  83. data/spec/fear/extractor/value_matcher_string_spec.rb +86 -0
  84. data/spec/fear/extractor/value_matcher_symbol_spec.rb +69 -0
  85. data/spec/fear/extractor_api_spec.rb +113 -0
  86. data/spec/fear/extractor_spec.rb +59 -0
  87. data/spec/fear/failure_spec.rb +73 -13
  88. data/spec/fear/for_spec.rb +35 -35
  89. data/spec/fear/future_spec.rb +466 -0
  90. data/spec/fear/guard_spec.rb +4 -4
  91. data/spec/fear/left_spec.rb +40 -14
  92. data/spec/fear/none_spec.rb +28 -12
  93. data/spec/fear/option/mixin_spec.rb +37 -0
  94. data/spec/fear/option_pattern_match_spec.rb +7 -9
  95. data/spec/fear/partial_function_spec.rb +25 -3
  96. data/spec/fear/pattern_match_spec.rb +33 -1
  97. data/spec/fear/promise_spec.rb +94 -0
  98. data/spec/fear/right_spec.rb +37 -9
  99. data/spec/fear/some_spec.rb +32 -6
  100. data/spec/fear/success_spec.rb +32 -4
  101. data/spec/fear/try/mixin_spec.rb +17 -0
  102. data/spec/fear/try_pattern_match_spec.rb +8 -10
  103. data/spec/spec_helper.rb +1 -1
  104. metadata +115 -20
  105. data/Appraisals +0 -32
  106. data/gemfiles/dry_equalizer_0.1.0.gemfile +0 -8
  107. data/gemfiles/dry_equalizer_0.1.0.gemfile.lock +0 -82
  108. data/gemfiles/dry_equalizer_0.2.1.gemfile +0 -8
  109. data/lib/fear/done.rb +0 -22
  110. data/spec/fear/option_spec.rb +0 -15
@@ -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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Fear
2
- VERSION = '0.11.0'.freeze
2
+ VERSION = '1.0.0'.freeze
3
3
  end
@@ -1,14 +1,14 @@
1
- RSpec.describe Fear::Done do
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('Done') }
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('Done') }
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?) { |x| "#{x} is even" }
8
- m.right(:odd?) { |x| "#{x} is 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(Right(4))).to eq('4 is even')
14
- expect(matcher.call(Right(3))).to eq('3 is odd')
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(Left(44))
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?) { |x| "#{x} is even" }
25
- m.left(:odd?) { |x| "#{x} is 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(Left(4))).to eq('4 is even')
31
- expect(matcher.call(Left(3))).to eq('3 is odd')
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(Right(44))
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