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 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