rom 0.9.0.rc1 → 0.9.0

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: 68b700901edb358688ae8f41a8f474cab6dc1254
4
- data.tar.gz: 97d2569ad4ad0b653e725b0598fe6edb0d6d70b8
3
+ metadata.gz: e37b5bfee7aba0349fc7072c15a936d86b5d64da
4
+ data.tar.gz: 960446e1976fcfbe3d13d7bafb25a83ce7912626
5
5
  SHA512:
6
- metadata.gz: 5627b18505dd2e30d7eca6b6514b84f6f81573cd99a44eb7fb67b15966e37fccc007df8b3d3016b8a65a4363321d10e056e5e93c255c0ef13704693592345c5c
7
- data.tar.gz: 46dd954fd398b22e3a5a5af01215ff9f52ab51ee9b750de68d7a5c9510a4275f29fb9e04914d03cb52e026653cf3c0754fa88aad10fb4feebd8ae28d138ea122
6
+ metadata.gz: 9c251e5659fb72fc73cfca473a1667d4da46a4ca58ed68f31eb2b74f275139ca86ffdf49c93f2b87a194420baa5911655e26927e5d923239ead79ca2bc910cda
7
+ data.tar.gz: 6c35bbee777498703f1a386ea4ce2f91d96b0860c7a664800ffe05f58ba1ce18199279f088f9ae3dac2b3b0ce6d11fc6aa718d10afbb7db01192b08500012674
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ## v0.9.0 to-be-released
1
+ ## v0.9.0 2015-08-19
2
2
 
3
3
  ### Added
4
4
 
@@ -24,8 +24,11 @@
24
24
  * Adapter-specific interface is properly included in relation descendants (solnic)
25
25
  * Combined commands (aka command graph) properly rejects keys from nested input
26
26
  prior sending the input to individual commands (solnic)
27
+ * Composite relation materializes correctly when another composite on the right
28
+ side became materialized (ie piping relation through a composite relation will
29
+ work correctly) (solnic)
27
30
 
