rom 0.7.0 → 0.7.1

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: 9513b27090115add08f6f4f4d8e446b7e805d0d8
4
- data.tar.gz: 4a33b39b54ee48c1d551138688e864a3b6052970
3
+ metadata.gz: fef04bd27871ee67a85b39c0cfb4a2a9c588a01f
4
+ data.tar.gz: 6f5e0515a4cdd8d0df9816c574bf176aa9634783
5
5
  SHA512:
6
- metadata.gz: 17c5de3ec96c11fcf6d95fd06c89ef1f76af66f6468bdbb139a421f5a7125ae1aae228021303b778e8150abf4a3650753ec164eb4aa393997e3a44cd42bbfcaf
7
- data.tar.gz: 5ded7613f606353f66371b9bc537c6a24c30f72e58d8a741f24133e976fa2d898609ca56bd4bf41a993827b3bda3f937b69dbc1f9c7ce9b432439ddfad0a1786
6
+ metadata.gz: 9ea6324c33c9c7701ab5452f291d7c397e41062ea706c2345c66d167b9cad8e7914f39af536fa065cb76e3bdca612898bc89de9e0fa6d46a1e58a4c532b88576
7
+ data.tar.gz: 9954ad8c0413dc7e94d4170703b47dd3a80387a22236c37a86d71ce7b6a01b8588658673a0cd10224013cf7b166c6592f800585f5c2fa4ecc691825701d3dcb0
data/.rubocop.yml CHANGED
@@ -6,10 +6,6 @@ AllCops:
6
6
  Exclude:
7
7
  - tmp/**/*
8
8
 
9
- # It’s quite readable when we know what we are doing
10
- Lint/AssignmentInCondition:
11
- Enabled: false
12
-
13
9
  Style/BlockDelimiters:
14
10
  EnforcedStyle: semantic
15
11
  FunctionalMethods:
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## v0.7.1 2015-05-22
2
+
3
+ ### Added
4
+
5
+ * Support for passing a block for custom coercion to `attribute` (gotar)
6
+ * `fold` mapping operation which groups keys from input tuples to array
7
+ of values from the first of listed keys (nepalez)
8
+ * Adapter `Relation` and command classes can specify `adapter` identifier
9
+ which allows using adapter-specific plugins w/o the need to specify adapter
10
+ when calling `use` (solnic)
11
+
12
+ ### Changed
13
+
14
+ * [rom/memory] `restrict` operation supports array as a value (gotar)
15
+ * [rom/memory] `restrict` operation supports regexp as a value (gotar)
16
+
17
+ [Compare v0.7.0...HEAD](https://github.com/rom-rb/rom/compare/v0.7.0...HEAD)
18
+
1
19
  ## v0.7.0 2015-05-17
2
20
 
3
21
  ### Added
data/lib/rom/command.rb CHANGED
@@ -9,7 +9,7 @@ module ROM
9
9
 
10
10
  include Equalizer.new(:relation, :options)
11
11
 
12
- defines :relation, :result, :input, :validator, :register_as
12
+ defines :adapter, :relation, :result, :input, :validator, :register_as
13
13
 
14
14
  input Hash
15
15
  validator proc {}
@@ -85,7 +85,6 @@ module ROM
85
85
  #
86
86
  # @api public
87
87
  def self.use(plugin, options = {})
88
- adapter = options.fetch(:adapter, :default)
89
88
  ROM.plugin_registry.commands.fetch(plugin, adapter).apply_to(self)
90
89
  end
91
90
 
@@ -47,6 +47,8 @@ module ROM
47
47
  Unwrap
48
48
  elsif type.equal?(:hash)
49
49
  meta[:wrap] ? Wrap : Hash
50
+ elsif meta[:fold]
51
+ Group
50
52
  elsif type.equal?(:array)
51
53
  meta[:group] ? Group : Array
52
54
  else
@@ -30,17 +30,22 @@ module ROM
30
30
  @reject_keys = options.fetch(:reject_keys)
31
31
  end
32
32
 
33
- # Define a mapping attribute with its options
33
+ # Define a mapping attribute with its options and/or block
34
34
  #
35
35
  # @example
36
36
  # dsl = AttributeDSL.new([])
37
37
  #
38
38
  # dsl.attribute(:name)
39
39
  # dsl.attribute(:email, from: 'user_email')
40
+ # dsl.attribute(:name) { 'John' }
41
+ # dsl.attribute(:name) { |t| t.upcase }
40
42
  #
41
43
  # @api public
42
- def attribute(name, options = EMPTY_HASH)
44
+ def attribute(name, options = EMPTY_HASH, &block)
43
45
  with_attr_options(name, options) do |attr_options|
46
+ raise ArgumentError,
47
+ "can't specify type and block at the same time" if options[:type] && block
48
+ attr_options[:coercer] = block if block
44
49
  add_attribute(name, attr_options)
45
50
  end
46
51
  end
@@ -166,6 +171,26 @@ module ROM
166
171
  end
167
172
  end
168
173
 
174
+ # Define an embedded hash attribute that requires "fold" transformation
175
+ #
176
+ # Typically this is used in sql context to fold single joined field
177
+ # to the array of values.
178
+ #
179
+ # @example
180
+ # dsl = AttributeDSL.new([])
181
+ #
182
+ # dsl.fold(tags: [:name])
183
+ #
184
+ # @see AttributeDSL#embedded
185
+ #
186
+ # @api public
187
+ def fold(*args)
188
+ with_name_or_options(*args) do |name, *|
189
+ fold_options = { type: :array, fold: true }
190
+ dsl(name, fold_options)
191
+ end
192
+ end
193
+
169
194
  # Define an embedded combined attribute that requires "combine" transformation
170
195
  #
171
196
  # Typically this can be used to process results of eager-loading
@@ -192,7 +217,7 @@ module ROM
192
217
  type: options.fetch(:type, :array),
193
218
  keys: options.fetch(:on),
194
219
  combine: true,
195
- header: dsl.header,
220
+ header: dsl.header
196
221
  }
