rom 0.9.0.rc1 → 0.9.0

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