28
- [Compare v0.8.1...HEAD](https://github.com/rom-rb/rom/compare/v0.8.1...HEAD)
31
+ [Compare v0.8.1...v0.9.0](https://github.com/rom-rb/rom/compare/v0.8.1...v0.9.0)
29
32
 
30
33
  ## v0.8.1 2015-07-12
31
34
 
data/lib/rom/command.rb CHANGED
@@ -60,7 +60,7 @@ module ROM
60
60
  # @return [Command]
61
61
  #
62
62
  # @api public
63
- def self.build(relation, options = {})
63
+ def self.build(relation, options = EMPTY_HASH)
64
64
  new(relation, self.options.merge(options))
65
65
  end
66
66
 
@@ -78,7 +78,7 @@ module ROM
78
78
  # @option options [Symbol] :adapter (:default) first adapter to check for plugin
79
79
  #
80
80
  # @api public
81
- def self.use(plugin, _options = {})
81
+ def self.use(plugin, _options = EMPTY_HASH)
82
82
  ROM.plugin_registry.commands.fetch(plugin, adapter).apply_to(self)
83
83
  end
84
84
 
@@ -19,7 +19,7 @@ module ROM
19
19
  option :mapper, reader: true
20
20
 
21
21
  # @api private
22
- def initialize(elements, options = {})
22
+ def initialize(elements, options = EMPTY_HASH)
23
23
  super
24
24
  @registry =
25
25
  if elements.is_a?(Registry)
@@ -35,7 +35,7 @@ module ROM
35
35
  'Source relation is now available as `Command#source`'
36
36
 
37
37
  # @api private
38
- def initialize(relation, options = {})
38
+ def initialize(relation, options = EMPTY_HASH)
39
39
  super
40
40
  @relation = relation
41
41
  @source = options[:source] || relation
@@ -26,7 +26,7 @@ module ROM
26
26
  option :mappers, reader: true, default: proc { MapperRegistry.new }
27
27
 
28
28
  # @api private
29
- def initialize(root, nodes, options = {})
29
+ def initialize(root, nodes, options = EMPTY_HASH)
30
30
  super
31
31
  @root = root
32
32
  @nodes = nodes
@@ -45,11 +45,14 @@ module ROM
45
45
  ROM.plugin_registry
46
46
  end
47
47
 
48
- # Apply
48
+ # Apply a plugin to the environment
49
+ #
50
+ # @param [Mixed] The plugin identifier, usually a Symbol
51
+ # @param [Hash] Plugin options
49
52
  #
50
53
  # @api public
51
- def use(plugin)
52
- plugin_registry.environment.fetch(plugin).apply_to(self)
54
+ def use(plugin, options = {})
55
+ plugin_registry.environment.fetch(plugin).apply_to(self, options)
53
56
  end
54
57
 
55
58
  # Starts the setup process for relations, mappers and commands.
@@ -10,8 +10,8 @@ module ROM
10
10
  # @param [ROM::Environment] environment
11
11
  #
12
12
  # @api private
13
- def apply_to(environment)
14
- mod.apply(environment)
13
+ def apply_to(environment, options = {})
14
+ mod.apply(environment, options)
15
15
  end
16
16
  end
17
17
  end
@@ -7,10 +7,20 @@ module ROM
7
7
  # @api public
8
8
  module AutoRegistration
9
9
  # @api private
10
- def self.apply(environment)
11
- ROM::Relation.on(:inherited) { |relation| environment.register_relation(relation) }
12
- ROM::Command.on(:inherited) { |command| environment.register_command(command) }
13
- ROM::Mapper.on(:inherited) { |mapper| environment.register_mapper(mapper) }
10
+ def self.apply(environment, options = {})
11
+ if_proc = options.fetch(:if, ->(*args) { true })
12
+
13
+ ROM::Relation.on(:inherited) do |relation|
14
+ environment.register_relation(relation) if if_proc.call(relation)
15
+ end
16
+
17
+ ROM::Command.on(:inherited) do |command|
18
+ environment.register_command(command) if if_proc.call(command)
19
+ end
20
+
21
+ ROM::Mapper.on(:inherited) do |mapper|
22
+ environment.register_mapper(mapper) if if_proc.call(mapper)
23
+ end
14
24
  end
15
25
  end
16
26
  end
@@ -19,7 +19,7 @@ module ROM
19
19
  attr_reader :registry
20
20
 
21
21
  # @api private
22
- def initialize(registry, defaults = {}, &block)
22
+ def initialize(registry, defaults = EMPTY_HASH, &block)
23
23
  @registry = registry
24
24
  @defaults = defaults
25
25
  instance_exec(&block)
@@ -32,7 +32,7 @@ module ROM
32
32
  # @param [Hash] options
33
33
  #
34
34
  # @api public
35
- def register(name, mod, options = {})
35
+ def register(name, mod, options = EMPTY_HASH)
36
36
  registry.register(name, mod, defaults.merge(options))
37
37
  end
38
38
 
@@ -49,7 +49,7 @@ module ROM
49
49
  # relation or mapper)
50
50
  # @option options [Symbol] :adapter (:default) which adapter this plugin
51
51
  # applies to. Leave blank for all adapters
52
- def register(name, mod, options = {})
52
+ def register(name, mod, options = EMPTY_HASH)
53
53
  type = options.fetch(:type)
54
54
  adapter = options.fetch(:adapter, :default)
55
55
 
data/lib/rom/relation.rb CHANGED
@@ -19,7 +19,7 @@ module ROM
19
19
  # however, is considered private and should not be used outside of the
20
20
  # relation instance.
21
21
  #
22
- # ROM builds sub-classes of this class for every relation defined in the
22
+ # ROM builds sub-classes of this class for every relation defined in the
23
23
  # environment for easy inspection and extensibility - every gateway can
24
24
  # provide extensions for those sub-classes but there is always a vanilla
25
25
  # relation instance stored in the schema registry.
@@ -47,7 +47,7 @@ module ROM
47
47
  attr_reader :dataset
48
48
 
49
49
  # @api private
50
- def initialize(dataset, options = {})
50
+ def initialize(dataset, options = EMPTY_HASH)
51
51
  @dataset = dataset
52
52
  super
53
53
  end
@@ -115,7 +115,7 @@ module ROM
115
115
  private
116
116
 
117
117
  # @api private
118
- def __new__(dataset, new_opts = {})
118
+ def __new__(dataset, new_opts = EMPTY_HASH)
119
119
  self.class.new(dataset, options.merge(new_opts))
120
120
  end
121
121
  end
@@ -72,7 +72,7 @@ module ROM
72
72
  end
73
73
 
74
74
  # @api private
75
- def initialize(dataset, options = {})
75
+ def initialize(dataset, options = EMPTY_HASH)
76
76
  @name = self.class.dataset
77
77
  super
78
78
  end
@@ -131,7 +131,7 @@ module ROM
131
131
  # @option options [Symbol] :adapter (:default) first adapter to check for plugin
132
132
  #
133
133
  # @api public
134
- def use(plugin, _options = {})
134
+ def use(plugin, _options = EMPTY_HASH)
135
135
  ROM.plugin_registry.relations.fetch(plugin, adapter).apply_to(self)
136
136
  end
137
137
 
@@ -21,7 +21,9 @@ module ROM
21
21
  relation = left.call(*args)
22
22
  response = right.call(relation)
23
23
 
24
- if relation.is_a?(Loaded)
24
+ if response.is_a?(Loaded)
25
+ response
26
+ elsif relation.is_a?(Loaded)
25
27
  relation.new(response)
26
28
  else
27
29
  Loaded.new(relation, response)
@@ -1,4 +1,6 @@
1
1
  require 'rom/support/options'
2
+
3
+ require 'rom/pipeline'
2
4
  require 'rom/relation/materializable'
3
5
 
4
6
  module ROM
@@ -6,6 +8,7 @@ module ROM
6
8
  class Curried
7
9
  include Options
8
10
  include Materializable
11
+ include Pipeline
9
12
 
10
13
  option :name, type: Symbol, reader: true
11
14
  option :arity, type: Integer, reader: true, default: -1
@@ -14,7 +17,7 @@ module ROM
14
17
  attr_reader :relation
15
18
 
16
19
  # @api private
17
- def initialize(relation, options = {})
20
+ def initialize(relation, options = EMPTY_HASH)
18
21
  @relation = relation
19
22
  super
20
23
  end
@@ -67,7 +70,7 @@ module ROM
67
70
  private
68
71
 
69
72
  # @api private
70
- def __new__(relation, new_opts = {})
73
+ def __new__(relation, new_opts = EMPTY_HASH)
71
74
  Curried.new(relation, options.merge(new_opts))
72
75
  end
73
76
 
@@ -8,7 +8,7 @@ module ROM
8
8
  # This is used by Setup#commands DSL and its `define` block
9
9
  #
10
10
  # @api private
11
- def self.build_class(name, relation, options = {}, &block)
11
+ def self.build_class(name, relation, options = EMPTY_HASH, &block)
12
12
  type = options.fetch(:type) { name }
13
13
  command_type = Inflector.classify(type)
14
14
  adapter = options.fetch(:adapter)
@@ -24,7 +24,7 @@ module ROM
24
24
  # @return [Class] generated class
25
25
  #
26
26
  # @api public
27
- def define(name, options = {}, &block)
27
+ def define(name, options = EMPTY_HASH, &block)
28
28
  Command.build_class(
29
29
  name, relation, { adapter: adapter }.merge(options), &block
30
30
  )
@@ -8,7 +8,7 @@ module ROM
8
8
  # This is used by Setup#mappers DSL
9
9
  #
10
10
  # @api private
11
- def self.build_class(name, options = {}, &block)
11
+ def self.build_class(name, options = EMPTY_HASH, &block)
12
12
  class_name = "ROM::Mapper[#{name}]"
13
13
 
14
14
  parent = options[:parent]
@@ -22,7 +22,7 @@ module ROM
22
22
  # @return [Class]
23
23
  #
24
24
  # @api public
25
- def define(name, options = {}, &block)
25
+ def define(name, options = EMPTY_HASH, &block)
26
26
  Mapper.build_class(name, options, &block)
27
27
  self
28
28
  end
@@ -8,7 +8,7 @@ module ROM
8
8
  # This is used by Setup#relation DSL
9
9
  #
10
10
  # @api private
11
- def self.build_class(name, options = {})
11
+ def self.build_class(name, options = EMPTY_HASH)
12
12
  class_name = "ROM::Relation[#{Inflector.camelize(name)}]"
13
13
  adapter = options.fetch(:adapter)
14
14
 
@@ -19,7 +19,7 @@ module ROM
19
19
  # end
20
20
  #
21
21
  # @api public
22
- def relation(name, options = {}, &block)
22
+ def relation(name, options = EMPTY_HASH, &block)
23
23
  klass_opts = { adapter: default_adapter }.merge(options)
24
24
  klass = Relation.build_class(name, klass_opts)
25
25
  klass.class_eval(&block) if block
data/lib/rom/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ROM
2
- VERSION = '0.9.0.rc1'.freeze
2
+ VERSION = '0.9.0'.freeze
3
3
  end
@@ -0,0 +1,177 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Setting up ROM with multiple environments' do
4
+ let(:environment) do
5
+ {
6
+ one: ROM::Environment.new,
7
+ two: ROM::Environment.new
8
+ }
9
+ end
10
+ let(:setup) do
11
+ {
12
+ one: environment[:one].setup(:memory),
13
+ two: environment[:two].setup(:memory)
14
+ }
15
+ end
16
+ let(:container) do
17
+ {
18
+ one: setup[:one].finalize,
19
+ two: setup[:two].finalize
20
+ }
21
+ end
22
+
23
+ before { setup }
24
+
25
+ context 'without :auto_registration plugin' do
26
+ before do
27
+ module Test
28
+ class Users < ROM::Relation[:memory]
29
+ dataset :users
30
+ end
31
+
32
+ class CreateUser < ROM::Commands::Create[:memory]
33
+ register_as :create
34
+ relation :users
35
+ result :one
36
+ end
37
+
38
+ class UserMapper < ROM::Mapper
39
+ relation :users
40
+ register_as :entity
41
+ end
42
+ end
43
+ end
44
+
45
+ it 'registers items independently of other environments' do
46
+ environment[:one].register_relation(Test::Users)
47
+ environment[:one].register_command(Test::CreateUser)
48
+ environment[:one].register_mapper(Test::UserMapper)
49
+
50
+ expect(container[:one].relations[:users]).to be_kind_of Test::Users
51
+ expect(container[:one].commands[:users].create).to be_kind_of Test::CreateUser
52
+ expect(container[:one].mappers[:users].entity).to be_kind_of Test::UserMapper
53
+
54
+ expect { container[:two].relations[:users] }.to raise_error(
55
+ ROM::Registry::ElementNotFoundError
56
+ )
57
+ expect { container[:two].commands[:users].create }.to raise_error(
58
+ ROM::Registry::ElementNotFoundError
59
+ )
60
+ expect { container[:two].commands[:users].create }.to raise_error(
61
+ ROM::Registry::ElementNotFoundError
62
+ )
63
+ end
64
+
65
+ it 'allows use of the same identifiers in different environments' do
66
+ environment[:one].register_relation(Test::Users)
67
+ environment[:one].register_command(Test::CreateUser)
68
+ environment[:one].register_mapper(Test::UserMapper)
69
+
70
+ expect { environment[:two].register_relation(Test::Users) }.to_not raise_error
71
+ expect { environment[:two].register_command(Test::CreateUser) }.to_not raise_error
72
+ expect { environment[:two].register_mapper(Test::UserMapper) }.to_not raise_error
73
+ end
74
+ end
75
+
76
+ context 'with :auto_registration plugin' do
77
+ context 'without if option' do
78
+ before do
79
+ environment[:one].use :auto_registration
80
+
81
+ module Test
82
+ class Users < ROM::Relation[:memory]
83
+ dataset :users
84
+ end
85
+
86
+ class CreateUser < ROM::Commands::Create[:memory]
87
+ register_as :create
88
+ relation :users
89
+ result :one
90
+ end
91
+
92
+ class UserMapper < ROM::Mapper
93
+ relation :users
94
+ register_as :entity
95
+ end
96
+ end
97
+ end
98
+
99
+ it 'registers all classes that are defined with the given environment' do
100
+ expect(container[:one].relations[:users]).to be_kind_of Test::Users
101
+ expect(container[:one].commands[:users].create).to be_kind_of Test::CreateUser
102
+ expect(container[:one].mappers[:users].entity).to be_kind_of Test::UserMapper
103
+ end
104
+
105
+ it 'works independently of other environments' do
106
+ expect { container[:two].relations[:users] }.to raise_error(
107
+ ROM::Registry::ElementNotFoundError
108
+ )
109
+ expect { container[:two].commands[:users].create }.to raise_error(
110
+ ROM::Registry::ElementNotFoundError
111
+ )
112
+ expect { container[:two].commands[:users].create }.to raise_error(
113
+ ROM::Registry::ElementNotFoundError
114
+ )
115
+ end
116
+ end
117
+
118
+ context 'with if option' do
119
+ before do
120
+ environment[:one].use :auto_registration, if: ->(item) do
121
+ item.to_s[/(.*)(?=::)/] == 'Test'
122
+ end
123
+
124
+ environment[:two].use :auto_registration, if: ->(item) do
125
+ item.to_s[/(.*)(?=::)/] == 'Test::API'
126
+ end
127
+
128
+ module Test
129
+ class Users < ROM::Relation[:memory]
130
+ dataset :users
131
+ end
132
+
133
+ class CreateUser < ROM::Commands::Create[:memory]
134
+ register_as :create
135
+ relation :users
136
+ result :one
137
+ end
138
+
139
+ class UserMapper < ROM::Mapper
140
+ relation :users
141
+ register_as :entity
142
+ end
143
+
144
+ module API
145
+ class Users < ROM::Relation[:memory]
146
+ dataset :users
147
+ end
148
+
149
+ class CreateUser < ROM::Commands::Create[:memory]
150
+ register_as :create
151
+ relation :users
152
+ result :one
153
+ end
154
+
155
+ class UserMapper < ROM::Mapper
156
+ relation :users
157
+ register_as :entity
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ it 'registers all classes that are defined where proc returns true' do
164
+ expect(container[:one].relations[:users]).to be_kind_of Test::Users
165
+ expect(container[:one].commands[:users].create).to be_kind_of Test::CreateUser
166
+ expect(container[:one].mappers[:users].entity).to be_kind_of Test::UserMapper
167
+ expect(container[:two].relations[:users]).to be_kind_of Test::API::Users
168
+ expect(container[:two].commands[:users].create).to be_kind_of(
169
+ Test::API::CreateUser
170
+ )
171
+ expect(container[:two].mappers[:users].entity).to be_kind_of(
172
+ Test::API::UserMapper
173
+ )
174
+ end
175
+ end
176
+ end
177
+ end
@@ -6,18 +6,20 @@ describe "ROM::PluginRegistry" do
6
6
  let(:setup) { ROM.setup(:memory) }
7
7
 
8
8
  before do
9
- Test::CommandPlugin = Module.new
10
- Test::MapperPlugin = Module.new
11
- Test::RelationPlugin = Module.new do
9
+ Test::EnvironmentPlugin = Module.new
10
+ Test::CommandPlugin = Module.new
11
+ Test::MapperPlugin = Module.new
12
+ Test::RelationPlugin = Module.new do
12
13
  def plugged_in
13
14
  "a relation"
14
15
  end
15
16
  end
16
17
 
17
18
  ROM.plugins do
18
- register :publisher, Test::CommandPlugin, type: :command
19
- register :pager, Test::RelationPlugin, type: :relation
20
- register :translater, Test::MapperPlugin, type: :mapper
19
+ register :registration, Test::EnvironmentPlugin, type: :environment
20
+ register :publisher, Test::CommandPlugin, type: :command
21
+ register :pager, Test::RelationPlugin, type: :relation
22
+ register :translater, Test::MapperPlugin, type: :mapper
21
23
  end
22
24
  end
23
25
 
@@ -27,6 +29,10 @@ describe "ROM::PluginRegistry" do
27
29
  ROM.instance_variable_set('@plugin_registry', orig_plugins)
28
30
  end
29
31
 
32
+ it "makes environment plugins available" do
33
+ expect(ROM.plugin_registry.environment[:registration].mod).to eq Test::EnvironmentPlugin
34
+ end
35
+
30
36
  it "includes relation plugins" do
31
37
  setup.relation(:users) do
32
38
  use :pager
@@ -4,6 +4,7 @@ describe ROM::Relation::Composite do
4
4
  include_context 'users and tasks'
5
5
 
6
6
  let(:users) { rom.relation(:users) }
7
+ let(:tasks) { rom.relation(:tasks) }
7
8
 
8
9
  let(:name_list) { proc { |r| r.map { |t| t[:name] } } }
9
10
  let(:upcaser) { proc { |r| r.map(&:upcase) } }
@@ -15,7 +16,13 @@ describe ROM::Relation::Composite do
15
16
  end
16
17
 
17
18
  def sorted(other)
18
- other.sort_by { |t| t[:name] }
19
+ other.source.order(:name)
20
+ end
21
+ end
22
+
23
+ setup.relation(:tasks) do
24
+ def for_users(users)
25
+ restrict(name: users.map { |u| u[:name] })
19
26
  end
20
27
  end
21
28
  end
@@ -26,6 +33,7 @@ describe ROM::Relation::Composite do
26
33
  loaded = relation.call
27
34
 
28
35
  expect(loaded.source).to eql(users)
36
+
29
37
  expect(loaded).to match_array(%w(JANE JOE))
30
38
  end
31
39
 
@@ -33,12 +41,26 @@ describe ROM::Relation::Composite do
33
41
  relation = users >> users.sorted
34
42
  loaded = relation.call
35
43
 
36
- expect(loaded.source).to eql(users)
44
+ expect(loaded.source).to eql(users.sorted(users.call))
45
+
37
46
  expect(loaded).to match_array([
38
47
  { name: 'Jane', email: 'jane@doe.org' },
39
48
  { name: 'Joe', email: 'joe@doe.org' }
40
49
  ])
41
50
  end
51
+
52
+ it 'sends a relation through another composite relation' do
53
+ task_mapper = -> tasks { tasks }
54
+ relation = users.by_name('Jane') >> (tasks.for_users >> task_mapper)
55
+
56
+ loaded = relation.call
57
+
58
+ expect(loaded.source).to eql(tasks.for_users(users.by_name('Jane')))
59
+
60
+ expect(loaded).to match_array([
61
+ { name: 'Jane', title: 'be cool', priority: 2 }
62
+ ])
63
+ end
42
64
  end
43
65
 
44
66
  describe '#each' do
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.9.0.rc1
4
+ version: 0.9.0
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-14 00:00:00.000000000 Z
11
+ date: 2015-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: transproc
@@ -224,6 +224,7 @@ files:
224
224
  - spec/integration/mappers/ungroup_spec.rb
225
225
  - spec/integration/mappers/unwrap_spec.rb
226
226
  - spec/integration/mappers/wrap_spec.rb
227
+ - spec/integration/multi_env_spec.rb
227
228
  - spec/integration/multi_repo_spec.rb
228
229
  - spec/integration/relations/inheritance_spec.rb
229
230
  - spec/integration/relations/reading_spec.rb
@@ -283,9 +284,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
283
284
  version: '0'
284
285
  required_rubygems_version: !ruby/object:Gem::Requirement
285
286
  requirements:
286
- - - ">"
287
+ - - ">="
287
288
  - !ruby/object:Gem::Version
288
- version: 1.3.1
289
+ version: '0'
289
290
  requirements: []
290
291
  rubyforge_project:
291
292
  rubygems_version: 2.4.5