197
222
 
198
223
  add_attribute(name, attr_opts)
@@ -260,7 +285,7 @@ module ROM
260
285
  dsl = new(options, &block)
261
286
  header = dsl.header
262
287
  add_attribute(name, options.update(header: header))
263
- header.each { |attr| exclude(attr.key) }
288
+ header.each { |attr| exclude(attr.key) unless name == attr.key }
264
289
  end
265
290
 
266
291
  # Define attributes from the `name => attributes` hash syntax
@@ -272,7 +297,7 @@ module ROM
272
297
  hash.each do |name, header|
273
298
  with_attr_options(name, options) do |attr_options|
274
299
  add_attribute(name, attr_options.update(header: header.zip))
275
- header.each { |attr| exclude(attr) }
300
+ header.each { |attr| exclude(attr) unless name == attr }
276
301
  end
277
302
  end
278
303
  end
@@ -10,6 +10,8 @@ module ROM
10
10
  #
11
11
  # @api public
12
12
  class Create < ROM::Commands::Create
13
+ adapter :memory
14
+
13
15
  # @see ROM::Commands::Create#execute
14
16
  def execute(tuple)
15
17
  attributes = input[tuple]
@@ -22,6 +24,8 @@ module ROM
22
24
  #
23
25
  # @api public
24
26
  class Update < ROM::Commands::Update
27
+ adapter :memory
28
+
25
29
  # @see ROM::Commands::Update#execute
26
30
  def execute(params)
27
31
  attributes = input[params]
@@ -34,6 +38,8 @@ module ROM
34
38
  #
35
39
  # @api public
36
40
  class Delete < ROM::Commands::Delete
41
+ adapter :memory
42
+
37
43
  # @see ROM::Commands::Delete#execute
38
44
  def execute
39
45
  tuples = target.to_a
@@ -30,10 +30,15 @@ module ROM
30
30
  #
31
31
  # @api public
32
32
  def restrict(criteria = nil)
33
- if criteria
34
- find_all { |tuple| criteria.all? { |k, v| tuple[k].eql?(v) } }
35
- else
36
- find_all { |tuple| yield(tuple) }
33
+ return find_all { |tuple| yield(tuple) } unless criteria
34
+ find_all do |tuple|
35
+ criteria.all? do |k, v|
36
+ case v
37
+ when Array then v.include?(tuple[k])
38
+ when Regexp then tuple[k].match(v)
39
+ else tuple[k].eql?(v)
40
+ end
41
+ end
37
42
  end
