rom-mapper 0.2.0 → 0.3.0.beta1

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