rom-mapper 0.2.0 → 0.3.0.beta1

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
  SHA1:
3
- metadata.gz: 1305458b68360474e3be88eb5418ce057e7a5dc3
4
- data.tar.gz: 69e816fabf9130eaf6daf3300f56b9efce63161f
3
+ metadata.gz: e261943dc4114a157a1f142045a0f5ee033dd5c5
4
+ data.tar.gz: 06c40a576ebf206f9719c161f332f43a5dbf075c
5
5
  SHA512:
6
- metadata.gz: 1184db0c8ce2fd3bea1d7bb7cdec72a8f1a7f298f0be35482a2357081c9841896aeea87e0a648f5deab1af1cad8a5160ac888ebc9840cadf960952421143e4f5
7
- data.tar.gz: fa2c178cdcf7ce602c4390a633fd255c2a04f15b5fe3425d90445ca6a6fa30bcb5ed1ed320adedee55e581e7f0c30530cbe7deb8fd618ff426f1947c866bfa4b
6
+ metadata.gz: 5f3dd818d7f91c3c73828bd8ed93354e41183bd86d3a3a30c1f8a26bad02994a37ed86c22befc4fa473d11b788595805a015d41792226ba12947fd6af71a984f
7
+ data.tar.gz: d53d9d99ad4be33c2faf1eca94eff0cf05bd75966e2cf6267afda48c605d7551772f141d3cb1c0b4f370d9a6bf3d9344838b456f9abde81cd303f3774d994115
data/.travis.yml CHANGED
@@ -8,7 +8,7 @@ rvm:
8
8
  - 2.1
9
9
  - 2.2
10
10
  - rbx-2
11
- - jruby
11
+ - jruby-9000
12
12
  - ruby-head
13
13
  - jruby-head
14
14
  env:
data/Gemfile CHANGED
@@ -2,8 +2,11 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
+ gem 'transproc', github: 'solnic/transproc', branch: 'master'
6
+ gem 'rom-support', github: 'rom-rb/rom-support', branch: 'master'
7
+
5
8
  group :test do
6
- gem 'anima'
9
+ gem 'anima', '~> 0.2.0'
7
10
  gem 'virtus'
8
11
  gem 'inflecto', '~> 0.0', '>= 0.0.2'
9
12
 
@@ -13,7 +16,7 @@ group :test do
13
16
  end
14
17
 
15
18
  group :benchmarks do
16
- gem 'benchmark-ips', '~> 2.2.0'
19
+ gem 'benchmark-ips', '~> 2.2'
17
20
  end
18
21
 
19
22
  group :tools do
@@ -26,7 +29,7 @@ group :tools do
26
29
  gem 'byebug'
27
30
 
28
31
  platform :mri do
29
- gem 'mutant', '>= 0.8.0', github: 'mbj/mutant', branch: 'master'
32
+ gem 'mutant', '~> 0.8.0'
30
33
  gem 'mutant-rspec'
31
34
  end
32
35
  end
data/lib/rom-mapper.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'dry-equalizer'
1
2
  require 'rom-support'
2
3
 
3
4
  require 'rom/mapper'
data/lib/rom/header.rb CHANGED
@@ -1,5 +1,3 @@
1
- require 'equalizer'
2
-
3
1
  require 'rom/header/attribute'
4
2
 
5
3
  module ROM
@@ -11,7 +9,7 @@ module ROM
11
9
  # @private
12
10
  class Header
13
11
  include Enumerable
14
- include Equalizer.new(:attributes, :model)
12
+ include Dry::Equalizer(:attributes, :model)
15
13
 
16
14
  # @return [Class] optional model associated with a header
17
15
  #
@@ -182,7 +180,7 @@ module ROM
182
180
  #
183
181
  # @api private
184
182
  def initialize_tuple_keys
185
- @tuple_keys = mapping.keys + non_primitives.flat_map(&:tuple_keys)
183
+ @tuple_keys = mapping.keys.flatten + non_primitives.flat_map(&:tuple_keys)
186
184
  end
187
185
 
188
186
  # Set all tuple keys from all attributes popping from Unwrap and Ungroup
@@ -9,7 +9,7 @@ module ROM
9
9
  #
10
10
  # @private
11
11
  class Attribute
