monolens 0.2.0 → 0.5.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/README.md +6 -0
- data/bin/monolens +11 -0
- data/lib/monolens/array/compact.rb +2 -2
- data/lib/monolens/array/join.rb +2 -2
- data/lib/monolens/array/map.rb +45 -6
- data/lib/monolens/array.rb +2 -2
- data/lib/monolens/coerce/date.rb +22 -6
- data/lib/monolens/coerce/date_time.rb +30 -6
- data/lib/monolens/coerce/integer.rb +15 -0
- data/lib/monolens/coerce/string.rb +13 -0
- data/lib/monolens/coerce.rb +12 -3
- data/lib/monolens/command.rb +96 -0
- data/lib/monolens/core/chain.rb +2 -2
- data/lib/monolens/core/dig.rb +52 -0
- data/lib/monolens/core/mapping.rb +23 -3
- data/lib/monolens/core.rb +6 -0
- data/lib/monolens/error.rb +9 -2
- data/lib/monolens/error_handler.rb +21 -0
- data/lib/monolens/file.rb +2 -7
- data/lib/monolens/lens/fetch_support.rb +19 -0
- data/lib/monolens/lens/location.rb +17 -0
- data/lib/monolens/lens/options.rb +41 -0
- data/lib/monolens/lens.rb +39 -23
- data/lib/monolens/object/extend.rb +53 -0
- data/lib/monolens/object/keys.rb +8 -10
- data/lib/monolens/object/rename.rb +3 -3
- data/lib/monolens/object/select.rb +71 -15
- data/lib/monolens/object/transform.rb +34 -12
- data/lib/monolens/object/values.rb +34 -10
- data/lib/monolens/object.rb +6 -0
- data/lib/monolens/skip/null.rb +1 -1
- data/lib/monolens/str/downcase.rb +2 -2
- data/lib/monolens/str/split.rb +2 -2
- data/lib/monolens/str/strip.rb +3 -1
- data/lib/monolens/str/upcase.rb +2 -2
- data/lib/monolens/version.rb +1 -1
- data/lib/monolens.rb +6 -0
- data/spec/fixtures/coerce.yml +3 -2
- data/spec/fixtures/transform.yml +5 -4
- data/spec/monolens/array/test_map.rb +89 -6
- data/spec/monolens/coerce/test_date.rb +34 -4
- data/spec/monolens/coerce/test_datetime.rb +70 -7
- data/spec/monolens/coerce/test_integer.rb +46 -0
- data/spec/monolens/coerce/test_string.rb +15 -0
- data/spec/monolens/command/map-upcase.lens.yml +5 -0
- data/spec/monolens/command/names-with-null.json +5 -0
- data/spec/monolens/command/names.json +4 -0
- data/spec/monolens/command/robust-map-upcase.lens.yml +7 -0
- data/spec/monolens/core/test_dig.rb +78 -0
- data/spec/monolens/core/test_mapping.rb +53 -11
- data/spec/monolens/lens/test_options.rb +73 -0
- data/spec/monolens/object/test_extend.rb +94 -0
- data/spec/monolens/object/test_keys.rb +54 -22
- data/spec/monolens/object/test_rename.rb +1 -1
- data/spec/monolens/object/test_select.rb +217 -4
- data/spec/monolens/object/test_transform.rb +93 -6
- data/spec/monolens/object/test_values.rb +110 -12
- data/spec/monolens/test_command.rb +128 -0
- data/spec/monolens/test_error_traceability.rb +60 -0
- data/spec/monolens/test_lens.rb +1 -1
- data/spec/test_readme.rb +7 -5
- metadata +37 -2
@@ -4,8 +4,10 @@ describe Monolens, 'object.select' do
|
|
4
4
|
context 'when using symbols in the definition' do
|
5
5
|
subject do
|
6
6
|
Monolens.lens('object.select' => {
|
7
|
-
|
8
|
-
|
7
|
+
defn: {
|
8
|
+
name: [:firstname, :lastname],
|
9
|
+
status: :priority
|
10
|
+
}
|
9
11
|
})
|
10
12
|
end
|
11
13
|
|
@@ -39,8 +41,10 @@ describe Monolens, 'object.select' do
|
|
39
41
|
context 'when using strings in the definition' do
|
40
42
|
subject do
|
41
43
|
Monolens.lens('object.select' => {
|
42
|
-
'
|
43
|
-
|
44
|
+
'defn' => {
|
45
|
+
'name' => ['firstname', 'lastname'],
|
46
|
+
'status' => 'priority'
|
47
|
+
}
|
44
48
|
})
|
45
49
|
end
|
46
50
|
|
@@ -70,4 +74,213 @@ describe Monolens, 'object.select' do
|
|
70
74
|
expect(subject.call(input)).to eql(expected)
|
71
75
|
end
|
72
76
|
end
|
77
|
+
|
78
|
+
context 'when using strategy: first' do
|
79
|
+
subject do
|
80
|
+
Monolens.lens('object.select' => {
|
81
|
+
defn: {
|
82
|
+
name: [:firstname, :lastname],
|
83
|
+
status: :priority
|
84
|
+
},
|
85
|
+
strategy: 'first',
|
86
|
+
on_missing: on_missing
|
87
|
+
}.compact)
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'without on_missing' do
|
91
|
+
let(:on_missing) do
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'works as expected when first option is present' do
|
96
|
+
input = {
|
97
|
+
firstname: 'Bernard',
|
98
|
+
priority: 12
|
99
|
+
}
|
100
|
+
expected = {
|
101
|
+
name: 'Bernard',
|
102
|
+
status: 12
|
103
|
+
}
|
104
|
+
expect(subject.call(input)).to eql(expected)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'works as expected when second is present' do
|
108
|
+
input = {
|
109
|
+
lastname: 'Lambeau',
|
110
|
+
priority: 12
|
111
|
+
}
|
112
|
+
expected = {
|
113
|
+
name: 'Lambeau',
|
114
|
+
status: 12
|
115
|
+
}
|
116
|
+
expect(subject.call(input)).to eql(expected)
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'fails when none is present' do
|
120
|
+
input = {
|
121
|
+
priority: 12
|
122
|
+
}
|
123
|
+
expect {
|
124
|
+
subject.call(input)
|
125
|
+
}.to raise_error(Monolens::Error)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'with on_missing: skip' do
|
130
|
+
let(:on_missing) do
|
131
|
+
:skip
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'works as expected when missing' do
|
135
|
+
input = {
|
136
|
+
priority: 12
|
137
|
+
}
|
138
|
+
expected = {
|
139
|
+
status: 12
|
140
|
+
}
|
141
|
+
expect(subject.call(input)).to eql(expected)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'with on_missing: null' do
|
146
|
+
let(:on_missing) do
|
147
|
+
:null
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'works as expected when missing' do
|
151
|
+
input = {
|
152
|
+
priority: 12
|
153
|
+
}
|
154
|
+
expected = {
|
155
|
+
name: nil,
|
156
|
+
status: 12
|
157
|
+
}
|
158
|
+
expect(subject.call(input)).to eql(expected)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'when using an array as selection' do
|
164
|
+
subject do
|
165
|
+
Monolens.lens('object.select' => {
|
166
|
+
defn: [
|
167
|
+
:firstname,
|
168
|
+
:priority
|
169
|
+
]
|
170
|
+
})
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'works as expected' do
|
174
|
+
input = {
|
175
|
+
firstname: 'Bernard',
|
176
|
+
lastname: 'Lambeau',
|
177
|
+
priority: 12
|
178
|
+
}
|
179
|
+
expected = {
|
180
|
+
firstname: 'Bernard',
|
181
|
+
priority: 12
|
182
|
+
}
|
183
|
+
expect(subject.call(input)).to eql(expected)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context 'when a key is missing and no option' do
|
188
|
+
subject do
|
189
|
+
Monolens.lens('object.select' => {
|
190
|
+
defn: {
|
191
|
+
name: [:firstname, :lastname],
|
192
|
+
status: :priority
|
193
|
+
}
|
194
|
+
})
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'raises an error' do
|
198
|
+
input = {
|
199
|
+
firstname: 'Bernard'
|
200
|
+
}
|
201
|
+
expect{
|
202
|
+
subject.call(input)
|
203
|
+
}.to raise_error(Monolens::LensError, /lastname/)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
context 'when using on_missing: skip' do
|
208
|
+
subject do
|
209
|
+
Monolens.lens('object.select' => {
|
210
|
+
on_missing: :skip,
|
211
|
+
defn: {
|
212
|
+
name: [:firstname, :lastname],
|
213
|
+
status: :priority
|
214
|
+
}
|
215
|
+
})
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'works as expected' do
|
219
|
+
input = {
|
220
|
+
firstname: 'Bernard'
|
221
|
+
}
|
222
|
+
expected = {
|
223
|
+
name: ['Bernard']
|
224
|
+
}
|
225
|
+
expect(subject.call(input)).to eql(expected)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
context 'when using on_missing: null' do
|
230
|
+
subject do
|
231
|
+
Monolens.lens('object.select' => {
|
232
|
+
on_missing: :null,
|
233
|
+
defn: {
|
234
|
+
name: [:firstname, :lastname],
|
235
|
+
status: :priority
|
236
|
+
}
|
237
|
+
})
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'works as expected' do
|
241
|
+
input = {
|
242
|
+
firstname: 'Bernard'
|
243
|
+
}
|
244
|
+
expected = {
|
245
|
+
name: ['Bernard', nil],
|
246
|
+
status: nil
|
247
|
+
}
|
248
|
+
expect(subject.call(input)).to eql(expected)
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'works as expected' do
|
252
|
+
input = {
|
253
|
+
priority: 12
|
254
|
+
}
|
255
|
+
expected = {
|
256
|
+
name: [nil, nil],
|
257
|
+
status: 12
|
258
|
+
}
|
259
|
+
expect(subject.call(input)).to eql(expected)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
describe 'error traceability' do
|
264
|
+
let(:lens) do
|
265
|
+
Monolens.lens('object.select' => {
|
266
|
+
defn: {
|
267
|
+
status: :priority
|
268
|
+
}
|
269
|
+
})
|
270
|
+
end
|
271
|
+
|
272
|
+
subject do
|
273
|
+
lens.call(input)
|
274
|
+
rescue Monolens::LensError => ex
|
275
|
+
ex
|
276
|
+
end
|
277
|
+
|
278
|
+
let(:input) do
|
279
|
+
{}
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'correctly updates the location' do
|
283
|
+
expect(subject.location).to eql(['status'])
|
284
|
+
end
|
285
|
+
end
|
73
286
|
end
|
@@ -1,15 +1,102 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Monolens, 'object.transform' do
|
4
|
-
|
5
|
-
|
4
|
+
context 'with default options' do
|
5
|
+
subject do
|
6
|
+
Monolens.lens('object.transform' => {
|
7
|
+
defn: { firstname: 'str.upcase' }
|
8
|
+
})
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'works as expected' do
|
12
|
+
expect(subject.call(firstname: 'Bernard')).to eql(firstname: 'BERNARD')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'works as expected on an object with String keys' do
|
16
|
+
expect(subject.call('firstname' => 'Bernard')).to eql('firstname' => 'BERNARD')
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'raises an error if input object does not have a key' do
|
20
|
+
expect {
|
21
|
+
subject.call(lastname: 'Lambeau')
|
22
|
+
}.to raise_error(Monolens::LensError, /firstname/)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'with on_missing: skip' do
|
27
|
+
subject do
|
28
|
+
Monolens.lens('object.transform' => {
|
29
|
+
on_missing: :skip,
|
30
|
+
defn: { firstname: 'str.upcase' }
|
31
|
+
})
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'works as expected' do
|
35
|
+
expect(subject.call(firstname: 'Bernard')).to eql(firstname: 'BERNARD')
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'skpis if missing' do
|
39
|
+
expect(subject.call(lastname: 'Lambeau')).to eql(lastname: 'Lambeau')
|
40
|
+
end
|
6
41
|
end
|
7
42
|
|
8
|
-
|
9
|
-
|
43
|
+
context 'with on_missing: null' do
|
44
|
+
subject do
|
45
|
+
Monolens.lens('object.transform' => {
|
46
|
+
on_missing: :null,
|
47
|
+
defn: { firstname: 'str.upcase' }
|
48
|
+
})
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'works as expected' do
|
52
|
+
expect(subject.call(firstname: 'Bernard')).to eql(firstname: 'BERNARD')
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'skpis if missing' do
|
56
|
+
expect(subject.call(lastname: 'Lambeau')).to eql(firstname: nil, lastname: 'Lambeau')
|
57
|
+
end
|
10
58
|
end
|
11
59
|
|
12
|
-
|
13
|
-
|
60
|
+
describe 'error traceability' do
|
61
|
+
let(:lens) do
|
62
|
+
Monolens.lens({
|
63
|
+
'array.map' => {
|
64
|
+
:lenses => {
|
65
|
+
'object.transform' => {
|
66
|
+
defn: { firstname: 'str.upcase' }
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
})
|
71
|
+
end
|
72
|
+
|
73
|
+
subject do
|
74
|
+
lens.call(input)
|
75
|
+
nil
|
76
|
+
rescue Monolens::LensError => ex
|
77
|
+
ex
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'when missing key' do
|
81
|
+
let(:input) do
|
82
|
+
[{}]
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'correctly updates the location' do
|
86
|
+
expect(subject.location).to eql([0])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'when an error down the line' do
|
91
|
+
let(:input) do
|
92
|
+
[{
|
93
|
+
firstname: nil
|
94
|
+
}]
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'correctly updates the location' do
|
98
|
+
expect(subject.location).to eql([0, :firstname])
|
99
|
+
end
|
100
|
+
end
|
14
101
|
end
|
15
102
|
end
|
@@ -1,19 +1,117 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Monolens, 'object.values' do
|
4
|
-
|
5
|
-
|
4
|
+
context 'with default options' do
|
5
|
+
subject do
|
6
|
+
Monolens.lens('object.values' => ['str.upcase'])
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'works as expected' do
|
10
|
+
input = {
|
11
|
+
firstname: 'Bernard',
|
12
|
+
lastname: 'Lambeau'
|
13
|
+
}
|
14
|
+
expected = {
|
15
|
+
firstname: 'BERNARD',
|
16
|
+
lastname: 'LAMBEAU'
|
17
|
+
}
|
18
|
+
expect(subject.call(input)).to eql(expected)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'raises an error on any problem' do
|
22
|
+
input = {
|
23
|
+
firstname: nil,
|
24
|
+
lastname: 'Lambeau'
|
25
|
+
}
|
26
|
+
expect {
|
27
|
+
subject.call(input)
|
28
|
+
}.to raise_error(Monolens::LensError)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with on_error: skip' do
|
33
|
+
subject do
|
34
|
+
Monolens.lens('object.values' => {
|
35
|
+
'on_error' => 'skip',
|
36
|
+
'lenses' => ['str.upcase']
|
37
|
+
})
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'skips key/value when an error occurs' do
|
41
|
+
input = {
|
42
|
+
firstname: nil,
|
43
|
+
lastname: 'Lambeau'
|
44
|
+
}
|
45
|
+
expected = {
|
46
|
+
lastname: 'LAMBEAU'
|
47
|
+
}
|
48
|
+
expect(subject.call(input)).to eql(expected)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'with on_error: null' do
|
53
|
+
subject do
|
54
|
+
Monolens.lens('object.values' => {
|
55
|
+
'on_error' => 'null',
|
56
|
+
'lenses' => ['str.upcase']
|
57
|
+
})
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'uses nil as value' do
|
61
|
+
input = {
|
62
|
+
firstname: 12,
|
63
|
+
lastname: 'Lambeau'
|
64
|
+
}
|
65
|
+
expected = {
|
66
|
+
firstname: nil,
|
67
|
+
lastname: 'LAMBEAU'
|
68
|
+
}
|
69
|
+
expect(subject.call(input)).to eql(expected)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'with on_error: keep' do
|
74
|
+
subject do
|
75
|
+
Monolens.lens('object.values' => {
|
76
|
+
'on_error' => 'keep',
|
77
|
+
'lenses' => ['str.upcase']
|
78
|
+
})
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'uses nil as value' do
|
82
|
+
input = {
|
83
|
+
firstname: 12,
|
84
|
+
lastname: 'Lambeau'
|
85
|
+
}
|
86
|
+
expected = {
|
87
|
+
firstname: 12,
|
88
|
+
lastname: 'LAMBEAU'
|
89
|
+
}
|
90
|
+
expect(subject.call(input)).to eql(expected)
|
91
|
+
end
|
6
92
|
end
|
7
93
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
94
|
+
describe 'error traceability' do
|
95
|
+
let(:lens) do
|
96
|
+
Monolens.lens('object.values' => ['str.upcase'])
|
97
|
+
end
|
98
|
+
|
99
|
+
subject do
|
100
|
+
lens.call(input)
|
101
|
+
nil
|
102
|
+
rescue Monolens::LensError => ex
|
103
|
+
ex
|
104
|
+
end
|
105
|
+
|
106
|
+
let(:input) do
|
107
|
+
{
|
108
|
+
'firstname' => 'Bernard',
|
109
|
+
'lastname' => nil
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'correctly updates the location' do
|
114
|
+
expect(subject.location).to eql(['lastname'])
|
115
|
+
end
|
18
116
|
end
|
19
117
|
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'stringio'
|
3
|
+
require 'monolens'
|
4
|
+
require 'monolens/command'
|
5
|
+
|
6
|
+
module Monolens
|
7
|
+
class Exited < Monolens::Error
|
8
|
+
end
|
9
|
+
class Command
|
10
|
+
attr_reader :exit_status
|
11
|
+
|
12
|
+
def do_exit(status)
|
13
|
+
@exit_status = status
|
14
|
+
raise Exited
|
15
|
+
end
|
16
|
+
end
|
17
|
+
describe Command do
|
18
|
+
FIXTURES = (Path.dir/"command").expand_path
|
19
|
+
|
20
|
+
let(:command) do
|
21
|
+
Command.new(argv, stdin, stdout, stderr)
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:stdin) do
|
25
|
+
StringIO.new
|
26
|
+
end
|
27
|
+
|
28
|
+
let(:stdout) do
|
29
|
+
StringIO.new
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:stderr) do
|
33
|
+
StringIO.new
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:file_args) do
|
37
|
+
[FIXTURES/'map-upcase.lens.yml', FIXTURES/'names.json']
|
38
|
+
end
|
39
|
+
|
40
|
+
subject do
|
41
|
+
begin
|
42
|
+
command.call
|
43
|
+
rescue Exited
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
before do
|
48
|
+
subject
|
49
|
+
end
|
50
|
+
|
51
|
+
def exit_status
|
52
|
+
command.exit_status
|
53
|
+
end
|
54
|
+
|
55
|
+
def reloaded_json
|
56
|
+
JSON.parse(stdout.string)
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'with no option nor args' do
|
60
|
+
let(:argv) do
|
61
|
+
[]
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'prints the help and exits' do
|
65
|
+
expect(exit_status).to eql(0)
|
66
|
+
expect(stdout.string).to match(/monolens/)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'with --version' do
|
71
|
+
let(:argv) do
|
72
|
+
['--version']
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'prints the version and exits' do
|
76
|
+
expect(exit_status).to eql(0)
|
77
|
+
expect(stdout.string).to eql("Monolens v#{VERSION} - (c) Enspirit #{Date.today.year}\n")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'with a lens and a json input' do
|
82
|
+
let(:argv) do
|
83
|
+
file_args
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'works as expected' do
|
87
|
+
expect(exit_status).to be_nil
|
88
|
+
expect(reloaded_json).to eql(['BERNARD', 'DAVID'])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'with --pretty' do
|
93
|
+
let(:argv) do
|
94
|
+
['--pretty'] + file_args
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'works as expected' do
|
98
|
+
expect(exit_status).to be_nil
|
99
|
+
expect(stdout.string).to match(/^\[\n/)
|
100
|
+
expect(reloaded_json).to eql(['BERNARD', 'DAVID'])
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'when yielding an error' do
|
105
|
+
let(:argv) do
|
106
|
+
[FIXTURES/'map-upcase.lens.yml', FIXTURES/'names-with-null.json']
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'works as expected' do
|
110
|
+
expect(exit_status).to eql(-2)
|
111
|
+
expect(stdout.string).to eql('')
|
112
|
+
expect(stderr.string).to eql("[1] String expected, got NilClass\n")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'when yielding an error on a robust lens' do
|
117
|
+
let(:argv) do
|
118
|
+
[FIXTURES/'robust-map-upcase.lens.yml', FIXTURES/'names-with-null.json']
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'works as expected' do
|
122
|
+
expect(exit_status).to be_nil
|
123
|
+
expect(stdout.string).to eql('["BERNARD","DAVID"]'+"\n")
|
124
|
+
expect(stderr.string).to eql("[1] String expected, got NilClass\n")
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, 'error traceability' do
|
4
|
+
context 'on a leaf monolens' do
|
5
|
+
let(:lens) do
|
6
|
+
Monolens.lens('str.upcase')
|
7
|
+
end
|
8
|
+
|
9
|
+
subject do
|
10
|
+
begin
|
11
|
+
lens.call(nil)
|
12
|
+
rescue => ex
|
13
|
+
ex
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'works as expected' do
|
18
|
+
expect(subject).to be_a(Monolens::LensError)
|
19
|
+
expect(subject.location).to eql([])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'on array.map' do
|
24
|
+
let(:lens) do
|
25
|
+
Monolens.lens('array.map' => 'str.upcase')
|
26
|
+
end
|
27
|
+
|
28
|
+
subject do
|
29
|
+
begin
|
30
|
+
lens.call(['foo', nil])
|
31
|
+
rescue => ex
|
32
|
+
ex
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'works as expected' do
|
37
|
+
expect(subject).to be_a(Monolens::LensError)
|
38
|
+
expect(subject.location).to eql([1])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'on array.map => object.values' do
|
43
|
+
let(:lens) do
|
44
|
+
Monolens.lens('array.map' => { lenses: { 'object.values' => 'str.upcase' } })
|
45
|
+
end
|
46
|
+
|
47
|
+
subject do
|
48
|
+
begin
|
49
|
+
lens.call([{ hello: 'foo' }, { hello: nil }])
|
50
|
+
rescue Monolens::LensError => ex
|
51
|
+
ex
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'works as expected' do
|
56
|
+
expect(subject).to be_a(Monolens::LensError)
|
57
|
+
expect(subject.location).to eql([1, :hello])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/spec/monolens/test_lens.rb
CHANGED
@@ -16,7 +16,7 @@ describe Monolens, '.lens' do
|
|
16
16
|
it 'preserves options' do
|
17
17
|
got = Monolens.lens(:"coerce.date" => { formats: ['%Y'] })
|
18
18
|
expect(got).to be_a(Monolens::Coerce::Date)
|
19
|
-
expect(got.options).to eql({ formats: ['%Y'] })
|
19
|
+
expect(got.options.to_h).to eql({ formats: ['%Y'] })
|
20
20
|
end
|
21
21
|
|
22
22
|
it 'allows using an Array, factors a Chain with coercion recursion' do
|
data/spec/test_readme.rb
CHANGED
@@ -23,12 +23,14 @@ describe "What's said in README" do
|
|
23
23
|
lenses:
|
24
24
|
- array.map:
|
25
25
|
- object.transform:
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
defn:
|
27
|
+
status:
|
28
|
+
- str.upcase
|
29
|
+
body:
|
30
|
+
- str.strip
|
30
31
|
- object.rename:
|
31
|
-
|
32
|
+
defn:
|
33
|
+
body: description
|
32
34
|
YML
|
33
35
|
}
|
34
36
|
|