monolens 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|