two-way-mapper 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/two_way_mapper/mapping.rb +23 -21
- data/lib/two_way_mapper/rule.rb +34 -15
- data/lib/two_way_mapper/version.rb +1 -1
- data/spec/mapping_spec.rb +32 -24
- data/spec/rule_spec.rb +149 -122
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 524242de8d10dfa77f277974cd5e1670dcc68b0345b371d847a687cce8998c59
|
4
|
+
data.tar.gz: e4b0d1784f91ee600a316c161a8bb97b3bccabd6c2d97a1296dbb82596a93c08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce3eb28e41536134ac6c221b41c7bc0c0fecd01092a8f2f26c7076d4d7249a93c26c1e8103a9644a8418e7d93e8570fd273a4eb96023b52d77f92138cfa81be8
|
7
|
+
data.tar.gz: '09b3e9f0ccf3cc4e9f5ca8d3668b2cd7b253d7c9190f06daceb3afb3f3c0f4d58329d0a12ec394e6675fdd95ec79d1a28c26242037d24b0387193db6957d2c2c'
|
@@ -2,31 +2,34 @@
|
|
2
2
|
|
3
3
|
module TwoWayMapper
|
4
4
|
class Mapping
|
5
|
+
DIRECTIONS = [:left, :right].freeze
|
6
|
+
|
5
7
|
attr_reader :rules, :left_class, :left_options, :right_class, :right_options
|
6
8
|
|
7
9
|
def initialize
|
8
10
|
@rules = []
|
9
11
|
end
|
10
12
|
|
11
|
-
[
|
13
|
+
[DIRECTIONS, DIRECTIONS.reverse].each do |from, to|
|
12
14
|
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
13
|
-
def #{
|
14
|
-
@#{
|
15
|
-
@#{
|
15
|
+
def #{from}(plugin, options = {})
|
16
|
+
@#{from}_class = node_class(plugin)
|
17
|
+
@#{from}_options = options
|
16
18
|
end
|
17
|
-
CODE
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
def #{from}_selectors(mappable: false)
|
21
|
+
rules.each_with_object [] do |rule, memo|
|
22
|
+
next if mappable && rule.from_#{from}_to_#{to}_only?
|
23
|
+
|
24
|
+
memo << rule.#{from}.selector
|
25
|
+
end
|
22
26
|
end
|
23
|
-
CODE
|
24
|
-
end
|
25
27
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
def from_#{from}_to_#{to}(left_obj, right_obj)
|
29
|
+
rules.each { |rule| rule.from_#{from}_to_#{to}(left_obj, right_obj) }
|
30
|
+
#{to}_obj
|
31
|
+
end
|
32
|
+
CODE
|
30
33
|
end
|
31
34
|
|
32
35
|
def rule(left_selector, right_selector = {}, options = {})
|
@@ -53,13 +56,12 @@ module TwoWayMapper
|
|
53
56
|
@rules << Rule.new(left, right, opt)
|
54
57
|
end
|
55
58
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
CODE
|
59
|
+
private
|
60
|
+
|
61
|
+
def node_class(plugin)
|
62
|
+
TwoWayMapper::Node.const_get(plugin.to_s.camelize)
|
63
|
+
rescue NameError
|
64
|
+
raise NameError, 'Cannot find node'
|
63
65
|
end
|
64
66
|
end
|
65
67
|
end
|
data/lib/two_way_mapper/rule.rb
CHANGED
@@ -10,29 +10,48 @@ module TwoWayMapper
|
|
10
10
|
@options = opt
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
13
|
+
def from_left_to_right(left_obj, right_obj)
|
14
|
+
return right_obj if from_right_to_left_only?
|
15
|
+
|
16
|
+
value = left.read(left_obj)
|
17
|
+
value = map_value(value, true)
|
18
|
+
if @options[:on_left_to_right].respond_to?(:call)
|
19
|
+
value = @options[:on_left_to_right].call(value, left_obj, right_obj)
|
20
|
+
end
|
21
|
+
right.write(right_obj, value)
|
22
|
+
|
23
|
+
right_obj
|
24
|
+
end
|
25
|
+
|
26
|
+
def from_right_to_left(left_obj, right_obj)
|
27
|
+
return left_obj if from_left_to_right_only?
|
28
|
+
|
29
|
+
value = right.read(right_obj)
|
30
|
+
value = map_value(value, false)
|
31
|
+
if @options[:on_right_to_left].respond_to?(:call)
|
32
|
+
value = @options[:on_right_to_left].call(value, left_obj, right_obj)
|
33
|
+
end
|
34
|
+
left.write(left_obj, value)
|
35
|
+
|
36
|
+
left_obj
|
37
|
+
end
|
38
|
+
|
39
|
+
def from_right_to_left_only?
|
40
|
+
@options[:from_right_to_left_only]
|
41
|
+
end
|
42
|
+
|
43
|
+
def from_left_to_right_only?
|
44
|
+
@options[:from_left_to_right_only]
|
26
45
|
end
|
27
46
|
|
28
47
|
private
|
29
48
|
|
30
49
|
def map_value(value, left_to_right = true)
|
31
50
|
map = @options[:map]
|
32
|
-
if map
|
51
|
+
if map.is_a?(Hash)
|
33
52
|
map = map.invert unless left_to_right
|
34
53
|
default_key = "default_#{left_to_right ? 'left' : 'right'}".to_sym
|
35
|
-
|
54
|
+
map[value] || @options[default_key] || @options[:default]
|
36
55
|
else
|
37
56
|
value
|
38
57
|
end
|
data/spec/mapping_spec.rb
CHANGED
@@ -3,39 +3,45 @@
|
|
3
3
|
describe TwoWayMapper::Mapping do
|
4
4
|
let(:mapping) { described_class.new }
|
5
5
|
|
6
|
-
|
7
|
-
describe "##{
|
8
|
-
it "should set #{
|
9
|
-
mapping.send
|
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: ''
|
10
10
|
|
11
|
-
expect(mapping.send("#{
|
12
|
-
expect(mapping.send("#{
|
11
|
+
expect(mapping.send("#{direction}_class")).to eql TwoWayMapper::Node::Object
|
12
|
+
expect(mapping.send("#{direction}_options")).to include opt1: ''
|
13
13
|
end
|
14
14
|
end
|
15
|
+
end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
context 'selectors' do
|
18
|
+
before do
|
19
|
+
mapping.left :object
|
20
|
+
mapping.right :object
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
mapping.rule 'firstname', 'FirstName'
|
23
|
+
mapping.rule 'fullname', 'FullName', from_right_to_left_only: true
|
24
|
+
mapping.rule 'lastname', 'LastName'
|
25
|
+
mapping.rule 'fullname1', 'FullName1', from_left_to_right_only: true
|
26
|
+
end
|
24
27
|
|
25
|
-
|
26
|
-
|
28
|
+
describe '#left_selectors' do
|
29
|
+
it 'should get left selectors' do
|
30
|
+
expect(mapping.left_selectors).to eql %w(firstname fullname lastname fullname1)
|
31
|
+
end
|
27
32
|
|
28
|
-
|
29
|
-
|
30
|
-
end
|
33
|
+
it 'should include only mappable selectors if such option is passed' do
|
34
|
+
expect(mapping.left_selectors(mappable: true)).to eql %w(firstname fullname lastname)
|
31
35
|
end
|
36
|
+
end
|
32
37
|
|
33
|
-
|
34
|
-
|
38
|
+
describe '#right_selectors' do
|
39
|
+
it 'should get right selectors' do
|
40
|
+
expect(mapping.right_selectors).to eql %w(FirstName FullName LastName FullName1)
|
41
|
+
end
|
35
42
|
|
36
|
-
|
37
|
-
|
38
|
-
end
|
43
|
+
it 'should include only mappable selectors if such option is passed' do
|
44
|
+
expect(mapping.right_selectors(mappable: true)).to eql %w(FirstName LastName FullName1)
|
39
45
|
end
|
40
46
|
end
|
41
47
|
end
|
@@ -110,7 +116,9 @@ describe TwoWayMapper::Mapping do
|
|
110
116
|
allow(mapping).to receive(:rules).and_return [rule1, rule2]
|
111
117
|
end
|
112
118
|
|
113
|
-
[
|
119
|
+
[described_class::DIRECTIONS, described_class::DIRECTIONS.reverse].each do |from, to|
|
120
|
+
method = "from_#{from}_to_#{to}"
|
121
|
+
|
114
122
|
describe "##{method}" do
|
115
123
|
it 'should proxy to all rules' do
|
116
124
|
expect(rule1).to receive(method).with left_obj, right_obj
|
data/spec/rule_spec.rb
CHANGED
@@ -1,151 +1,178 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
describe TwoWayMapper::Rule do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
4
|
+
let(:left_node) { TwoWayMapper::Node::Object.new('key1') }
|
5
|
+
let(:right_node) { TwoWayMapper::Node::Hash.new('Kk.Key1') }
|
6
|
+
let(:left_object) { OpenStruct.new }
|
7
|
+
let(:map) { { 'value' => 'VALUE' } }
|
8
|
+
let(:rule) { described_class.new(left_node, right_node, options) }
|
9
|
+
|
10
|
+
context 'without options' do
|
11
|
+
let(:options) { {} }
|
12
|
+
|
13
|
+
describe '#from_left_to_right' do
|
14
|
+
it 'should read from left node and write to right node' do
|
15
|
+
left_object.key1 = 'value1'
|
16
|
+
right_object = {}
|
17
|
+
rule.from_left_to_right(left_object, right_object)
|
18
|
+
|
19
|
+
expect(right_object).to eql Kk: { Key1: 'value1' }
|
21
20
|
end
|
21
|
+
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
describe '#from_right_to_left' do
|
24
|
+
it 'should read from right node and write to left node' do
|
25
|
+
left_object.key1 = nil
|
26
|
+
right_object = { Kk: { Key1: 'value1' } }
|
27
|
+
rule.from_right_to_left(left_object, right_object)
|
28
28
|
|
29
|
-
|
30
|
-
end
|
29
|
+
expect(left_object.key1).to eql 'value1'
|
31
30
|
end
|
32
31
|
end
|
32
|
+
end
|
33
33
|
|
34
|
-
|
35
|
-
|
34
|
+
context 'with map option' do
|
35
|
+
let(:options) { { map: map } }
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
describe '#from_left_to_right' do
|
38
|
+
it 'should read from left node and write to right node' do
|
39
|
+
left_object.key1 = 'value'
|
40
|
+
right_object = {}
|
41
|
+
rule.from_left_to_right(left_object, right_object)
|
42
42
|
|
43
|
-
|
44
|
-
end
|
43
|
+
expect(right_object).to eql Kk: { Key1: 'VALUE' }
|
45
44
|
end
|
45
|
+
end
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
describe '#from_right_to_left' do
|
48
|
+
it 'should read from right node and write to left node' do
|
49
|
+
left_object.key1 = nil
|
50
|
+
right_object = { Kk: { Key1: 'VALUE' } }
|
51
|
+
rule.from_right_to_left(left_object, right_object)
|
52
52
|
|
53
|
-
|
54
|
-
end
|
53
|
+
expect(left_object.key1).to eql 'value'
|
55
54
|
end
|
56
55
|
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with default option' do
|
59
|
+
describe '#from_left_to_right' do
|
60
|
+
it 'should return default value if not found' do
|
61
|
+
rule = described_class.new left_node, right_node, map: map, default: 'not found'
|
62
|
+
|
63
|
+
left_object.key1 = 'value1'
|
64
|
+
right_object = {}
|
65
|
+
rule.from_left_to_right(left_object, right_object)
|
66
|
+
|
67
|
+
expect(right_object).to eql Kk: { Key1: 'not found' }
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should return use default_left if present and value not found' do
|
71
|
+
rule = described_class.new(
|
72
|
+
left_node,
|
73
|
+
right_node,
|
74
|
+
map: map,
|
75
|
+
default: 'not found',
|
76
|
+
default_left: 'not found on left',
|
77
|
+
default_right: 'not found on right'
|
78
|
+
)
|
79
|
+
|
80
|
+
left_object.key1 = 'value1'
|
81
|
+
right_object = {}
|
82
|
+
rule.from_left_to_right(left_object, right_object)
|
83
|
+
|
84
|
+
expect(right_object).to eql Kk: { Key1: 'not found on left' }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#from_right_to_left' 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 = nil
|
93
|
+
right_object = { Kk: { Key1: 'VALUE1' } }
|
94
|
+
rule.from_right_to_left(left_object, right_object)
|
57
95
|
|
58
|
-
|
59
|
-
describe '#from_left_to_right' do
|
60
|
-
it 'should return default value if not found' do
|
61
|
-
rule = described_class.new left_node, right_node, map: map, default: 'not found'
|
62
|
-
|
63
|
-
left_object.key1 = 'value1'
|
64
|
-
right_object = {}
|
65
|
-
rule.from_left_to_right left_object, right_object
|
66
|
-
|
67
|
-
expect(right_object).to eql Kk: { Key1: 'not found' }
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'should return use default_left if present and value not found' do
|
71
|
-
rule = described_class.new(
|
72
|
-
left_node,
|
73
|
-
right_node,
|
74
|
-
map: map,
|
75
|
-
default: 'not found',
|
76
|
-
default_left: 'not found on left',
|
77
|
-
default_right: 'not found on right'
|
78
|
-
)
|
79
|
-
|
80
|
-
left_object.key1 = 'value1'
|
81
|
-
right_object = {}
|
82
|
-
rule.from_left_to_right left_object, right_object
|
83
|
-
|
84
|
-
expect(right_object).to eql Kk: { Key1: 'not found on left' }
|
85
|
-
end
|
96
|
+
expect(left_object.key1).to eql 'not found'
|
86
97
|
end
|
87
98
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
map: map,
|
104
|
-
default: 'not found',
|
105
|
-
default_left: 'not found on left',
|
106
|
-
default_right: 'not found on right'
|
107
|
-
)
|
108
|
-
|
109
|
-
left_object.key1 = nil
|
110
|
-
right_object = { Kk: { Key1: 'VALUE1' } }
|
111
|
-
rule.from_right_to_left left_object, right_object
|
112
|
-
|
113
|
-
expect(left_object.key1).to eql 'not found on right'
|
114
|
-
end
|
99
|
+
it 'should return use default_right 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
|
+
)
|
108
|
+
|
109
|
+
left_object.key1 = nil
|
110
|
+
right_object = { Kk: { Key1: 'VALUE1' } }
|
111
|
+
rule.from_right_to_left(left_object, right_object)
|
112
|
+
|
113
|
+
expect(left_object.key1).to eql 'not found on right'
|
115
114
|
end
|
116
115
|
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe 'with callback option' do
|
119
|
+
describe 'on_left_to_right' do
|
120
|
+
it 'should transform value if such options passed' do
|
121
|
+
rule = described_class.new(
|
122
|
+
left_node,
|
123
|
+
right_node,
|
124
|
+
on_left_to_right: ->(v, _l, _r) { v.upcase }
|
125
|
+
)
|
126
|
+
|
127
|
+
left_object.key1 = 'value1'
|
128
|
+
right_object = {}
|
129
|
+
rule.from_left_to_right(left_object, right_object)
|
130
|
+
|
131
|
+
expect(right_object).to eql Kk: { Key1: 'VALUE1' }
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should pass left object and right object' do
|
135
|
+
rule = described_class.new(
|
136
|
+
left_node,
|
137
|
+
right_node,
|
138
|
+
on_left_to_right: ->(_v, l, r) { "#{l.object_id}-#{r.object_id}" }
|
139
|
+
)
|
140
|
+
|
141
|
+
left_object.key1 = 'value1'
|
142
|
+
right_object = {}
|
143
|
+
rule.from_left_to_right(left_object, right_object)
|
144
|
+
|
145
|
+
expect(right_object).to eql Kk: { Key1: "#{left_object.object_id}-#{right_object.object_id}" }
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe 'on_right_to_left' do
|
150
|
+
it 'should transform value if such options passed' do
|
151
|
+
rule = described_class.new(
|
152
|
+
left_node,
|
153
|
+
right_node,
|
154
|
+
on_right_to_left: ->(v, _l, _r) { v.downcase }
|
155
|
+
)
|
156
|
+
|
157
|
+
left_object.key1 = nil
|
158
|
+
right_object = { Kk: { Key1: 'VALUE1' } }
|
159
|
+
rule.from_right_to_left(left_object, right_object)
|
117
160
|
|
118
|
-
|
119
|
-
describe 'on_left_to_right' do
|
120
|
-
it 'should transform value if such options passed' do
|
121
|
-
rule = described_class.new(
|
122
|
-
left_node,
|
123
|
-
right_node,
|
124
|
-
on_left_to_right: ->(v) { v.upcase }
|
125
|
-
)
|
126
|
-
|
127
|
-
left_object.key1 = 'value1'
|
128
|
-
right_object = {}
|
129
|
-
rule.from_left_to_right left_object, right_object
|
130
|
-
|
131
|
-
expect(right_object).to eql Kk: { Key1: 'VALUE1' }
|
132
|
-
end
|
161
|
+
expect(left_object.key1).to eql 'value1'
|
133
162
|
end
|
134
163
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
)
|
164
|
+
it 'should pass left object and right object' do
|
165
|
+
rule = described_class.new(
|
166
|
+
left_node,
|
167
|
+
right_node,
|
168
|
+
on_right_to_left: ->(_v, l, r) { "#{l.object_id}-#{r.object_id}" }
|
169
|
+
)
|
142
170
|
|
143
|
-
|
144
|
-
|
145
|
-
|
171
|
+
left_object.key1 = nil
|
172
|
+
right_object = { Kk: { Key1: 'VALUE1' } }
|
173
|
+
rule.from_right_to_left(left_object, right_object)
|
146
174
|
|
147
|
-
|
148
|
-
end
|
175
|
+
expect(left_object.key1).to eql "#{left_object.object_id}-#{right_object.object_id}"
|
149
176
|
end
|
150
177
|
end
|
151
178
|
end
|