38
43
  end
39
44
 
@@ -10,6 +10,8 @@ module ROM
10
10
  class Relation < ROM::Relation
11
11
  include Enumerable
12
12
 
13
+ adapter :memory
14
+
13
15
  forward :take, :join, :project, :restrict, :order
14
16
 
15
17
  # Insert tuples into the relation
@@ -129,6 +129,6 @@ module ROM
129
129
  raise(UnknownPluginError, name)
130
130
  end
131
131
 
132
- alias [] fetch
132
+ alias_method :[], :fetch
133
133
  end
134
134
  end
@@ -91,13 +91,18 @@ module ROM
91
91
 
92
92
  # Visit plain attribute
93
93
  #
94
+ # It will call block transformation if it's used
95
+ #
94
96
  # If it's a typed attribute a coercion transformation is added
95
97
  #
96
98
  # @param [Header::Attribute] attribute
97
99
  #
98
100
  # @api private
99
101
  def visit_attribute(attribute)
100
- if attribute.typed?
102
+ coercer = attribute.meta[:coercer]
103
+ if coercer
104
+ t(:map_value, attribute.name, coercer)
105
+ elsif attribute.typed?
101
106
  t(:map_value, attribute.name, t(:"to_#{attribute.type}"))
102
107
  end
103
108
  end
@@ -189,6 +194,7 @@ module ROM
189
194
  name = attribute.name
190
195
  header = attribute.header
191
196
  keys = attribute.tuple_keys
197
+ fold = attribute.meta[:fold]
192
198
 
193
199
  other = header.groups
194
200
 
@@ -196,9 +202,13 @@ module ROM
196
202
  ops << t(:group, name, keys)
197
203
  ops << t(:map_array, t(:map_value, name, FILTER_EMPTY))
198
204
 
199
- ops << other.map { |attr|
200
- t(:map_array, t(:map_value, name, visit_group(attr, true)))
201
- }
205
+ if fold
206
+ ops << t(:map_array, t(:fold, name, keys.first))
207
+ else
208
+ ops << other.map { |attr|
209
+ t(:map_array, t(:map_value, name, visit_group(attr, true)))
210
+ }
211
+ end
202
212
  end
203
213
  else
204
214
  visit_array(attribute)
@@ -12,11 +12,12 @@ module ROM
12
12
  def inherited(klass)
13
13
  super
14
14
 
15
+ klass.extend ClassMacros
16
+ klass.defines :adapter
17
+
15
18
  return if klass.superclass == ROM::Relation
16
19
 
17
20
  klass.class_eval do
18
- extend ClassMacros
19
-
20
21
  use :registry_reader
21
22
 
22
23
  defines :repository, :dataset, :register_as, :exposed_relations
@@ -128,7 +129,6 @@ module ROM
128
129
  #
129
130
  # @api public
130
131
  def use(plugin, options = {})
131
- adapter = options.fetch(:adapter, :default)
132
132
  ROM.plugin_registry.relations.fetch(plugin, adapter).apply_to(self)
133
133
  end
134
134
 
@@ -6,8 +6,9 @@ module ROM
6
6
  define_method(old_name) do |*args, &block|
7
7
  warn <<-MSG.gsub(/^\s+/, '')
8
8
  #{self.class}##{old_name} is deprecated and will be removed in 1.0.0.
9
- Please use #{self.class}##{new_name} instead."
9
+ Please use #{self.class}##{new_name} instead.
10
10
  #{msg}
11
+ #{caller.detect { |l| !l.include?('lib/rom')}}
11
12
  MSG
12
13
  __send__(new_name, *args, &block)
13
14
  end
data/lib/rom/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ROM
2
- VERSION = '0.7.0'.freeze
2
+ VERSION = '0.7.1'.freeze
3
3
  end
data/rom.gemspec CHANGED
@@ -15,7 +15,7 @@ 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_runtime_dependency 'transproc', '~> 0.2', '>= 0.2.1'
18
+ gem.add_runtime_dependency 'transproc', '~> 0.2', '>= 0.2.2'
19
19
  gem.add_runtime_dependency 'equalizer', '~> 0.0', '>= 0.0.9'
