monolens 0.5.1 → 0.6.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 +51 -82
- data/lib/monolens/command.rb +111 -14
- data/lib/monolens/error.rb +2 -0
- data/lib/monolens/file.rb +6 -0
- data/lib/monolens/jsonpath.rb +76 -0
- data/lib/monolens/lens/options.rb +26 -12
- data/lib/monolens/lens/signature/missing.rb +11 -0
- data/lib/monolens/lens/signature.rb +60 -0
- data/lib/monolens/lens.rb +25 -4
- data/lib/monolens/macros.rb +28 -0
- data/lib/monolens/namespace.rb +11 -0
- data/lib/monolens/registry.rb +77 -0
- data/lib/monolens/{array → stdlib/array}/compact.rb +2 -0
- data/lib/monolens/{array → stdlib/array}/join.rb +4 -0
- data/lib/monolens/{array → stdlib/array}/map.rb +13 -19
- data/lib/monolens/{array.rb → stdlib/array.rb} +8 -6
- data/lib/monolens/stdlib/check/not_empty.rb +30 -0
- data/lib/monolens/stdlib/check.rb +13 -0
- data/lib/monolens/{coerce → stdlib/coerce}/date.rb +6 -1
- data/lib/monolens/{coerce → stdlib/coerce}/date_time.rb +7 -2
- data/lib/monolens/{coerce → stdlib/coerce}/integer.rb +4 -0
- data/lib/monolens/{coerce → stdlib/coerce}/string.rb +2 -0
- data/lib/monolens/{coerce.rb → stdlib/coerce.rb} +10 -8
- data/lib/monolens/{core → stdlib/core}/chain.rb +5 -3
- data/lib/monolens/{core → stdlib/core}/dig.rb +5 -0
- data/lib/monolens/stdlib/core/literal.rb +68 -0
- data/lib/monolens/{core → stdlib/core}/mapping.rb +15 -5
- data/lib/monolens/stdlib/core.rb +31 -0
- data/lib/monolens/stdlib/object/allbut.rb +22 -0
- data/lib/monolens/{object → stdlib/object}/extend.rb +10 -5
- data/lib/monolens/{object → stdlib/object}/keys.rb +4 -0
- data/lib/monolens/stdlib/object/merge.rb +56 -0
- data/lib/monolens/{object → stdlib/object}/rename.rb +5 -1
- data/lib/monolens/{object → stdlib/object}/select.rb +9 -0
- data/lib/monolens/{object → stdlib/object}/transform.rb +8 -3
- data/lib/monolens/{object → stdlib/object}/values.rb +9 -4
- data/lib/monolens/stdlib/object.rb +55 -0
- data/lib/monolens/{skip → stdlib/skip}/null.rb +2 -0
- data/lib/monolens/{skip.rb → stdlib/skip.rb} +4 -2
- data/lib/monolens/{str → stdlib/str}/downcase.rb +2 -0
- data/lib/monolens/{str → stdlib/str}/split.rb +5 -1
- data/lib/monolens/{str → stdlib/str}/strip.rb +2 -0
- data/lib/monolens/{str → stdlib/str}/upcase.rb +2 -0
- data/lib/monolens/{str.rb → stdlib/str.rb} +10 -8
- data/lib/monolens/stdlib.rb +7 -0
- data/lib/monolens/type/any.rb +39 -0
- data/lib/monolens/type/array.rb +27 -0
- data/lib/monolens/type/boolean.rb +17 -0
- data/lib/monolens/type/callback.rb +17 -0
- data/lib/monolens/type/coercible.rb +10 -0
- data/lib/monolens/type/diggable.rb +9 -0
- data/lib/monolens/type/emptyable.rb +9 -0
- data/lib/monolens/type/integer.rb +18 -0
- data/lib/monolens/type/lenses.rb +17 -0
- data/lib/monolens/type/map.rb +30 -0
- data/lib/monolens/type/object.rb +17 -0
- data/lib/monolens/type/responding.rb +25 -0
- data/lib/monolens/type/strategy.rb +56 -0
- data/lib/monolens/type/string.rb +18 -0
- data/lib/monolens/type/symbol.rb +20 -0
- data/lib/monolens/type.rb +33 -0
- data/lib/monolens/version.rb +2 -2
- data/lib/monolens.rb +22 -65
- data/spec/fixtures/macro.yml +13 -0
- data/spec/fixtures/recursive.yml +15 -0
- data/spec/monolens/command/literal.yml +2 -0
- data/spec/monolens/command/literal2.yml +2 -0
- data/spec/monolens/command/upcase.lens.yml +4 -0
- data/spec/monolens/lens/test_options.rb +2 -14
- data/spec/monolens/lens/test_signature.rb +38 -0
- data/spec/monolens/{array → stdlib/array}/test_compact.rb +8 -0
- data/spec/monolens/{array → stdlib/array}/test_join.rb +0 -0
- data/spec/monolens/{array → stdlib/array}/test_map.rb +15 -0
- data/spec/monolens/stdlib/check/test_not_empty.rb +50 -0
- data/spec/monolens/{coerce → stdlib/coerce}/test_date.rb +0 -0
- data/spec/monolens/{coerce → stdlib/coerce}/test_datetime.rb +1 -1
- data/spec/monolens/{coerce → stdlib/coerce}/test_integer.rb +0 -0
- data/spec/monolens/{coerce → stdlib/coerce}/test_string.rb +0 -0
- data/spec/monolens/{core → stdlib/core}/test_dig.rb +0 -0
- data/spec/monolens/stdlib/core/test_literal.rb +73 -0
- data/spec/monolens/{core → stdlib/core}/test_mapping.rb +37 -1
- data/spec/monolens/stdlib/object/test_allbut.rb +31 -0
- data/spec/monolens/{object → stdlib/object}/test_extend.rb +0 -0
- data/spec/monolens/{object → stdlib/object}/test_keys.rb +0 -0
- data/spec/monolens/stdlib/object/test_merge.rb +133 -0
- data/spec/monolens/{object → stdlib/object}/test_rename.rb +0 -0
- data/spec/monolens/{object → stdlib/object}/test_select.rb +0 -0
- data/spec/monolens/{object → stdlib/object}/test_transform.rb +0 -0
- data/spec/monolens/{object → stdlib/object}/test_values.rb +0 -0
- data/spec/monolens/{skip → stdlib/skip}/test_null.rb +0 -0
- data/spec/monolens/{str → stdlib/str}/test_downcase.rb +0 -0
- data/spec/monolens/{str → stdlib/str}/test_split.rb +0 -0
- data/spec/monolens/{str → stdlib/str}/test_strip.rb +0 -0
- data/spec/monolens/{str → stdlib/str}/test_upcase.rb +0 -0
- data/spec/monolens/test_command.rb +145 -0
- data/spec/monolens/test_error_traceability.rb +1 -1
- data/spec/monolens/test_jsonpath.rb +88 -0
- data/spec/monolens/test_lens.rb +1 -1
- data/spec/test_documentation.rb +52 -0
- data/spec/test_monolens.rb +20 -0
- data/tasks/test.rake +1 -1
- metadata +91 -50
- data/lib/monolens/core.rb +0 -23
- data/lib/monolens/object.rb +0 -41
data/lib/monolens.rb
CHANGED
@@ -1,81 +1,38 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
require 'date'
|
3
|
+
require 'ostruct'
|
4
|
+
|
2
5
|
module Monolens
|
3
|
-
|
6
|
+
require_relative 'monolens/version'
|
7
|
+
require_relative 'monolens/error'
|
8
|
+
require_relative 'monolens/error_handler'
|
9
|
+
require_relative 'monolens/type'
|
10
|
+
require_relative 'monolens/jsonpath'
|
11
|
+
require_relative 'monolens/lens'
|
12
|
+
require_relative 'monolens/namespace'
|
13
|
+
require_relative 'monolens/registry'
|
14
|
+
require_relative 'monolens/macros'
|
15
|
+
|
16
|
+
STDLIB = Registry.new
|
4
17
|
|
5
18
|
class << self
|
6
|
-
require_relative 'monolens/version'
|
7
|
-
require_relative 'monolens/error'
|
8
|
-
require_relative 'monolens/error_handler'
|
9
|
-
require_relative 'monolens/lens'
|
10
|
-
|
11
19
|
def define_namespace(name, impl_module)
|
12
|
-
|
20
|
+
STDLIB.define_namespace(name, impl_module)
|
13
21
|
end
|
14
22
|
|
15
|
-
require_relative 'monolens/file'
|
16
|
-
require_relative 'monolens/core'
|
17
|
-
require_relative 'monolens/skip'
|
18
|
-
require_relative 'monolens/str'
|
19
|
-
require_relative 'monolens/array'
|
20
|
-
require_relative 'monolens/object'
|
21
|
-
require_relative 'monolens/coerce'
|
22
|
-
|
23
23
|
def load_file(file)
|
24
|
-
|
24
|
+
STDLIB.load_file(file)
|
25
25
|
end
|
26
26
|
|
27
|
-
def load_yaml(
|
28
|
-
|
27
|
+
def load_yaml(yaml_str)
|
28
|
+
STDLIB.load_yaml(yaml_str)
|
29
29
|
end
|
30
30
|
|
31
31
|
def lens(arg)
|
32
|
-
|
33
|
-
when Lens then arg
|
34
|
-
when ::Array then chain(arg)
|
35
|
-
when ::String, ::Symbol then leaf_lens(arg)
|
36
|
-
when ::Hash then hash_lens(arg)
|
37
|
-
else
|
38
|
-
raise Error, "No such lens #{arg} (#{arg.class})"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def chain(lenses)
|
43
|
-
Core::Chain.new(lenses.map{|l| lens(l) })
|
44
|
-
end
|
45
|
-
private :chain
|
46
|
-
|
47
|
-
def file_lens(arg)
|
48
|
-
File.new(arg)
|
32
|
+
STDLIB.lens(arg)
|
49
33
|
end
|
50
|
-
|
51
|
-
def leaf_lens(arg)
|
52
|
-
namespace_name, lens_name = arg.to_s.split('.')
|
53
|
-
factor_lens(namespace_name, lens_name, {})
|
54
|
-
end
|
55
|
-
private :leaf_lens
|
56
|
-
|
57
|
-
def hash_lens(arg)
|
58
|
-
return file_lens(arg) if arg['version'] || arg[:version]
|
59
|
-
raise "Invalid lens #{arg}" unless arg.size == 1
|
60
|
-
|
61
|
-
name, options = arg.to_a.first
|
62
|
-
namespace_name, lens_name = if name =~ /^[a-z]+\.[a-z]+$/
|
63
|
-
name.to_s.split('.')
|
64
|
-
else
|
65
|
-
['core', name]
|
66
|
-
end
|
67
|
-
factor_lens(namespace_name, lens_name, options)
|
68
|
-
end
|
69
|
-
private :hash_lens
|
70
|
-
|
71
|
-
def factor_lens(namespace_name, lens_name, options)
|
72
|
-
namespace = NAMESPACES[namespace_name]
|
73
|
-
if namespace&.private_method_defined?(lens_name, false)
|
74
|
-
namespace.send(lens_name, options)
|
75
|
-
else
|
76
|
-
raise Error, "No such lens #{[namespace_name, lens_name].join('.')}"
|
77
|
-
end
|
78
|
-
end
|
79
|
-
private :factor_lens
|
80
34
|
end
|
35
|
+
|
36
|
+
require_relative 'monolens/file'
|
37
|
+
require_relative 'monolens/stdlib'
|
81
38
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
version: "1.0"
|
3
|
+
#
|
4
|
+
macros:
|
5
|
+
join_them:
|
6
|
+
- array.map:
|
7
|
+
- str.strip
|
8
|
+
- str.upcase
|
9
|
+
- array.join: { separator: <.separator }
|
10
|
+
## This is strictly forbidden
|
11
|
+
- join_them: { separator: ',' }
|
12
|
+
#
|
13
|
+
lenses:
|
14
|
+
- join_them:
|
15
|
+
separator: ', '
|
@@ -4,7 +4,7 @@ module Monolens
|
|
4
4
|
module Lens
|
5
5
|
describe Options do
|
6
6
|
subject do
|
7
|
-
Options.new(input)
|
7
|
+
Options.new(input, STDLIB, Signature::MISSING)
|
8
8
|
end
|
9
9
|
|
10
10
|
describe 'initialize' do
|
@@ -28,19 +28,7 @@ module Monolens
|
|
28
28
|
it 'converts it to lenses' do
|
29
29
|
expect(subject.to_h.keys).to eql([:lenses])
|
30
30
|
lenses = subject.to_h[:lenses]
|
31
|
-
expect(lenses).to
|
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)
|
31
|
+
expect(lenses).to eql(input)
|
44
32
|
end
|
45
33
|
end
|
46
34
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Monolens
|
4
|
+
module Lens
|
5
|
+
describe Signature do
|
6
|
+
let(:signature) do
|
7
|
+
Signature.new(Type::String, Type::String, {
|
8
|
+
separator: [Type::String, true],
|
9
|
+
help: [Type::String, false]
|
10
|
+
})
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'is ok with valid options' do
|
14
|
+
expect {
|
15
|
+
signature.dress_options({ separator: ',' }, nil)
|
16
|
+
}.not_to raise_error
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'detects a missing option' do
|
20
|
+
expect {
|
21
|
+
signature.dress_options({}, nil)
|
22
|
+
}.to raise_error(Error, /Missing option `separator`/)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'detects an extra option' do
|
26
|
+
expect {
|
27
|
+
signature.dress_options({ foo: 'bar' }, nil)
|
28
|
+
}.to raise_error(Error, /Invalid option `foo`/)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'detects an option of the wrong type' do
|
32
|
+
expect {
|
33
|
+
signature.dress_options({ separator: 12 }, nil)
|
34
|
+
}.to raise_error(Error, /Invalid option `separator`: Invalid string 12/)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -12,4 +12,12 @@ describe Monolens, 'array.compact' do
|
|
12
12
|
it 'supports empty arrays' do
|
13
13
|
expect(subject.call([])).to eql([])
|
14
14
|
end
|
15
|
+
|
16
|
+
describe 'signature checking' do
|
17
|
+
it 'detects unexisting options' do
|
18
|
+
expect {
|
19
|
+
Monolens.lens('array.compact' => { foo: 'bar' })
|
20
|
+
}.to raise_error(Monolens::Error, /Invalid option `foo`/)
|
21
|
+
end
|
22
|
+
end
|
15
23
|
end
|
File without changes
|
@@ -58,6 +58,21 @@ describe Monolens, 'array.map' do
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
+
context 'keeping on error' do
|
62
|
+
subject do
|
63
|
+
Monolens.lens('array.map' => {
|
64
|
+
on_error: 'keep',
|
65
|
+
lenses: [ 'str.upcase' ]
|
66
|
+
})
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'skips errors' do
|
70
|
+
input = [12, 'world']
|
71
|
+
expected = [12, 'WORLD']
|
72
|
+
expect(subject.call(input)).to eql(expected)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
61
76
|
context 'on error with :handler' do
|
62
77
|
subject do
|
63
78
|
Monolens.lens('array.map' => {
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, 'check.notEmpty' do
|
4
|
+
subject do
|
5
|
+
Monolens.lens('check.notEmpty' => options)
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'with default options' do
|
9
|
+
let(:options) do
|
10
|
+
{}
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'works on non empty strings' do
|
14
|
+
input = '12'
|
15
|
+
expect(subject.call(input)).to be(input)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'works on non empty arrays' do
|
19
|
+
input = ['12']
|
20
|
+
expect(subject.call(input)).to be(input)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'raises on empty strings' do
|
24
|
+
input = ''
|
25
|
+
expect {
|
26
|
+
subject.call(input)
|
27
|
+
}.to raise_error(Monolens::LensError, 'Input may not be empty')
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'raises on empty arrays' do
|
31
|
+
input = []
|
32
|
+
expect {
|
33
|
+
subject.call(input)
|
34
|
+
}.to raise_error(Monolens::LensError, 'Input may not be empty')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with a specific error message' do
|
39
|
+
let(:options) do
|
40
|
+
{ message: 'Hello failure!' }
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'raises on empty strings' do
|
44
|
+
input = ''
|
45
|
+
expect {
|
46
|
+
subject.call(input)
|
47
|
+
}.to raise_error(Monolens::LensError, 'Hello failure!')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, "core.literal" do
|
4
|
+
let(:lens) do
|
5
|
+
Monolens.lens('core.literal' => { defn: 'hello' })
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'works' do
|
9
|
+
input = {}
|
10
|
+
expected = 'hello'
|
11
|
+
expect(lens.call(input)).to eql(expected)
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'with a simple json path expressions' do
|
15
|
+
let(:lens) do
|
16
|
+
Monolens.lens('core.literal' => { defn: '$.foo' })
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'works' do
|
20
|
+
input = { 'foo' => 'bar' }
|
21
|
+
expected = 'bar'
|
22
|
+
expect(lens.call(input)).to eql(expected)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'works with symbols too' do
|
26
|
+
input = { foo: 'bar' }
|
27
|
+
expected = 'bar'
|
28
|
+
expect(lens.call(input)).to eql(expected)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with an object literal with json path expressions' do
|
33
|
+
let(:lens) do
|
34
|
+
Monolens.lens('core.literal' => {
|
35
|
+
defn: {
|
36
|
+
hobbies: [{
|
37
|
+
name: '$.foo'
|
38
|
+
}]
|
39
|
+
}
|
40
|
+
})
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'works' do
|
44
|
+
input = { 'foo' => 'bar' }
|
45
|
+
expected = { hobbies: [{ name: 'bar' }] }
|
46
|
+
expect(lens.call(input)).to eql(expected)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'works with symbols too' do
|
50
|
+
input = { foo: 'bar' }
|
51
|
+
expected = { hobbies: [{ name: 'bar' }] }
|
52
|
+
expect(lens.call(input)).to eql(expected)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'changing the root symbol' do
|
57
|
+
let(:lens) do
|
58
|
+
Monolens.lens('core.literal' => {
|
59
|
+
defn: {
|
60
|
+
one: '<.foo',
|
61
|
+
interpolate: 'Hello <(.foo)'
|
62
|
+
},
|
63
|
+
jsonpath: { root_symbol: '<' }
|
64
|
+
})
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'keeps working' do
|
68
|
+
input = { foo: 'bar' }
|
69
|
+
expected = { one: 'bar', interpolate: 'Hello bar' }
|
70
|
+
expect(lens.call(input)).to eql(expected)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Monolens, 'core.mapping' do
|
4
4
|
let(:mapping) do
|
5
|
-
{ '
|
5
|
+
{ 'defn' => { 'todo' => 'open' } }
|
6
6
|
end
|
7
7
|
|
8
8
|
context 'with default options' do
|
@@ -49,6 +49,20 @@ describe Monolens, 'core.mapping' do
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
+
context 'on_missing: keep' do
|
53
|
+
subject do
|
54
|
+
Monolens.lens('core.mapping' => mapping.merge('on_missing' => 'keep'))
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'replaces the value by its mapped' do
|
58
|
+
expect(subject.call('todo')).to eql('open')
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns nil if missing' do
|
62
|
+
expect(subject.call('nosuchone')).to eql('nosuchone')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
52
66
|
context 'on_missing: fallback' do
|
53
67
|
subject do
|
54
68
|
Monolens.lens('core.mapping' => mapping.merge(
|
@@ -90,4 +104,26 @@ describe Monolens, 'core.mapping' do
|
|
90
104
|
expect(subject.location).to eql([1])
|
91
105
|
end
|
92
106
|
end
|
107
|
+
|
108
|
+
context 'backward compatibility' do
|
109
|
+
let(:mapping) do
|
110
|
+
{ 'values' => { 'todo' => 'open' } }
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'with using values instead of defn' do
|
114
|
+
subject do
|
115
|
+
Monolens.lens('core.mapping' => mapping)
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'replaces the value by its mapped' do
|
119
|
+
expect(subject.call('todo')).to eql('open')
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'raises if not found' do
|
123
|
+
expect {
|
124
|
+
subject.call('nosuchone')
|
125
|
+
}.to raise_error(Monolens::LensError)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
93
129
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Monolens, 'object.allbut' do
|
4
|
+
subject do
|
5
|
+
Monolens.lens('object.allbut' => { defn: [ :lastname, :city ] })
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'works as expected' do
|
9
|
+
input = {
|
10
|
+
'firstname' => 'Bernard',
|
11
|
+
'lastname' => 'Lambeau',
|
12
|
+
'city' => 'Brussels'
|
13
|
+
}
|
14
|
+
expected = {
|
15
|
+
'firstname' => 'Bernard',
|
16
|
+
}
|
17
|
+
expect(subject.call(input)).to eql(expected)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'works as expected with Symbol keys' do
|
21
|
+
input = {
|
22
|
+
firstname: 'Bernard',
|
23
|
+
lastname: 'Lambeau',
|
24
|
+
city: 'Brussels'
|
25
|
+
}
|
26
|
+
expected = {
|
27
|
+
firstname: 'Bernard',
|
28
|
+
}
|
29
|
+
expect(subject.call(input)).to eql(expected)
|
30
|
+
end
|
31
|
+
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,133 @@
|
|
1
|
+
describe Monolens, 'object.merge' do
|
2
|
+
subject do
|
3
|
+
Monolens.lens('object.merge' => {
|
4
|
+
priority: priority,
|
5
|
+
deep: deep,
|
6
|
+
defn: {
|
7
|
+
name: 'Monolens',
|
8
|
+
version: "1.0",
|
9
|
+
links: {
|
10
|
+
github: "https://github.com/enspirit/monolens"
|
11
|
+
},
|
12
|
+
}
|
13
|
+
}.compact)
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:priority) do
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:deep) do
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'with default options' do
|
25
|
+
it 'works as expected on a flat structure' do
|
26
|
+
input = {
|
27
|
+
version: "1.2",
|
28
|
+
extra: "foo"
|
29
|
+
}
|
30
|
+
expected = {
|
31
|
+
name: 'Monolens',
|
32
|
+
version: "1.0",
|
33
|
+
links: {
|
34
|
+
github: "https://github.com/enspirit/monolens"
|
35
|
+
},
|
36
|
+
extra: "foo"
|
37
|
+
}
|
38
|
+
expect(subject.call(input)).to eql(expected)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'does not apply a deep merge' do
|
42
|
+
input = {
|
43
|
+
links: {
|
44
|
+
owner: "https://enspirit.be/"
|
45
|
+
},
|
46
|
+
}
|
47
|
+
expected = {
|
48
|
+
name: 'Monolens',
|
49
|
+
version: "1.0",
|
50
|
+
links: {
|
51
|
+
github: "https://github.com/enspirit/monolens"
|
52
|
+
}
|
53
|
+
}
|
54
|
+
expect(subject.call(input)).to eql(expected)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'priority: input' do
|
59
|
+
let(:priority) do
|
60
|
+
'input'
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'reverse the logic on shared keys' do
|
64
|
+
input = {
|
65
|
+
version: "1.2",
|
66
|
+
extra: "foo",
|
67
|
+
}
|
68
|
+
expected = {
|
69
|
+
name: 'Monolens',
|
70
|
+
version: "1.2",
|
71
|
+
links: {
|
72
|
+
github: "https://github.com/enspirit/monolens"
|
73
|
+
},
|
74
|
+
extra: "foo"
|
75
|
+
}
|
76
|
+
expect(subject.call(input)).to eql(expected)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'deep: true' do
|
81
|
+
let(:deep) do
|
82
|
+
true
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'applies a deep merge' do
|
86
|
+
input = {
|
87
|
+
version: "1.2",
|
88
|
+
links: {
|
89
|
+
owner: "https://enspirit.be/",
|
90
|
+
github: "https://github.com/enspirit/monolens/"
|
91
|
+
},
|
92
|
+
}
|
93
|
+
expected = {
|
94
|
+
name: 'Monolens',
|
95
|
+
version: "1.0",
|
96
|
+
links: {
|
97
|
+
owner: "https://enspirit.be/",
|
98
|
+
github: "https://github.com/enspirit/monolens"
|
99
|
+
}
|
100
|
+
}
|
101
|
+
expect(subject.call(input)).to eql(expected)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe 'deep: true, priority: input' do
|
106
|
+
let(:deep) do
|
107
|
+
true
|
108
|
+
end
|
109
|
+
|
110
|
+
let(:priority) do
|
111
|
+
'input'
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'applies a deep merge' do
|
115
|
+
input = {
|
116
|
+
version: "1.2",
|
117
|
+
links: {
|
118
|
+
owner: "https://enspirit.be/",
|
119
|
+
github: "https://github.com/enspirit/monolens/"
|
120
|
+
},
|
121
|
+
}
|
122
|
+
expected = {
|
123
|
+
name: 'Monolens',
|
124
|
+
version: "1.2",
|
125
|
+
links: {
|
126
|
+
owner: "https://enspirit.be/",
|
127
|
+
github: "https://github.com/enspirit/monolens/"
|
128
|
+
}
|
129
|
+
}
|
130
|
+
expect(subject.call(input)).to eql(expected)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|