two-way-mapper 0.0.1 → 0.3.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/.travis.yml +4 -4
- data/README.md +28 -5
- data/lib/two-way-mapper.rb +2 -0
- data/lib/two_way_mapper.rb +2 -0
- data/lib/two_way_mapper/map.rb +4 -0
- data/lib/two_way_mapper/mapping.rb +58 -32
- data/lib/two_way_mapper/node.rb +3 -1
- data/lib/two_way_mapper/node/active_record.rb +3 -1
- data/lib/two_way_mapper/node/{abstract.rb → base.rb} +18 -15
- data/lib/two_way_mapper/node/hash.rb +6 -2
- data/lib/two_way_mapper/node/object.rb +9 -5
- data/lib/two_way_mapper/railtie.rb +4 -2
- data/lib/two_way_mapper/rule.rb +55 -19
- data/lib/two_way_mapper/tools.rb +4 -2
- data/lib/two_way_mapper/version.rb +3 -1
- data/spec/map_spec.rb +3 -1
- data/spec/mapping_spec.rb +118 -30
- data/spec/node/active_record_spec.rb +6 -2
- data/spec/node/{abstract_spec.rb → base_spec.rb} +10 -5
- data/spec/node/hash_spec.rb +7 -3
- data/spec/node/object_spec.rb +4 -2
- data/spec/rule_spec.rb +263 -85
- data/spec/tools_spec.rb +8 -8
- data/two-way-mapper.gemspec +16 -15
- metadata +26 -27
data/lib/two_way_mapper/tools.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module TwoWayMapper
|
2
4
|
module Tools
|
3
5
|
class << self
|
4
6
|
def first_item_from_hash!(hash)
|
5
7
|
raise ArgumentError unless hash.is_a?(Hash)
|
6
|
-
raise ArgumentError unless first = hash.first
|
8
|
+
raise ArgumentError unless (first = hash.first)
|
7
9
|
|
8
|
-
hash.delete
|
10
|
+
hash.delete(first[0])
|
9
11
|
first
|
10
12
|
end
|
11
13
|
end
|
data/spec/map_spec.rb
CHANGED
data/spec/mapping_spec.rb
CHANGED
@@ -1,65 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
describe TwoWayMapper::Mapping do
|
2
|
-
|
3
|
-
describe "##{method}" do
|
4
|
-
let(:mapping) { TwoWayMapper::Mapping.new }
|
4
|
+
let(:mapping) { described_class.new }
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
described_class::DIRECTIONS.each do |direction|
|
7
|
+
describe "##{direction}" do
|
8
|
+
it "should set #{direction} with options" do
|
9
|
+
mapping.send direction, :object, opt1: ''
|
8
10
|
|
9
|
-
expect(mapping.send("#{
|
10
|
-
expect(mapping.send("#{
|
11
|
+
expect(mapping.send("#{direction}_class")).to eql TwoWayMapper::Node::Object
|
12
|
+
expect(mapping.send("#{direction}_options")).to include opt1: ''
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'selectors' do
|
18
|
+
before do
|
19
|
+
mapping.left :object
|
20
|
+
mapping.right :object
|
21
|
+
end
|
22
|
+
|
23
|
+
before do
|
24
|
+
mapping.rule 'firstname', 'FirstName'
|
25
|
+
mapping.rule 'fullname', 'FullName', from_right_to_left_only: true
|
26
|
+
mapping.rule 'lastname', 'LastName'
|
27
|
+
mapping.rule 'fullname1', 'FullName1', from_left_to_right_only: true
|
28
|
+
mapping.rule ['field1', 'field2'], 'Field1'
|
29
|
+
mapping.rule 'field3', ['Field2', 'Field3']
|
30
|
+
mapping.rule ['field4', 'field5'], ['Field4', 'Field5']
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#left_selectors' do
|
34
|
+
it 'should get left selectors' do
|
35
|
+
expect(mapping.left_selectors).to eql(
|
36
|
+
%w(firstname fullname lastname fullname1 field1 field2 field3 field4 field5)
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should include only mappable selectors if such option is passed' do
|
41
|
+
expect(mapping.left_selectors(mappable: true)).to eql(
|
42
|
+
%w(firstname fullname lastname field1 field2 field3 field4 field5)
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#right_selectors' do
|
48
|
+
it 'should get right selectors' do
|
49
|
+
expect(mapping.right_selectors).to eql(
|
50
|
+
%w(FirstName FullName LastName FullName1 Field1 Field2 Field3 Field4 Field5)
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should include only mappable selectors if such option is passed' do
|
55
|
+
expect(mapping.right_selectors(mappable: true)).to eql(
|
56
|
+
%w(FirstName LastName FullName1 Field1 Field2 Field3 Field4 Field5)
|
57
|
+
)
|
11
58
|
end
|
12
59
|
end
|
13
60
|
end
|
14
61
|
|
15
62
|
describe '#rule' do
|
16
|
-
let(:mapping) { TwoWayMapper::Mapping.new }
|
17
63
|
before :each do
|
18
64
|
mapping.left :object
|
19
65
|
mapping.right :hash
|
20
66
|
end
|
21
67
|
|
22
68
|
context 'left and right validation' do
|
23
|
-
let(:mapping_without_both) {
|
24
|
-
let(:mapping_without_left) {
|
25
|
-
let(:mapping_without_right) {
|
69
|
+
let(:mapping_without_both) { described_class.new }
|
70
|
+
let(:mapping_without_left) { described_class.new }
|
71
|
+
let(:mapping_without_right) { described_class.new }
|
72
|
+
|
26
73
|
before :each do
|
27
74
|
mapping_without_left.right :hash
|
28
75
|
mapping_without_right.left :hash
|
29
76
|
end
|
30
77
|
|
31
78
|
it 'should raise error when no left or right nodes' do
|
32
|
-
expect{mapping_without_left.rule 'key', 'key'}.to raise_error
|
33
|
-
expect{mapping_without_right.rule 'key', 'key'}.to raise_error
|
34
|
-
expect{mapping_without_both.rule 'key', 'key'}.to raise_error
|
79
|
+
expect { mapping_without_left.rule 'key', 'key' }.to raise_error StandardError
|
80
|
+
expect { mapping_without_right.rule 'key', 'key' }.to raise_error StandardError
|
81
|
+
expect { mapping_without_both.rule 'key', 'key' }.to raise_error StandardError
|
35
82
|
end
|
36
83
|
end
|
37
84
|
|
38
85
|
it 'should add item to rules hash' do
|
39
|
-
expect{mapping.rule 'key1', 'Key1'}.to change{mapping.
|
86
|
+
expect { mapping.rule 'key1', 'Key1' }.to change { mapping.rules_list.count }.from(0).to(1)
|
40
87
|
|
41
|
-
rule = mapping.
|
88
|
+
rule = mapping.rules_list.first
|
42
89
|
expect(rule).to be_instance_of TwoWayMapper::Rule
|
43
|
-
expect(rule.
|
44
|
-
expect(rule.
|
90
|
+
expect(rule.left_nodes.map(&:selector)).to eql ['key1']
|
91
|
+
expect(rule.right_nodes.map(&:selector)).to eql ['Key1']
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should support multiple selectors' do
|
95
|
+
mapping.rule ['key1', 'key2'], ['Key1', 'Key2']
|
96
|
+
|
97
|
+
rule = mapping.rules_list.first
|
98
|
+
|
99
|
+
expect(rule.left_nodes.size).to eql 2
|
100
|
+
expect(rule.left_nodes[0].selector).to eql 'key1'
|
101
|
+
expect(rule.left_nodes[1].selector).to eql 'key2'
|
102
|
+
expect(rule.right_nodes.size).to eql 2
|
103
|
+
expect(rule.right_nodes[0].selector).to eql 'Key1'
|
104
|
+
expect(rule.right_nodes[1].selector).to eql 'Key2'
|
45
105
|
end
|
46
106
|
|
47
107
|
it 'should allow to pass hash' do
|
48
|
-
expect{mapping.rule 'key1' => { opt1: 'val' }}.to raise_error
|
108
|
+
expect { mapping.rule 'key1' => { opt1: 'val' } }.to raise_error StandardError
|
49
109
|
|
50
110
|
mapping.rule 'key1' => { opt1: 'val' }, 'Key2' => {}
|
51
|
-
rule = mapping.
|
111
|
+
rule = mapping.rules_list.first
|
52
112
|
|
53
|
-
expect(rule.
|
54
|
-
expect(rule.
|
113
|
+
expect(rule.left_nodes.map(&:selector)).to eql ['key1']
|
114
|
+
expect(rule.right_nodes.map(&:selector)).to eql ['Key2']
|
55
115
|
end
|
56
116
|
|
57
117
|
it 'should allow to pass left abd right options ' do
|
58
118
|
mapping.rule 'key1', 'Key2', left: { opt1: 'val' }, right: { opt2: 'val' }
|
59
|
-
rule = mapping.
|
119
|
+
rule = mapping.rules_list.first
|
60
120
|
|
61
|
-
expect(rule.
|
62
|
-
expect(rule.
|
121
|
+
expect(rule.left_nodes.first.options).to include opt1: 'val'
|
122
|
+
expect(rule.right_nodes.first.options).to include opt2: 'val'
|
63
123
|
end
|
64
124
|
|
65
125
|
it 'should work with options copy' do
|
@@ -71,18 +131,20 @@ describe TwoWayMapper::Mapping do
|
|
71
131
|
end
|
72
132
|
|
73
133
|
context 'convertion methods' do
|
74
|
-
let(:mapping) { TwoWayMapper::Mapping.new }
|
75
134
|
let(:rule1) { double from_left_to_right: nil, from_right_to_left: nil }
|
76
135
|
let(:rule2) { double from_left_to_right: nil, from_right_to_left: nil }
|
77
|
-
let(:left_obj) { double
|
78
|
-
let(:right_obj) { double
|
136
|
+
let(:left_obj) { double }
|
137
|
+
let(:right_obj) { double }
|
138
|
+
|
79
139
|
before :each do
|
80
140
|
mapping.left :object
|
81
141
|
mapping.right :hash
|
82
|
-
allow(mapping).to receive(:
|
142
|
+
allow(mapping).to receive(:rules_list).and_return [rule1, rule2]
|
83
143
|
end
|
84
144
|
|
85
|
-
[
|
145
|
+
[described_class::DIRECTIONS, described_class::DIRECTIONS.reverse].each do |from, to|
|
146
|
+
method = "from_#{from}_to_#{to}"
|
147
|
+
|
86
148
|
describe "##{method}" do
|
87
149
|
it 'should proxy to all rules' do
|
88
150
|
expect(rule1).to receive(method).with left_obj, right_obj
|
@@ -93,4 +155,30 @@ describe TwoWayMapper::Mapping do
|
|
93
155
|
end
|
94
156
|
end
|
95
157
|
end
|
158
|
+
|
159
|
+
describe '#rules' do
|
160
|
+
let(:hash) do
|
161
|
+
{
|
162
|
+
key1: :Key1,
|
163
|
+
key2: :Key2
|
164
|
+
}
|
165
|
+
end
|
166
|
+
|
167
|
+
before :each do
|
168
|
+
mapping.left :object
|
169
|
+
mapping.right :hash
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'should allow to define multiple rules' do
|
173
|
+
expect { mapping.rules(hash) }.to change { mapping.rules_list.count }.from(0).to(2)
|
174
|
+
|
175
|
+
hash.each_with_index do |(left, right), index|
|
176
|
+
rule = mapping.rules_list[index]
|
177
|
+
|
178
|
+
expect(rule).to be_instance_of TwoWayMapper::Rule
|
179
|
+
expect(rule.left_nodes.map(&:selector)).to eql [left]
|
180
|
+
expect(rule.right_nodes.map(&:selector)).to eql [right]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
96
184
|
end
|
@@ -1,10 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
describe TwoWayMapper::Node::ActiveRecord do
|
2
|
-
let(:node) {
|
4
|
+
let(:node) { described_class.new 'user.email' }
|
3
5
|
|
4
6
|
describe '#write' do
|
5
7
|
it 'should try to build before write' do
|
6
8
|
user = double(email: '')
|
7
|
-
obj = double
|
9
|
+
obj = double
|
10
|
+
|
8
11
|
allow(obj).to receive :build_user do
|
9
12
|
allow(obj).to receive(:user).and_return user
|
10
13
|
end
|
@@ -18,6 +21,7 @@ describe TwoWayMapper::Node::ActiveRecord do
|
|
18
21
|
it 'should try to build even if respond_to but obj itself is nil' do
|
19
22
|
user = double(email: '')
|
20
23
|
obj = double(user: nil)
|
24
|
+
|
21
25
|
allow(obj).to receive :build_user do
|
22
26
|
allow(obj).to receive(:user).and_return user
|
23
27
|
end
|
@@ -1,19 +1,24 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe TwoWayMapper::Node::Base do
|
2
4
|
describe '#keys' do
|
3
|
-
subject {
|
5
|
+
subject { described_class.new('key1.key11.key111') }
|
4
6
|
|
5
|
-
its(:keys) { should eql [
|
7
|
+
its(:keys) { should eql %i[key1 key11 key111] }
|
6
8
|
end
|
7
9
|
|
8
10
|
describe 'writable?' do
|
9
11
|
it 'should be truthy if write_if options not set' do
|
10
|
-
node =
|
12
|
+
node = described_class.new('key1.key11.key111')
|
11
13
|
|
12
14
|
expect(node).to be_writable 'current', 'new'
|
13
15
|
end
|
14
16
|
|
15
17
|
it 'should be truthy if write_if option set' do
|
16
|
-
node =
|
18
|
+
node = described_class.new(
|
19
|
+
'key1.key11.key111',
|
20
|
+
write_if: ->(c, n) { c == 'current' || n == 'new' }
|
21
|
+
)
|
17
22
|
|
18
23
|
expect(node).to be_writable 'current', 'new1'
|
19
24
|
expect(node).to be_writable 'current1', 'new'
|
data/spec/node/hash_spec.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
describe TwoWayMapper::Node::Hash do
|
2
4
|
context 'normal keys' do
|
3
|
-
let(:node) {
|
5
|
+
let(:node) { described_class.new('key1.key11.key111') }
|
4
6
|
|
5
7
|
describe '#read' do
|
6
8
|
it 'should return nil when path is not avaiable' do
|
@@ -25,7 +27,9 @@ describe TwoWayMapper::Node::Hash do
|
|
25
27
|
end
|
26
28
|
|
27
29
|
context 'string keys' do
|
28
|
-
let(:node)
|
30
|
+
let(:node) do
|
31
|
+
described_class.new('key1.key11.key111', stringify_keys: true)
|
32
|
+
end
|
29
33
|
|
30
34
|
describe '#read' do
|
31
35
|
it 'should return nil when path is not avaiable' do
|
@@ -50,7 +54,7 @@ describe TwoWayMapper::Node::Hash do
|
|
50
54
|
end
|
51
55
|
|
52
56
|
context 'write_if option' do
|
53
|
-
let(:node) {
|
57
|
+
let(:node) { described_class.new 'key1.key11', write_if: ->(c, n) { c.empty? || n == 'value1' } }
|
54
58
|
let(:writable_obj1) { { key1: { key11: '' } } }
|
55
59
|
let(:writable_obj2) { { key1: { key11: 'smth' } } }
|
56
60
|
let(:not_writable_obj) { { key1: { key11: 'smth' } } }
|
data/spec/node/object_spec.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
describe TwoWayMapper::Node::Object do
|
2
|
-
let(:node) {
|
4
|
+
let(:node) { described_class.new 'key1.key11.key111' }
|
3
5
|
|
4
6
|
describe '#read' do
|
5
7
|
it 'should return nil when path is not avaiable' do
|
@@ -25,7 +27,7 @@ describe TwoWayMapper::Node::Object do
|
|
25
27
|
end
|
26
28
|
|
27
29
|
context 'write_if option' do
|
28
|
-
let(:node) {
|
30
|
+
let(:node) { described_class.new 'key', write_if: ->(c, n) { c.empty? || n == 'value1'} }
|
29
31
|
let(:writable_obj1) { OpenStruct.new key: '' }
|
30
32
|
let(:writable_obj2) { OpenStruct.new key: 'smth' }
|
31
33
|
let(:not_writable_obj) { OpenStruct.new key: 'smth' }
|
data/spec/rule_spec.rb
CHANGED
@@ -1,127 +1,305 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
describe TwoWayMapper::Rule do
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
let(:left_node) { TwoWayMapper::Node::Object.new('key1') }
|
5
|
+
let(:left_nodes) { [left_node] }
|
6
|
+
let(:right_node) { TwoWayMapper::Node::Hash.new('Kk.Key1') }
|
7
|
+
let(:right_nodes) { [right_node] }
|
8
|
+
let(:left_object) { OpenStruct.new }
|
9
|
+
let(:map) { { 'value' => 'VALUE' } }
|
10
|
+
let(:options) { {} }
|
11
|
+
let(:rule) { described_class.new(left_nodes, right_nodes, options) }
|
7
12
|
|
8
|
-
|
9
|
-
|
13
|
+
context 'without options' do
|
14
|
+
let(:options) { {} }
|
10
15
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
+
describe '#from_left_to_right' do
|
17
|
+
it 'should read from the left node and write to the right node' do
|
18
|
+
left_object.key1 = 'value1'
|
19
|
+
right_object = {}
|
20
|
+
rule.from_left_to_right(left_object, right_object)
|
16
21
|
|
17
|
-
|
18
|
-
end
|
22
|
+
expect(right_object).to eql Kk: { Key1: 'value1' }
|
19
23
|
end
|
24
|
+
end
|
20
25
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
+
describe '#from_right_to_left' do
|
27
|
+
it 'should read from the right node and write to the left node' do
|
28
|
+
left_object.key1 = nil
|
29
|
+
right_object = { Kk: { Key1: 'value1' } }
|
30
|
+
rule.from_right_to_left(left_object, right_object)
|
26
31
|
|
27
|
-
|
28
|
-
end
|
32
|
+
expect(left_object.key1).to eql 'value1'
|
29
33
|
end
|
30
34
|
end
|
35
|
+
end
|
31
36
|
|
32
|
-
|
33
|
-
|
37
|
+
context 'with from_left_to_right_only/from_right_to_left_only options' do
|
38
|
+
describe '#from_left_to_right' do
|
39
|
+
let(:options) { { from_right_to_left_only: true } }
|
34
40
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
rule.from_left_to_right left_object, right_object
|
41
|
+
it 'should do nothing if from_right_to_left_only is set to true' do
|
42
|
+
left_object.key1 = 'value1'
|
43
|
+
right_object = {}
|
44
|
+
rule.from_left_to_right(left_object, right_object)
|
40
45
|
|
41
|
-
|
42
|
-
end
|
46
|
+
expect(right_object).to eql({})
|
43
47
|
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#from_right_to_left' do
|
51
|
+
let(:options) { { from_left_to_right_only: true } }
|
44
52
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
rule.from_right_to_left left_object, right_object
|
53
|
+
it 'should do nothing if from_left_to_right_only is set to true' do
|
54
|
+
left_object.key1 = nil
|
55
|
+
right_object = { Kk: { Key1: 'value1' } }
|
56
|
+
rule.from_right_to_left(left_object, right_object)
|
50
57
|
|
51
|
-
|
52
|
-
end
|
58
|
+
expect(left_object.key1).to be_nil
|
53
59
|
end
|
54
60
|
end
|
61
|
+
end
|
55
62
|
|
56
|
-
|
57
|
-
|
58
|
-
it 'should return default value if not found' do
|
59
|
-
rule = TwoWayMapper::Rule.new left_node, right_node, map: map, default: 'not found'
|
63
|
+
context 'with map option' do
|
64
|
+
let(:options) { { map: map } }
|
60
65
|
|
61
|
-
|
62
|
-
|
63
|
-
|
66
|
+
describe '#from_left_to_right' do
|
67
|
+
it 'should read from left node and write to right node' do
|
68
|
+
left_object.key1 = 'value'
|
69
|
+
right_object = {}
|
70
|
+
rule.from_left_to_right(left_object, right_object)
|
64
71
|
|
65
|
-
|
66
|
-
|
72
|
+
expect(right_object).to eql Kk: { Key1: 'VALUE' }
|
73
|
+
end
|
74
|
+
end
|
67
75
|
|
68
|
-
|
69
|
-
|
76
|
+
describe '#from_right_to_left' do
|
77
|
+
it 'should read from right node and write to left node' do
|
78
|
+
left_object.key1 = nil
|
79
|
+
right_object = { Kk: { Key1: 'VALUE' } }
|
80
|
+
rule.from_right_to_left(left_object, right_object)
|
70
81
|
|
71
|
-
|
72
|
-
|
73
|
-
|
82
|
+
expect(left_object.key1).to eql 'value'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'with map and default option' do
|
88
|
+
describe '#from_left_to_right' do
|
89
|
+
it 'should return default value if not found' do
|
90
|
+
rule = described_class.new [left_node], [right_node], map: map, default: 'not found'
|
91
|
+
|
92
|
+
left_object.key1 = 'value1'
|
93
|
+
right_object = {}
|
94
|
+
rule.from_left_to_right(left_object, right_object)
|
74
95
|
|
75
|
-
|
76
|
-
end
|
96
|
+
expect(right_object).to eql Kk: { Key1: 'not found' }
|
77
97
|
end
|
78
98
|
|
79
|
-
|
80
|
-
|
81
|
-
|
99
|
+
it 'should return use default_left if present and value not found' do
|
100
|
+
rule = described_class.new(
|
101
|
+
[left_node],
|
102
|
+
[right_node],
|
103
|
+
map: map,
|
104
|
+
default: 'not found',
|
105
|
+
default_left: 'not found on left',
|
106
|
+
default_right: 'not found on right'
|
107
|
+
)
|
82
108
|
|
83
|
-
|
84
|
-
|
85
|
-
|
109
|
+
left_object.key1 = 'value1'
|
110
|
+
right_object = {}
|
111
|
+
rule.from_left_to_right(left_object, right_object)
|
86
112
|
|
87
|
-
|
88
|
-
|
113
|
+
expect(right_object).to eql Kk: { Key1: 'not found on left' }
|
114
|
+
end
|
115
|
+
end
|
89
116
|
|
90
|
-
|
91
|
-
|
117
|
+
describe '#from_right_to_left' do
|
118
|
+
it 'should return default value if not found' do
|
119
|
+
rule = described_class.new [left_node], [right_node], map: map, default: 'not found'
|
92
120
|
|
93
|
-
|
94
|
-
|
95
|
-
|
121
|
+
left_object.key1 = nil
|
122
|
+
right_object = { Kk: { Key1: 'VALUE1' } }
|
123
|
+
rule.from_right_to_left(left_object, right_object)
|
96
124
|
|
97
|
-
|
98
|
-
|
125
|
+
expect(left_object.key1).to eql 'not found'
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should return use default_right if present and value not found' do
|
129
|
+
rule = described_class.new(
|
130
|
+
[left_node],
|
131
|
+
[right_node],
|
132
|
+
map: map,
|
133
|
+
default: 'not found',
|
134
|
+
default_left: 'not found on left',
|
135
|
+
default_right: 'not found on right'
|
136
|
+
)
|
137
|
+
|
138
|
+
left_object.key1 = nil
|
139
|
+
right_object = { Kk: { Key1: 'VALUE1' } }
|
140
|
+
rule.from_right_to_left(left_object, right_object)
|
141
|
+
|
142
|
+
expect(left_object.key1).to eql 'not found on right'
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'with callback option' do
|
148
|
+
describe '#on_left_to_right' do
|
149
|
+
it 'should transform value if such options passed' do
|
150
|
+
rule = described_class.new(
|
151
|
+
[left_node],
|
152
|
+
[right_node],
|
153
|
+
on_left_to_right: ->(v, _l, _r, _n) { v.upcase }
|
154
|
+
)
|
155
|
+
|
156
|
+
left_object.key1 = 'value1'
|
157
|
+
right_object = {}
|
158
|
+
rule.from_left_to_right(left_object, right_object)
|
159
|
+
|
160
|
+
expect(right_object).to eql Kk: { Key1: 'VALUE1' }
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'should pass left object and right object' do
|
164
|
+
rule = described_class.new(
|
165
|
+
[left_node],
|
166
|
+
[right_node],
|
167
|
+
on_left_to_right: ->(_v, l, r, n) { "#{l.object_id}-#{r.object_id}-#{n.selector}" }
|
168
|
+
)
|
169
|
+
|
170
|
+
left_object.key1 = 'value1'
|
171
|
+
right_object = {}
|
172
|
+
rule.from_left_to_right(left_object, right_object)
|
173
|
+
|
174
|
+
expect(right_object).to eql Kk: { Key1: "#{left_object.object_id}-#{right_object.object_id}-#{left_node.selector}" }
|
99
175
|
end
|
100
176
|
end
|
101
177
|
|
102
|
-
describe '
|
103
|
-
|
104
|
-
|
105
|
-
|
178
|
+
describe '#on_right_to_left' do
|
179
|
+
it 'should transform value if such options passed' do
|
180
|
+
rule = described_class.new(
|
181
|
+
[left_node],
|
182
|
+
[right_node],
|
183
|
+
on_right_to_left: ->(v, _l, _r, _n) { v.downcase }
|
184
|
+
)
|
185
|
+
|
186
|
+
left_object.key1 = nil
|
187
|
+
right_object = { Kk: { Key1: 'VALUE1' } }
|
188
|
+
rule.from_right_to_left(left_object, right_object)
|
189
|
+
|
190
|
+
expect(left_object.key1).to eql 'value1'
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'should pass left object and right object' do
|
194
|
+
rule = described_class.new(
|
195
|
+
[left_node],
|
196
|
+
[right_node],
|
197
|
+
on_right_to_left: ->(_v, l, r, n) { "#{l.object_id}-#{r.object_id}-#{n.selector}" }
|
198
|
+
)
|
106
199
|
|
107
|
-
|
108
|
-
|
109
|
-
|
200
|
+
left_object.key1 = nil
|
201
|
+
right_object = { Kk: { Key1: 'VALUE1' } }
|
202
|
+
rule.from_right_to_left(left_object, right_object)
|
110
203
|
|
111
|
-
|
112
|
-
end
|
204
|
+
expect(left_object.key1).to eql "#{left_object.object_id}-#{right_object.object_id}-#{right_node.selector}"
|
113
205
|
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
context 'with multiple nodes on the left side' do
|
210
|
+
let(:another_left_node) { TwoWayMapper::Node::Object.new('key2') }
|
211
|
+
let(:left_nodes) { [left_node, another_left_node] }
|
212
|
+
|
213
|
+
describe '#from_left_to_right' do
|
214
|
+
it 'should get first non nil value from left nodes and write to the right node' do
|
215
|
+
left_object.key2 = 'value2'
|
216
|
+
right_object = {}
|
217
|
+
rule.from_left_to_right(left_object, right_object)
|
218
|
+
|
219
|
+
expect(right_object).to eql Kk: { Key1: 'value2' }
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
describe '#from_right_to_left' do
|
224
|
+
it 'should read from right node and write to all left nodes' do
|
225
|
+
left_object.key1 = nil
|
226
|
+
left_object.key2 = nil
|
227
|
+
right_object = { Kk: { Key1: 'value1' } }
|
228
|
+
rule.from_right_to_left(left_object, right_object)
|
229
|
+
|
230
|
+
expect(left_object.key1).to eql 'value1'
|
231
|
+
expect(left_object.key2).to eql 'value1'
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
context 'with multiple nodes on the right side' do
|
237
|
+
let(:another_right_node) { TwoWayMapper::Node::Hash.new('Kk1.Key') }
|
238
|
+
let(:right_nodes) { [right_node, another_right_node] }
|
239
|
+
|
240
|
+
describe '#from_left_to_right' do
|
241
|
+
it 'should read from the left node and write to all right nodes' do
|
242
|
+
left_object.key1 = 'value'
|
243
|
+
right_object = {}
|
244
|
+
rule.from_left_to_right(left_object, right_object)
|
245
|
+
|
246
|
+
expect(right_object).to eql Kk: { Key1: 'value' }, Kk1: { Key: 'value' }
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
describe '#from_right_to_left' do
|
251
|
+
it 'should get first non nil value from right nodes and write to the left node' do
|
252
|
+
left_object.key1 = nil
|
253
|
+
right_object = { Kk1: { Key: 'value' } }
|
254
|
+
rule.from_right_to_left(left_object, right_object)
|
255
|
+
|
256
|
+
expect(left_object.key1).to eql 'value'
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
context 'with multiple nodes on both sides' do
|
262
|
+
let(:another_left_node) { TwoWayMapper::Node::Object.new('key2') }
|
263
|
+
let(:left_nodes) { [left_node, another_left_node] }
|
264
|
+
let(:another_right_node) { TwoWayMapper::Node::Hash.new('Kk1.Key') }
|
265
|
+
let(:right_nodes) { [right_node, another_right_node] }
|
266
|
+
|
267
|
+
describe '#from_left_to_right' do
|
268
|
+
it 'should get first non nil value from left nodes and write to all right nodes' do
|
269
|
+
left_object.key2 = 'value'
|
270
|
+
right_object = {}
|
271
|
+
rule.from_left_to_right(left_object, right_object)
|
272
|
+
|
273
|
+
expect(right_object).to eql Kk: { Key1: 'value' }, Kk1: { Key: 'value' }
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
describe '#from_right_to_left' do
|
278
|
+
it 'should get first non nil value from right nodes and write to all left nodes' do
|
279
|
+
left_object.key1 = nil
|
280
|
+
left_object.key2 = nil
|
281
|
+
right_object = { Kk1: { Key: 'value' } }
|
282
|
+
rule.from_right_to_left(left_object, right_object)
|
283
|
+
|
284
|
+
expect(left_object.key1).to eql 'value'
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
114
288
|
|
115
|
-
|
116
|
-
|
117
|
-
|
289
|
+
describe 'multiple nodes with callback' do
|
290
|
+
let(:another_left_node) { TwoWayMapper::Node::Object.new('key2') }
|
291
|
+
let(:left_nodes) { [left_node, another_left_node] }
|
292
|
+
# return false on empty string to emulate a situation when we need to skip blank values
|
293
|
+
let(:options) { { on_left_to_right: proc { |v| v != '' && v } } }
|
118
294
|
|
119
|
-
|
120
|
-
|
121
|
-
|
295
|
+
describe '#from_left_to_right' do
|
296
|
+
it 'should involve the callback' do
|
297
|
+
left_object.key1 = ''
|
298
|
+
left_object.key2 = 'value'
|
299
|
+
right_object = {}
|
300
|
+
rule.from_left_to_right(left_object, right_object)
|
122
301
|
|
123
|
-
|
124
|
-
end
|
302
|
+
expect(right_object).to eql Kk: { Key1: 'value' }
|
125
303
|
end
|
126
304
|
end
|
127
305
|
end
|