20
20
 
21
21
  gem.add_development_dependency 'rake', '~> 10.3'
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Mapper definition DSL' do
4
+ include_context 'users and tasks'
5
+
6
+ let(:header) { mapper.header }
7
+
8
+ describe 'folded relation mapper' do
9
+ before do
10
+ setup.relation(:tasks) do
11
+ def with_users
12
+ join(users)
13
+ end
14
+ end
15
+
16
+ setup.relation(:users) do
17
+ def with_tasks
18
+ join(tasks)
19
+ end
20
+ end
21
+ end
22
+
23
+ let(:rom) { setup.finalize }
24
+ let(:actual) do
25
+ rom.relation(:users).with_tasks.map_with(:users).to_a
26
+ end
27
+
28
+ it 'groups all attributes and folds the first key' do
29
+ setup.mappers do
30
+ define(:users) do
31
+ fold tasks: [:title, :priority]
32
+ end
33
+ end
34
+
35
+ expect(actual).to eql [
36
+ { name: 'Joe', email: 'joe@doe.org', tasks: ['be nice', 'sleep well'] },
37
+ { name: 'Jane', email: 'jane@doe.org', tasks: ['be cool'] }
38
+ ]
39
+ end
40
+
41
+ it 'is sensitive to the order of keys' do
42
+ setup.mappers do
43
+ define(:users) do
44
+ fold priorities: [:priority, :title]
45
+ end
46
+ end
47
+
48
+ expect(actual).to eql [
49
+ { name: 'Joe', email: 'joe@doe.org', priorities: [1, 2] },
50
+ { name: 'Jane', email: 'jane@doe.org', priorities: [2] }
51
+ ]
52
+ end
53
+ end
54
+ end
@@ -158,5 +158,27 @@ describe 'Mapper definition DSL' do
158
158
  ])
159
159
  )
160
160
  end
161
+
162
+ it 'allows defining grouped attributes with the same name as their keys' do
163
+ setup.mappers do
164
+ define(:with_tasks, parent: :users) do
165
+
166
+ attribute :name
167
+ attribute :email
168
+
169
+ group title: [:title, :priority]
170
+ end
171
+ end
172
+
173
+ rom = setup.finalize
174
+
175
+ jane = rom.relation(:users).with_tasks.map_with(:with_tasks).to_a.last
176
+
177
+ expect(jane).to eql(
178
+ name: 'Jane',
179
+ email: 'jane@doe.org',
180
+ title: [{ title: 'be cool', priority: 2 }]
181
+ )
182
+ end
161
183
  end
162
184
  end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+ require 'rom/memory'
3
+
4
+ describe 'Mappers / Attributes value' do
5
+ let(:setup) { ROM.setup(:memory) }
6
+
7
+ before do
8
+ setup.relation(:users)
9
+ end
10
+
11
+ it 'allows to manipulate attribute value' do
12
+ class Test::UserMapper < ROM::Mapper
13
+ relation :users
14
+
15
+ attribute :id
16
+ attribute :name, from: :first_name do
17
+ 'John'
18
+ end
19
+ attribute :age do
20
+ 9+9
21
+ end
22
+ attribute :weight do |t|
23
+ t+15
24
+ end
25
+ end
26
+
27
+ rom = setup.finalize
28
+
29
+ rom.relations.users << {
30
+ id: 123,
31
+ first_name: 'Jane',
32
+ weight: 75
33
+ }
34
+
35
+ jane = rom.relation(:users).as(:users).first
36
+
37
+ expect(jane).to eql(id: 123, name: 'John', weight: 90, age: 18)
38
+ end
39
+
40
+ it 'raise ArgumentError if type and block used at the same time' do
41
+ expect {
42
+ class Test::UserMapper < ROM::Mapper
43
+ relation :users
44
+
45
+ attribute :name, type: :string do
46
+ 'John'
47
+ end
48
+ end
49
+ }.to raise_error(ArgumentError, "can't specify type and block at the same time")
50
+ end
51
+ end
@@ -2,7 +2,7 @@ module Mutant
2
2
  class Selector