12
- include Equalizer.new(:name, :key, :type)
12
+ include Dry::Equalizer(:name, :key, :type)
13
13
 
14
14
  # @return [Symbol] name of an attribute
15
15
  #
@@ -93,6 +93,10 @@ module ROM
93
93
  def mapping
94
94
  { key => name }
95
95
  end
96
+
97
+ def union?
98
+ key.is_a? ::Array
99
+ end
96
100
  end
97
101
 
98
102
  # Embedded attribute is a special attribute type that has a header
@@ -101,7 +105,7 @@ module ROM
101
105
  #
102
106
  # @private
103
107
  class Embedded < Attribute
104
- include Equalizer.new(:name, :key, :type, :header)
108
+ include Dry::Equalizer(:name, :key, :type, :header)
105
109
 
106
110
  # return [Header] header of an attribute
107
111
  #
data/lib/rom/mapper.rb CHANGED
@@ -1,15 +1,12 @@
1
1
  require 'rom/mapper/dsl'
2
2
 
3
- require 'rom/support/inheritance_hook'
4
-
5
3
  module ROM
6
4
  # Mapper is a simple object that uses transformers to load relations
7
5
  #
8
6
  # @private
9
7
  class Mapper
10
- extend ROM::Support::InheritanceHook
11
8
  include DSL
12
- include Equalizer.new(:transformers, :header)
9
+ include Dry::Equalizer(:transformers, :header)
13
10
 
14
11
  defines :relation, :register_as, :symbolize_keys,
15
12
  :prefix, :prefix_separator, :inherit_header, :reject_keys
@@ -62,9 +59,7 @@ module ROM
62
59
  #
63
60
  # @api private
64
61
  def self.build(header = self.header, processor = :transproc)
65
- processor = Mapper.processors.fetch(processor)
66
- transformers = headers(header).map(&processor.method(:build))
67
- new(transformers, header)
62
+ new(header, processor)
68
63
  end
69
64
 
70
65
  # @api private
@@ -76,8 +71,11 @@ module ROM
76
71
  end
77
72
 
78
73
  # @api private
79
- def initialize(transformers, header)
80
- @transformers = Array(transformers)
74
+ def initialize(header, processor = :transproc)
75
+ processor = Mapper.processors.fetch(processor)
76
+ @transformers = self.class.headers(header).map do |header|
77
+ processor.build(self, header)
78
+ end
81
79
  @header = header
82
80
  end
83
81
 
@@ -48,7 +48,10 @@ module ROM
48
48
  # @api private
49
49
  def build_class
50
50
  return klass if klass
51
- return builder.call(attributes.map(&:first)) if builder
51
+ included_attrs = attributes.reject do |_name, opts|
52
+ opts && opts[:exclude]
53
+ end
54
+ builder.call(included_attrs.map(&:first)) if builder
52
55
  end
53
56
  end
54
57
  end
@@ -1,5 +1,5 @@
1
1
  module ROM
2
2
  class Mapper
3
- VERSION = '0.2.0'.freeze
3
+ VERSION = '0.3.0.beta1'.freeze
4
4
  end
5
5
  end
@@ -21,6 +21,7 @@ module ROM
21
21
  import ::Transproc::ArrayTransformations
22
22
  import ::Transproc::HashTransformations
23
23
  import ::Transproc::ClassTransformations
24
+ import ::Transproc::ProcTransformations
24
25
 
25
26
  def self.identity(tuple)
26
27
  tuple
@@ -29,8 +30,20 @@ module ROM
29
30
  def self.filter_empty(arr)
30
31
  arr.reject { |row| row.values.all?(&:nil?) }
31
32
  end
33
+
34
+ def self.inject_union_value(tuple, name, keys, coercer)
35
+ values = tuple.values_at(*keys)
36
+ result = coercer.call(*values)
37
+
38
+ tuple.merge(name => result)
39
+ end
32
40
  end
33
41
 
42
+ # @return [Mapper] mapper that this processor belongs to
43
+ #
44
+ # @api private
45
+ attr_reader :mapper
46
+
34
47
  # @return [Header] header from a mapper
35
48
  #
36
49
  # @api private
@@ -58,12 +71,13 @@ module ROM
58
71
  # @return [Transproc::Function]
59
72
  #
60
73
  # @api private
