two-way-mapper 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b6b6b6c10afaa565467784f5fca1b94bb7a6a7040d0edcff5c8be15a71114db
4
- data.tar.gz: a996e65d5901e53b367134044b8e322e15f9c3dd105f7ae41d0d46345bca001c
3
+ metadata.gz: 524242de8d10dfa77f277974cd5e1670dcc68b0345b371d847a687cce8998c59
4
+ data.tar.gz: e4b0d1784f91ee600a316c161a8bb97b3bccabd6c2d97a1296dbb82596a93c08
5
5
  SHA512:
6
- metadata.gz: 434786c065ea474bd39fceeb6e43961eaa97a0b1052f7ce8f9f6da957eb98aab76eb3b1e637759c50ff7a2d78e887645be86715f084478514d5a993d8df65c22
7
- data.tar.gz: 1752b21435477d3f948f87c69655cc606de07f80afefc156f2717851051be1cf3a141b257a6eea2deb8bbaa756468fc8a67102232ae7f228e7ef1d43a3d2c2ee
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
- [:left, :right].each do |method|
13
+ [DIRECTIONS, DIRECTIONS.reverse].each do |from, to|
12
14
  class_eval <<-CODE, __FILE__, __LINE__ + 1
13
- def #{method}(plugin, options = {})
14
- @#{method}_class = node_class(plugin)
15
- @#{method}_options = options
15
+ def #{from}(plugin, options = {})
16
+ @#{from}_class = node_class(plugin)
17
+ @#{from}_options = options
16
18
  end
17
- CODE
18
19
 
19
- class_eval <<-CODE, __FILE__, __LINE__ + 1
20
- def #{method}_selectors
21
- rules.map { |rule| rule.#{method}.selector }
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
- def node_class(plugin)
27
- TwoWayMapper::Node.const_get(plugin.to_s.camelize)
28
- rescue NameError
29
- raise NameError, 'Cannot find node'
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
- { left: :right, right: :left }.each do |from, to|
57
- class_eval <<-CODE, __FILE__, __LINE__ + 1
58
- def from_#{from}_to_#{to}(left_obj, right_obj)
59
- rules.each { |r| r.from_#{from}_to_#{to}(left_obj, right_obj) }
60
- #{to}_obj
61
- end
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
@@ -10,29 +10,48 @@ module TwoWayMapper
10
10
  @options = opt
11
11
  end
12
12
 
13
- { left: :right, right: :left }.each do |from, to|
14
- class_eval <<-CODE, __FILE__, __LINE__ + 1
15
- def from_#{from}_to_#{to}(left_obj, right_obj)
16
- value = #{from}.read(#{from}_obj)
17
- value = map_value(value, #{(from == :left).inspect})
18
- if @options[:on_#{from}_to_#{to}].respond_to?(:call)
19
- value = @options[:on_#{from}_to_#{to}].call(value)
20
- end
21
- #{to}.write(#{to}_obj, value)
22
-
23
- #{to}_obj
24
- end
25
- CODE
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 && map.is_a?(Hash)
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
- value = map[value] || @options[default_key] || @options[:default]
54
+ map[value] || @options[default_key] || @options[:default]
36
55
  else
37
56
  value
38
57
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TwoWayMapper
4
- VERSION = '0.1.1'
4
+ VERSION = '0.1.2'
5
5
  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
- [:left, :right].each do |method|
7
- describe "##{method}" do
8
- it "should set #{method} with options" do
9
- mapping.send method, :object, opt1: ''
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("#{method}_class")).to eql TwoWayMapper::Node::Object
12
- expect(mapping.send("#{method}_options")).to include opt1: ''
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
- context 'selectors' do
17
- before do
18
- mapping.left :object
19
- mapping.right :object
17
+ context 'selectors' do
18
+ before do
19
+ mapping.left :object
20
+ mapping.right :object
20
21
 
21
- mapping.rule 'firstname', 'FirstName'
22
- mapping.rule 'lastname', 'LastName'
23
- end
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
- describe "#left_selectors" do
26
- subject { mapping.left_selectors }
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
- it "should get left selectors" do
29
- is_expected.to eql %w(firstname lastname)
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
- describe "#right_selectors" do
34
- subject { mapping.right_selectors }
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
- it "should get right selectors" do
37
- is_expected.to eql %w(FirstName LastName)
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
- [:from_left_to_right, :from_right_to_left].each do |method|
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
- context 'transformation methods' do
5
- let(:left_node) { TwoWayMapper::Node::Object.new('key1') }
6
- let(:right_node) { TwoWayMapper::Node::Hash.new('Kk.Key1') }
7
- let(:left_object) { OpenStruct.new }
8
- let(:map) { { 'value' => 'VALUE' } }
9
-
10
- context 'without options' do
11
- let(:rule) { described_class.new left_node, right_node }
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' }
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
- 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
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
- expect(left_object.key1).to eql 'value1'
30
- end
29
+ expect(left_object.key1).to eql 'value1'
31
30
  end
32
31
  end
32
+ end
33
33
 
34
- context 'with map option' do
35
- let(:rule) { described_class.new left_node, right_node, map: map, default: 'not found' }
34
+ context 'with map option' do
35
+ let(:options) { { map: map } }
36
36
 
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
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
- expect(right_object).to eql Kk: { Key1: 'VALUE' }
44
- end
43
+ expect(right_object).to eql Kk: { Key1: 'VALUE' }
45
44
  end
45
+ end
46
46
 
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
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
- expect(left_object.key1).to eql 'value'
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
- 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
96
+ expect(left_object.key1).to eql 'not found'
86
97
  end
87
98
 
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
95
-
96
- expect(left_object.key1).to eql 'not found'
97
- end
98
-
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'
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
- 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) { 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
- describe 'on_right_to_left' do
136
- it 'should transform value if such options passed' do
137
- rule = described_class.new(
138
- left_node,
139
- right_node,
140
- on_right_to_left: ->(v) { v.downcase }
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
- left_object.key1 = nil
144
- right_object = { Kk: { Key1: 'VALUE1' } }
145
- rule.from_right_to_left left_object, right_object
171
+ left_object.key1 = nil
172
+ right_object = { Kk: { Key1: 'VALUE1' } }
173
+ rule.from_right_to_left(left_object, right_object)
146
174
 
147
- expect(left_object.key1).to eql 'value1'
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: two-way-mapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Masliuchenko