3
3
  # Expression based test selector
4
4
  class Expression < self
5
- def call(subject)
5
+ def call(_subject)
6
6
  integration.all_tests
7
7
  end
8
8
  end # Expression
@@ -49,6 +49,20 @@ describe ROM::Memory::Relation do
49
49
  { name: 'Joe', email: 'joe@doe.org', age: 12 }
50
50
  ])
51
51
  end
52
+
53
+ it 'allows to use array as a value' do
54
+ expect(relation.restrict(age: [10, 11])).to match_array([
55
+ { name: 'Jane', email: 'jane@doe.org', age: 10 },
56
+ { name: 'Jade', email: 'jade@doe.org', age: 11 }
57
+ ])
58
+ end
59
+
60
+ it 'allows to use regexp as a value' do
61
+ expect(relation.restrict(name: /\w{4}/)).to match_array([
62
+ { name: 'Jane', email: 'jane@doe.org', age: 10 },
63
+ { name: 'Jade', email: 'jade@doe.org', age: 11 }
64
+ ])
65
+ end
52
66
  end
53
67
 
54
68
  describe '#order' do
@@ -89,7 +89,7 @@ describe "ROM::PluginRegistry" do
89
89
  end
90
90
 
91
91
  setup.relation(:users) do
92
- use :lazy, adapter: :memory
92
+ use :lazy
93
93
  end
94
94
 
95
95
  expect(env.relation(:users)).to be_lazy
@@ -97,11 +97,16 @@ describe "ROM::PluginRegistry" do
97
97
 
98
98
  it "respects adapter restrictions" do
99
99
  Test::LazyPlugin = Module.new
100
+ Test::LazyMemoryPlugin = Module.new
100
101
  Test::LazySQLPlugin = Module.new
101
102
 
102
103
  ROM.plugins do
103
104
  register :lazy, Test::LazyPlugin, type: :command
104
105
 
106
+ adapter :memory do
107
+ register :lazy_command, Test::LazyMemoryPlugin, type: :command
108
+ end
109
+
105
110
  adapter :sql do
106
111
  register :lazy, Test::LazySQLPlugin, type: :command
107
112
  end
@@ -112,10 +117,17 @@ describe "ROM::PluginRegistry" do
112
117
  Class.new(ROM::Commands::Create[:memory]) do
113
118
  relation :users
114
119
  register_as :create
115
- use :lazy, adapter: :memory
120
+ use :lazy
121
+ end
122
+
123
+ Class.new(ROM::Commands::Update[:memory]) do
124
+ relation :users
125
+ register_as :update
126
+ use :lazy_command
116
127
  end
117
128
 
118
129
  expect(env.command(:users).create).not_to be_kind_of Test::LazySQLPlugin
119
130
  expect(env.command(:users).create).to be_kind_of Test::LazyPlugin
131
+ expect(env.command(:users).update).to be_kind_of Test::LazyMemoryPlugin
120
132
  end
121
133
  end
@@ -23,7 +23,7 @@ describe ROM::Relation::Graph do
23
23
  end
24
24
 
25
25
  setup.relation(:tasks) do
26
- def for_users(users)
26
+ def for_users(_users)
27
27
  self
28
28
  end
29
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rom
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.7.1
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-05-17 00:00:00.000000000 Z
11
+ date: 2015-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: transproc
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '0.2'
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 0.2.1
22
+ version: 0.2.2
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '0.2'
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 0.2.1
32
+ version: 0.2.2
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: equalizer
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -203,7 +203,9 @@ files:
203
203
  - spec/integration/mappers/deep_embedded_spec.rb
204
204
  - spec/integration/mappers/definition_dsl_spec.rb
205
205
  - spec/integration/mappers/embedded_spec.rb
206
+ - spec/integration/mappers/fold_spec.rb
206
207
  - spec/integration/mappers/group_spec.rb
208
+ - spec/integration/mappers/overwrite_attributes_value_spec.rb
207
209
  - spec/integration/mappers/prefixing_attributes_spec.rb
208
210
  - spec/integration/mappers/registering_custom_mappers_spec.rb
209
211
  - spec/integration/mappers/renaming_attributes_spec.rb