61
- def self.build(header)
62
- new(header).to_transproc
74
+ def self.build(mapper, header)
75
+ new(mapper, header).to_transproc
63
76
  end
64
77
 
65
78
  # @api private
66
- def initialize(header)
79
+ def initialize(mapper, header)
80
+ @mapper = mapper
67
81
  @header = header
68
82
  @model = header.model
69
83
  @mapping = header.mapping
@@ -111,8 +125,13 @@ module ROM
111
125
  # @api private
112
126
  def visit_attribute(attribute)
113
127
  coercer = attribute.meta[:coercer]
114
- if coercer
115
- t(:map_value, attribute.name, coercer)
128
+ if attribute.union?
129
+ compose do |ops|
130
+ ops << t(:inject_union_value, attribute.name, attribute.key, coercer)
131
+ ops << t(:reject_keys, attribute.key)
132
+ end
133
+ elsif coercer
134
+ t(:map_value, attribute.name, t(:bind, mapper, coercer))
116
135
  elsif attribute.typed?
117
136
  t(:map_value, attribute.name, t(:"to_#{attribute.type}"))
118
137
  end
@@ -369,7 +388,7 @@ module ROM
369
388
  #
370
389
  # @api private
371
390
  def row_proc_from(attribute)
372
- new(attribute.header).row_proc
391
+ new(mapper, attribute.header).row_proc
373
392
  end
374
393
 
375
394
  # Return a new instance of the processor
data/rom-mapper.gemspec CHANGED
@@ -15,9 +15,8 @@ Gem::Specification.new do |gem|
15
15
  gem.test_files = `git ls-files -- {spec}/*`.split("\n")
16
16
  gem.license = 'MIT'
17
17
 
18
- gem.add_dependency 'transproc', '~> 0.3'
19
- gem.add_dependency 'equalizer', '~> 0.0', '>= 0.0.10'
20
- gem.add_dependency 'rom-support', '~> 0.1', '>= 0.1.0'
18
+ gem.add_dependency 'dry-equalizer', '~> 0.2'
19
+ gem.add_dependency 'rom-support', '~> 1.0.0.beta1'
21
20
 
22
21
  gem.add_development_dependency 'rake', '~> 10.3'
23
22
  gem.add_development_dependency 'rspec', '~> 3.3'
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ describe ROM::Mapper do
4
+ let(:mapper_klass) do
5
+ Class.new(ROM::Mapper).tap do |mapper_klass|
6
+ mapper_klass.class_eval(&mapper_body)
7
+ end
8
+ end
9
+ let(:mapper) { mapper_klass.build }
10
+
11
+ subject { mapper.call(tuples) }
12
+
13
+ describe '.attribute' do
14
+ context 'with block' do
15
+ let(:tuples) { [{ key: 'bar' }] }
16
+ let(:results) { [{ key: 'foo_bar' }] }
17
+ let(:mapper_body) do
18
+ proc do
19
+ attribute(:key) { |key| [prefix, key].join('_') }
20
+
21
+ def prefix
22
+ 'foo'
23
+ end
24
+ end
25
+ end
26
+
27
+ it 'creates the attribute from the proc with the mapper as the binding' do
28
+ is_expected.to match_array(results)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe '.embedded' do
34
+ context 'with block' do
35
+ let(:tuples) { [{ items: { key: 'bar' } }] }
36
+ let(:results) { [{ items: { key: 'foo_bar' } }] }
37
+ let(:mapper_body) do
38
+ proc do
39
+ embedded :items, type: :hash do
40
+ attribute(:key) { |key| [prefix, key].join('_') }
41
+ end
42
+
43
+ def prefix
44
+ 'foo'
45
+ end
46
+ end
47
+ end
48
+
49
+ it 'creates the attribute from the proc with the mapper as the binding' do
50
+ is_expected.to match_array(results)
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '.wrap' do
56
+ context 'attribute with block' do
57
+ let(:tuples) { [{ key: 'bar' }] }
58
+ let(:results) { [{ items: { key: 'foo_bar' } }] }
59
+ let(:mapper_body) do
60
+ proc do
61
+ wrap :items do
62
+ attribute(:key) { |key| [prefix, key].join('_') }
63
+ end
64
+
65
+ def prefix
66
+ 'foo'
67
+ end
68
+ end
69
+ end
70
+
71
+ it 'creates the attribute from the proc with the mapper as the binding' do
72
+ is_expected.to match_array(results)
73
+ end
74
+ end
75
+ end
76
+
77
+ describe '.unwrap' do
78
+ context 'attribute with block' do
79
+ let(:tuples) { [{ items: { key: 'bar' } }] }
80
+ let(:results) { [{ key: 'foo_bar' }] }
81
+ let(:mapper_body) do
82
+ proc do
83
+ unwrap :items do
84
+ attribute(:key) { |key| [prefix, key].join('_') }
85
+ end
86
+
87
+ def prefix
88
+ 'foo'
89
+ end
90
+ end
91
+ end
92
+
93
+ it 'creates the attribute from the proc with the mapper as the binding' do
94
+ is_expected.to match_array(results)
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe ROM::Mapper::ModelDSL do
4
+ describe '#model' do
5
+ it 'calls the builder with non-excluded attributes only' do
6
+ definition_class = Class.new do
7
+ include ROM::Mapper::ModelDSL
8
+
9
+ def initialize
10
+ @attributes = [[:name], [:title, { exclude: true }]]
11
+ @builder = ->(attrs) { Struct.new(*attrs) }
12
+ end
13
+ end
14
+ model_instance = definition_class.new.model.new
15
+ expect(model_instance).to respond_to(:name)
16
+ expect(model_instance).to_not respond_to(:title)
17
+ end
18
+ end
19
+ end
@@ -2,8 +2,9 @@ require 'spec_helper'
2
2
  require 'virtus'
