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
@@ -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
|
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Monolens, 'core.mapping' do
|
4
4
|
let(:mapping) do
|
5
|
-
{ 'values' => { 'todo' => 'open' }}
|
5
|
+
{ 'values' => { 'todo' => 'open' } }
|
6
6
|
end
|
7
7
|
|
8
8
|
context 'with default options' do
|
@@ -14,14 +14,16 @@ describe Monolens, 'core.mapping' do
|
|
14
14
|
expect(subject.call('todo')).to eql('open')
|
15
15
|
end
|
16
16
|
|
17
|
-
it '
|
18
|
-
expect
|
17
|
+
it 'raises if not found' do
|
18
|
+
expect {
|
19
|
+
subject.call('nosuchone')
|
20
|
+
}.to raise_error(Monolens::LensError)
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
22
|
-
context '
|
24
|
+
context 'on_missing: default' do
|
23
25
|
subject do
|
24
|
-
Monolens.lens('core.mapping' => mapping.merge('default' => 'foo'))
|
26
|
+
Monolens.lens('core.mapping' => mapping.merge('on_missing' => 'default', 'default' => 'foo'))
|
25
27
|
end
|
26
28
|
|
27
29
|
it 'replaces the value by its mapped' do
|
@@ -33,19 +35,59 @@ describe Monolens, 'core.mapping' do
|
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
|
-
context '
|
38
|
+
context 'on_missing: null' do
|
37
39
|
subject do
|
38
|
-
Monolens.lens('core.mapping' => mapping.merge('
|
40
|
+
Monolens.lens('core.mapping' => mapping.merge('on_missing' => 'null'))
|
39
41
|
end
|
40
42
|
|
41
43
|
it 'replaces the value by its mapped' do
|
42
44
|
expect(subject.call('todo')).to eql('open')
|
43
45
|
end
|
44
46
|
|
45
|
-
it '
|
46
|
-
expect
|
47
|
-
|
48
|
-
|
47
|
+
it 'returns nil if missing' do
|
48
|
+
expect(subject.call('nosuchone')).to eql(nil)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'on_missing: fallback' do
|
53
|
+
subject do
|
54
|
+
Monolens.lens('core.mapping' => mapping.merge(
|
55
|
+
'on_missing' => 'fallback',
|
56
|
+
'fallback' => ->(lens, arg, world) { 'foo' }
|
57
|
+
))
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'replaces the value by its mapped' do
|
61
|
+
expect(subject.call('todo')).to eql('open')
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'returns nil if missing' do
|
65
|
+
expect(subject.call('nosuchone')).to eql('foo')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'error handling' do
|
70
|
+
let(:lens) do
|
71
|
+
Monolens.lens({
|
72
|
+
'array.map' => {
|
73
|
+
:lenses => {
|
74
|
+
'core.mapping' => mapping.merge('on_missing' => 'fail')
|
75
|
+
}
|
76
|
+
}
|
77
|
+
})
|
78
|
+
end
|
79
|
+
|
80
|
+
subject do
|
81
|
+
begin
|
82
|
+
lens.call(['todo', 'foo'])
|
83
|
+
nil
|
84
|
+
rescue Monolens::LensError => ex
|
85
|
+
ex
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'sets the location correctly' do
|
90
|
+
expect(subject.location).to eql([1])
|
49
91
|
end
|
50
92
|
end
|
51
93
|
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
|
@@ -1,31 +1,63 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Monolens, 'object.keys' do
|
4
|
-
|
5
|
-
|
4
|
+
context 'with string keys' do
|
5
|
+
subject do
|
6
|
+
Monolens.lens('object.keys' => ['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
|
6
20
|
end
|
7
21
|
|
8
|
-
|
9
|
-
|
10
|
-
'
|
11
|
-
|
12
|
-
|
13
|
-
expected
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
22
|
+
context 'with symbol keys' do
|
23
|
+
subject do
|
24
|
+
Monolens.lens('object.keys' => ['coerce.string', 'str.upcase'])
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'works as expected with Symbol keys' do
|
28
|
+
input = {
|
29
|
+
firstname: 'Bernard',
|
30
|
+
lastname: 'Lambeau'
|
31
|
+
}
|
32
|
+
expected = {
|
33
|
+
FIRSTNAME: 'Bernard',
|
34
|
+
LASTNAME: 'Lambeau'
|
35
|
+
}
|
36
|
+
expect(subject.call(input)).to eql(expected)
|
37
|
+
end
|
18
38
|
end
|
19
39
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
40
|
+
describe 'error handling' do
|
41
|
+
let(:lens) do
|
42
|
+
Monolens.lens('object.keys' => ['str.upcase'])
|
43
|
+
end
|
44
|
+
|
45
|
+
subject do
|
46
|
+
lens.call(input)
|
47
|
+
nil
|
48
|
+
rescue Monolens::LensError => ex
|
49
|
+
ex
|
50
|
+
end
|
51
|
+
|
52
|
+
let(:input) do
|
53
|
+
{
|
54
|
+
'firstname' => 'Bernard',
|
55
|
+
nil => 'Lambeau'
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'correctly updates the location' do
|
60
|
+
expect(subject.location).to eql([nil])
|
61
|
+
end
|
30
62
|
end
|
31
63
|
end
|