monolens 0.1.0 → 0.4.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/README.md +14 -4
- data/bin/monolens +11 -0
- data/lib/monolens/array/compact.rb +2 -2
- data/lib/monolens/array/join.rb +13 -0
- data/lib/monolens/array/map.rb +57 -0
- data/lib/monolens/array.rb +12 -0
- 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 +87 -0
- data/lib/monolens/core/chain.rb +2 -2
- data/lib/monolens/core/dig.rb +52 -0
- data/lib/monolens/core/mapping.rb +15 -0
- data/lib/monolens/core.rb +10 -4
- 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 +41 -18
- 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 +58 -0
- data/lib/monolens/object/transform.rb +34 -12
- data/lib/monolens/object/values.rb +34 -10
- data/lib/monolens/object.rb +12 -0
- data/lib/monolens/skip/null.rb +1 -1
- data/lib/monolens/str/downcase.rb +2 -2
- data/lib/monolens/str/split.rb +14 -0
- data/lib/monolens/str/strip.rb +3 -1
- data/lib/monolens/str/upcase.rb +2 -2
- data/lib/monolens/str.rb +12 -6
- data/lib/monolens/version.rb +1 -1
- data/lib/monolens.rb +7 -1
- data/spec/fixtures/coerce.yml +3 -2
- data/spec/fixtures/transform.yml +5 -4
- data/spec/monolens/array/test_compact.rb +15 -0
- data/spec/monolens/array/test_join.rb +27 -0
- data/spec/monolens/array/test_map.rb +96 -0
- 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 +76 -0
- 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 +202 -0
- data/spec/monolens/object/test_transform.rb +93 -6
- data/spec/monolens/object/test_values.rb +110 -12
- data/spec/monolens/skip/test_null.rb +2 -2
- data/spec/monolens/str/test_downcase.rb +13 -0
- data/spec/monolens/str/test_split.rb +39 -0
- data/spec/monolens/str/test_strip.rb +13 -0
- data/spec/monolens/str/test_upcase.rb +13 -0
- 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 +8 -6
- metadata +39 -5
- data/lib/monolens/core/map.rb +0 -18
- data/spec/monolens/core/test_map.rb +0 -11
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, 'array.map' do
|
4
|
+
context 'without options' do
|
5
|
+
subject do
|
6
|
+
Monolens.lens('array.map' => 'str.upcase')
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'joins values with spaces' do
|
10
|
+
input = ['hello', 'world']
|
11
|
+
expected = ['HELLO', 'WORLD']
|
12
|
+
expect(subject.call(input)).to eql(expected)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'default on error' do
|
17
|
+
subject do
|
18
|
+
Monolens.lens('array.map' => {
|
19
|
+
lenses: [ 'str.upcase' ]
|
20
|
+
})
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'raise errors' do
|
24
|
+
input = [nil, 'world']
|
25
|
+
expect {
|
26
|
+
subject.call(input)
|
27
|
+
}.to raise_error(Monolens::LensError)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'skipping on error' do
|
32
|
+
subject do
|
33
|
+
Monolens.lens('array.map' => {
|
34
|
+
on_error: 'skip',
|
35
|
+
lenses: [ 'str.upcase' ]
|
36
|
+
})
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'skips errors' do
|
40
|
+
input = [nil, 'world']
|
41
|
+
expected = ['WORLD']
|
42
|
+
expect(subject.call(input)).to eql(expected)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'nulling on error' do
|
47
|
+
subject do
|
48
|
+
Monolens.lens('array.map' => {
|
49
|
+
on_error: 'null',
|
50
|
+
lenses: [ 'str.upcase' ]
|
51
|
+
})
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'skips errors' do
|
55
|
+
input = [nil, 'world']
|
56
|
+
expected = [nil, 'WORLD']
|
57
|
+
expect(subject.call(input)).to eql(expected)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'on error with :handler' do
|
62
|
+
subject do
|
63
|
+
Monolens.lens('array.map' => {
|
64
|
+
on_error: 'handler',
|
65
|
+
lenses: [ 'str.upcase' ]
|
66
|
+
})
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'collects the error then skips' do
|
70
|
+
input = [nil, 'world']
|
71
|
+
expected = ['WORLD']
|
72
|
+
errs = []
|
73
|
+
got = subject.call(input, error_handler: ->(err){ errs << err })
|
74
|
+
expect(errs.size).to eql(1)
|
75
|
+
expect(got).to eql(expected)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'collecting on error then nulling' do
|
80
|
+
subject do
|
81
|
+
Monolens.lens('array.map' => {
|
82
|
+
on_error: ['handler', 'null'],
|
83
|
+
lenses: [ 'str.upcase' ]
|
84
|
+
})
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'uses the handler' do
|
88
|
+
input = [nil, 'world']
|
89
|
+
expected = [nil, 'WORLD']
|
90
|
+
errs = []
|
91
|
+
got = subject.call(input, error_handler: ->(err){ errs << err })
|
92
|
+
expect(errs.size).to eql(1)
|
93
|
+
expect(got).to eql(expected)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -5,13 +5,43 @@ describe Monolens, 'coerce.date' do
|
|
5
5
|
Monolens.lens('coerce.date' => { formats: ['%d/%m/%Y'] })
|
6
6
|
end
|
7
7
|
|
8
|
+
it 'returns Date objects unchanged (idempotency)' do
|
9
|
+
input = Date.today
|
10
|
+
expect(subject.call(input)).to be(input)
|
11
|
+
end
|
12
|
+
|
8
13
|
it 'coerces valid dates' do
|
9
14
|
expect(subject.call('11/12/2022')).to eql(Date.parse('2022-12-11'))
|
10
15
|
end
|
11
16
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
17
|
+
describe 'error handling' do
|
18
|
+
let(:lens) do
|
19
|
+
Monolens.lens({
|
20
|
+
'array.map' => {
|
21
|
+
:lenses => 'coerce.date'
|
22
|
+
}
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
subject do
|
27
|
+
begin
|
28
|
+
lens.call(input)
|
29
|
+
nil
|
30
|
+
rescue Monolens::LensError => ex
|
31
|
+
ex
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
let(:input) do
|
36
|
+
['invalid']
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'fails on invalid dates' do
|
40
|
+
expect(subject).to be_a(Monolens::LensError)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'properly sets the location' do
|
44
|
+
expect(subject.location).to eql([0])
|
45
|
+
end
|
16
46
|
end
|
17
47
|
end
|
@@ -2,16 +2,79 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Monolens, 'coerce.datetime' do
|
4
4
|
subject do
|
5
|
-
Monolens.lens('coerce.datetime' => {
|
5
|
+
Monolens.lens('coerce.datetime' => {
|
6
|
+
}.merge(options))
|
6
7
|
end
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
let(:options) do
|
10
|
+
{}
|
10
11
|
end
|
11
12
|
|
12
|
-
it '
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
it 'returns DateTime objects unchanged (idempotency)' do
|
14
|
+
input = DateTime.now
|
15
|
+
expect(subject.call(input)).to be(input)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'support for formats' do
|
19
|
+
let(:options) do
|
20
|
+
{ formats: ['%d/%m/%Y %H:%M'] }
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'coerces valid date times' do
|
24
|
+
expect(subject.call('11/12/2022 17:38')).to eql(DateTime.parse('2022-12-11 17:38'))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'support for a timezone' do
|
29
|
+
let(:options) do
|
30
|
+
{ parser: timezone }
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:now) do
|
34
|
+
::DateTime.now
|
35
|
+
end
|
36
|
+
|
37
|
+
let(:timezone) do
|
38
|
+
Object.new
|
39
|
+
end
|
40
|
+
|
41
|
+
before do
|
42
|
+
expect(timezone).to receive(:parse).and_return(now)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'uses it to parse' do
|
46
|
+
expect(subject.call('2022-01-01')).to be(now)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'error handling' do
|
51
|
+
let(:lens) do
|
52
|
+
Monolens.lens({
|
53
|
+
'array.map' => {
|
54
|
+
:lenses => 'coerce.datetime'
|
55
|
+
}
|
56
|
+
})
|
57
|
+
end
|
58
|
+
|
59
|
+
subject do
|
60
|
+
begin
|
61
|
+
lens.call(input)
|
62
|
+
nil
|
63
|
+
rescue Monolens::LensError => ex
|
64
|
+
ex
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
let(:input) do
|
69
|
+
['invalid']
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'fails on invalid dates' do
|
73
|
+
expect(subject).to be_a(Monolens::LensError)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'properly sets the location' do
|
77
|
+
expect(subject.location).to eql([0])
|
78
|
+
end
|
16
79
|
end
|
17
80
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, 'coerce.integer' do
|
4
|
+
subject do
|
5
|
+
Monolens.lens('coerce.integer')
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'is idempotent' do
|
9
|
+
expect(subject.call(12)).to eql(12)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'coerces valid integers' do
|
13
|
+
expect(subject.call('12')).to eql(12)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'error handling' do
|
17
|
+
let(:lens) do
|
18
|
+
Monolens.lens({
|
19
|
+
'array.map' => {
|
20
|
+
:lenses => 'coerce.integer'
|
21
|
+
}
|
22
|
+
})
|
23
|
+
end
|
24
|
+
|
25
|
+
subject do
|
26
|
+
begin
|
27
|
+
lens.call(input)
|
28
|
+
nil
|
29
|
+
rescue Monolens::LensError => ex
|
30
|
+
ex
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
let(:input) do
|
35
|
+
['12sh']
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'fails on invalid integers' do
|
39
|
+
expect(subject).to be_a(Monolens::LensError)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'properly sets the location' do
|
43
|
+
expect(subject.location).to eql([0])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, 'coerce.string' do
|
4
|
+
subject do
|
5
|
+
Monolens.lens('coerce.string')
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'works' do
|
9
|
+
expect(subject.call(12)).to eql('12')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'accepts null' do
|
13
|
+
expect(subject.call(nil)).to eql('')
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, "core.dig" do
|
4
|
+
let(:lens) do
|
5
|
+
Monolens.lens('core.dig' => { defn: ['hobbies', 1, 'name'] })
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'works' do
|
9
|
+
input = {
|
10
|
+
hobbies: [
|
11
|
+
{ name: 'programming' },
|
12
|
+
{ name: 'music' }
|
13
|
+
]
|
14
|
+
}
|
15
|
+
expected = 'music'
|
16
|
+
expect(lens.call(input)).to eql(expected)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'error handling' do
|
20
|
+
let(:lens) do
|
21
|
+
Monolens.lens({
|
22
|
+
'array.map' => {
|
23
|
+
lenses: {
|
24
|
+
'core.dig' => {
|
25
|
+
on_missing: on_missing,
|
26
|
+
defn: ['hobbies', 1, 'name']
|
27
|
+
}.compact
|
28
|
+
}
|
29
|
+
}
|
30
|
+
})
|
31
|
+
end
|
32
|
+
|
33
|
+
subject do
|
34
|
+
begin
|
35
|
+
lens.call(input)
|
36
|
+
rescue Monolens::LensError => ex
|
37
|
+
ex
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'default behavior' do
|
42
|
+
let(:on_missing) do
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
|
46
|
+
let(:input) do
|
47
|
+
[{
|
48
|
+
hobbies: [
|
49
|
+
{ name: 'programming' }
|
50
|
+
]
|
51
|
+
}]
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'fails as expected' do
|
55
|
+
expect(subject).to be_a(Monolens::LensError)
|
56
|
+
expect(subject.location).to eql([0])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'on_missing: null' do
|
61
|
+
let(:on_missing) do
|
62
|
+
:null
|
63
|
+
end
|
64
|
+
|
65
|
+
let(:input) do
|
66
|
+
[{
|
67
|
+
hobbies: [
|
68
|
+
{ name: 'programming' }
|
69
|
+
]
|
70
|
+
}]
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'works' do
|
74
|
+
expect(subject).to eql([nil])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, 'core.mapping' do
|
4
|
+
let(:mapping) do
|
5
|
+
{ 'values' => { 'todo' => 'open' }}
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'with default options' do
|
9
|
+
subject do
|
10
|
+
Monolens.lens('core.mapping' => mapping)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'replaces the value by its mapped' do
|
14
|
+
expect(subject.call('todo')).to eql('open')
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'returns nil if not found' do
|
18
|
+
expect(subject.call('nosuchone')).to eql(nil)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'specifying a default value' do
|
23
|
+
subject do
|
24
|
+
Monolens.lens('core.mapping' => mapping.merge('default' => 'foo'))
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'replaces the value by its mapped' do
|
28
|
+
expect(subject.call('todo')).to eql('open')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns the default if not found' do
|
32
|
+
expect(subject.call('nosuchone')).to eql('foo')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'lets raise if not found' do
|
37
|
+
subject do
|
38
|
+
Monolens.lens('core.mapping' => mapping.merge('fail_if_missing' => true))
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'replaces the value by its mapped' do
|
42
|
+
expect(subject.call('todo')).to eql('open')
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'raises if not found' do
|
46
|
+
expect {
|
47
|
+
subject.call('nosuchone')
|
48
|
+
}.to raise_error(Monolens::LensError)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'error handling' do
|
53
|
+
let(:lens) do
|
54
|
+
Monolens.lens({
|
55
|
+
'array.map' => {
|
56
|
+
:lenses => {
|
57
|
+
'core.mapping' => mapping.merge('fail_if_missing' => true)
|
58
|
+
}
|
59
|
+
}
|
60
|
+
})
|
61
|
+
end
|
62
|
+
|
63
|
+
subject do
|
64
|
+
begin
|
65
|
+
lens.call(['todo', 'foo'])
|
66
|
+
nil
|
67
|
+
rescue Monolens::LensError => ex
|
68
|
+
ex
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'sets the location correctly' do
|
73
|
+
expect(subject.location).to eql([1])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Monolens
|
4
|
+
module Lens
|
5
|
+
describe Options do
|
6
|
+
subject do
|
7
|
+
Options.new(input)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'initialize' do
|
11
|
+
context('when used with a Hash') do
|
12
|
+
let(:input) do
|
13
|
+
{ separator: ',' }
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'uses a copy of the hash' do
|
17
|
+
expect(subject.send(:options)).not_to be(input)
|
18
|
+
expect(subject.to_h).not_to be(input)
|
19
|
+
expect(subject.to_h).to eql(input)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context('when used with an Array') do
|
24
|
+
let(:input) do
|
25
|
+
['str.strip']
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'converts it to lenses' do
|
29
|
+
expect(subject.to_h.keys).to eql([:lenses])
|
30
|
+
lenses = subject.to_h[:lenses]
|
31
|
+
expect(lenses).to be_a(Core::Chain)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context('when used with a String') do
|
36
|
+
let(:input) do
|
37
|
+
'str.strip'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'converts it to lenses' do
|
41
|
+
expect(subject.to_h.keys).to eql([:lenses])
|
42
|
+
lenses = subject.to_h[:lenses]
|
43
|
+
expect(lenses).to be_a(Str::Strip)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'fetch' do
|
49
|
+
context 'when used with Symbols' do
|
50
|
+
let(:input) do
|
51
|
+
{ separator: ',' }
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'lets fetch as Symbols' do
|
55
|
+
expect(subject.fetch(:separator)).to eql(',')
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'lets fetch as Strings' do
|
59
|
+
expect(subject.fetch('separator')).to eql(',')
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'raises if not found' do
|
63
|
+
expect { subject.fetch('nosuchone') }.to raise_error(Monolens::Error)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'lets pass a default value' do
|
67
|
+
expect(subject.fetch('nosuchone', 'foo')).to eql('foo')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, 'object.extend' do
|
4
|
+
subject do
|
5
|
+
Monolens.lens('object.extend' => {
|
6
|
+
defn: {
|
7
|
+
name: [
|
8
|
+
{ 'core.dig' => { defn: ['firstname'] } },
|
9
|
+
'str.upcase'
|
10
|
+
]
|
11
|
+
}
|
12
|
+
})
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'works as expected' do
|
16
|
+
input = {
|
17
|
+
'firstname' => 'Bernard',
|
18
|
+
'lastname' => 'Lambeau'
|
19
|
+
}
|
20
|
+
expected = input.merge({
|
21
|
+
'name' => 'BERNARD',
|
22
|
+
})
|
23
|
+
expect(subject.call(input)).to eql(expected)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'on_error' do
|
27
|
+
let(:lens) do
|
28
|
+
Monolens.lens({
|
29
|
+
'array.map' => {
|
30
|
+
:lenses => {
|
31
|
+
'object.extend' => {
|
32
|
+
on_error: on_error,
|
33
|
+
defn: {
|
34
|
+
upcased: [
|
35
|
+
{ 'core.dig' => { defn: ['firstname'] } },
|
36
|
+
'str.upcase'
|
37
|
+
]
|
38
|
+
}
|
39
|
+
}.compact
|
40
|
+
}
|
41
|
+
}
|
42
|
+
})
|
43
|
+
end
|
44
|
+
|
45
|
+
subject do
|
46
|
+
lens.call(input)
|
47
|
+
rescue Monolens::LensError => ex
|
48
|
+
ex
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'default' do
|
52
|
+
let(:on_error) do
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
56
|
+
let(:input) do
|
57
|
+
[{}]
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'works as expected' do
|
61
|
+
expect(subject).to be_a(Monolens::LensError)
|
62
|
+
expect(subject.location).to eql([0, :upcased])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'with :null' do
|
67
|
+
let(:on_error) do
|
68
|
+
:null
|
69
|
+
end
|
70
|
+
|
71
|
+
let(:input) do
|
72
|
+
[{}]
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'works as expected' do
|
76
|
+
expect(subject).to eql([{'upcased' => nil}])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'with :skip' do
|
81
|
+
let(:on_error) do
|
82
|
+
:skip
|
83
|
+
end
|
84
|
+
|
85
|
+
let(:input) do
|
86
|
+
[{}]
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'works as expected' do
|
90
|
+
expect(subject).to eql([{}])
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|