3
3
 
4
4
  describe ROM::Processor::Transproc do
5
- subject(:transproc) { ROM::Processor::Transproc.build(header) }
5
+ subject(:transproc) { ROM::Processor::Transproc.build(binding, header) }
6
6
 
7
+ let(:binding) { nil }
7
8
  let(:header) { ROM::Header.coerce(attributes, options) }
8
9
  let(:options) { {} }
9
10
 
@@ -67,6 +68,29 @@ describe ROM::Processor::Transproc do
67
68
  end
68
69
  end
69
70
 
71
+ describe 'key from exsisting keys' do
72
+ let(:attributes) do
73
+ coercer = ->(a,b) { b + a }
74
+ [[:c, {from: [:a, :b], coercer: coercer} ]]
75
+ end
76
+
77
+ let(:relation) do
78
+ [
79
+ {a: 'works', b: 'this'}
80
+ ]
81
+ end
82
+
83
+ let (:expected_result) do
84
+ [
85
+ {c: 'thisworks'}
86
+ ]
87
+ end
88
+
89
+ it 'returns tuples a new key added based on exsiting keys' do
90
+ expect(transproc[relation]).to eql(expected_result)
91
+ end
92
+ end
93
+
70
94
  describe 'rejecting keys' do
71
95
  let(:options) { { reject_keys: true } }
72
96
 
metadata CHANGED
@@ -1,69 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rom-mapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-10 00:00:00.000000000 Z
11
+ date: 2015-11-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: transproc
14
+ name: dry-equalizer
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.3'
19
+ version: '0.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.3'
27
- - !ruby/object:Gem::Dependency
28
- name: equalizer
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '0.0'
34
- - - ">="
35
- - !ruby/object:Gem::Version
36
- version: 0.0.10
37
- type: :runtime
38
- prerelease: false
39
- version_requirements: !ruby/object:Gem::Requirement
40
- requirements:
41
- - - "~>"
42
- - !ruby/object:Gem::Version
43
- version: '0.0'
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- version: 0.0.10
26
+ version: '0.2'
47
27
  - !ruby/object:Gem::Dependency
48
28
  name: rom-support
49
29
  requirement: !ruby/object:Gem::Requirement
50
30
  requirements:
51
31
  - - "~>"
52
32
  - !ruby/object:Gem::Version
53
- version: '0.1'
54
- - - ">="
55
- - !ruby/object:Gem::Version
56
- version: 0.1.0
33
+ version: 1.0.0.beta1
57
34
  type: :runtime
58
35
  prerelease: false
59
36
  version_requirements: !ruby/object:Gem::Requirement
60
37
  requirements:
61
38
  - - "~>"
62
39
  - !ruby/object:Gem::Version
63
- version: '0.1'
64
- - - ">="
65
- - !ruby/object:Gem::Version
66
- version: 0.1.0
40
+ version: 1.0.0.beta1
67
41
  - !ruby/object:Gem::Dependency
68
42
  name: rake
69
43
  requirement: !ruby/object:Gem::Requirement
@@ -114,7 +88,6 @@ files:
114
88
  - lib/rom/mapper.rb
115
89
  - lib/rom/mapper/attribute_dsl.rb
116
90
  - lib/rom/mapper/dsl.rb
117
- - lib/rom/mapper/header.rb
118
91
  - lib/rom/mapper/model_dsl.rb
119
92
  - lib/rom/mapper/version.rb
120
93
  - lib/rom/model_builder.rb
@@ -124,10 +97,12 @@ files:
124
97
  - rakelib/mutant.rake
125
98
  - rakelib/rubocop.rake
126
99
  - rom-mapper.gemspec
100
+ - spec/integration/mapper_spec.rb
127
101
  - spec/spec_helper.rb
128
102
  - spec/support/constant_leak_finder.rb
129
103
  - spec/support/mutant.rb
130
104
  - spec/unit/rom/mapper/dsl_spec.rb
105
+ - spec/unit/rom/mapper/model_dsl_spec.rb
131
106
  - spec/unit/rom/mapper_spec.rb
132
107
  - spec/unit/rom/processor/transproc_spec.rb
133
108
  homepage: http://rom-rb.org
@@ -145,9 +120,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
145
120
  version: '0'
146
121
  required_rubygems_version: !ruby/object:Gem::Requirement
147
122
  requirements:
148
- - - ">="
123
+ - - ">"
149
124
  - !ruby/object:Gem::Version
150
- version: '0'
125
+ version: 1.3.1
151
126
  requirements: []
152
127
  rubyforge_project:
153
128
  rubygems_version: 2.4.5
@@ -155,3 +130,4 @@ signing_key:
155
130
  specification_version: 4
156
131
  summary: ROM mapper component
157
132
  test_files: []
133
+ has_rdoc:
@@ -1,85 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module ROM
4
- class Mapper
5
-
6
- # Mapper header wrapping axiom header and providing mapping information
7
- #
8
- # @private
9
- class Header
10
- include Enumerable, Concord.new(:header, :attributes), Adamantium
11
-
12
- # Build a header
13
- #
14
- # @api private
15
- def self.build(input, options = {})
16
- return input if input.is_a?(self)
17
-
18
- keys = options.fetch(:keys, [])
19
- header = Axiom::Relation::Header.coerce(input, keys: keys)
20
-
21
- mapping = options.fetch(:map, {})
22
- attributes = header.each_with_object({}) { |field, object|
23
- attribute = Attribute.coerce(field, mapping[field.name])
24
- object[attribute.name] = attribute
25
- }
26
-
27
- new(header, attributes)
28
- end
29
-
30
- # Return attribute mapping
31
- #
32
- # @api private
33
- def mapping
34
- each_with_object({}) { |attribute, hash|
35
- hash.update attribute.mapping
36
- }
37
- end
38
- memoize :mapping
39
-
40
- # Return all key attributes
41
- #
42
- # @return [Array<Attribute>]
43
- #
44
- # @api public
45
- def keys
46
- # FIXME: find a way to simplify this
47
- header.keys.flat_map { |key_header|
48
- key_header.flat_map { |key|
49
- attributes.values.select { |attribute|
50
- attribute.tuple_key == key.name
51
- }
52
- }
53
- }
54
- end
55
- memoize :keys
56
-
57
- # Return attribute with the given name
58
- #
59
- # @return [Attribute]
60
- #
61
- # @api public
62
- def [](name)
63
- attributes.fetch(name)
64
- end
65
-
66
- # Return attribute names
67
- #
68
- # @api private
69
- def attribute_names
70
- map(&:name)
71
- end
72
-
73
- # Iterate over attributes
74
- #
75
- # @api private
76
- def each(&block)
77
- return to_enum unless block_given?
78
- attributes.each_value(&block)
79
- self
80
- end
81
-
82
- end # Header
83
-
84
- end # Mapper
85
- end # ROM