rom 0.8.1 → 0.9.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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +5 -1
  4. data/lib/rom.rb +35 -16
  5. data/lib/rom/command.rb +1 -9
  6. data/lib/rom/commands/graph/class_interface.rb +2 -2
  7. data/lib/rom/constants.rb +0 -6
  8. data/lib/rom/{env.rb → container.rb} +3 -3
  9. data/lib/rom/environment.rb +238 -0
  10. data/lib/rom/environment_plugin.rb +17 -0
  11. data/lib/rom/environment_plugins/auto_registration.rb +17 -0
  12. data/lib/rom/global.rb +0 -203
  13. data/lib/rom/mapper_registry.rb +2 -0
  14. data/lib/rom/pipeline.rb +2 -0
  15. data/lib/rom/plugin.rb +4 -18
  16. data/lib/rom/plugin_base.rb +31 -0
  17. data/lib/rom/plugin_registry.rb +54 -17
  18. data/lib/rom/relation.rb +54 -11
  19. data/lib/rom/relation/class_interface.rb +14 -21
  20. data/lib/rom/relation/curried.rb +36 -2
  21. data/lib/rom/relation/graph.rb +7 -0
  22. data/lib/rom/relation_registry.rb +4 -0
  23. data/lib/rom/setup.rb +9 -8
  24. data/lib/rom/setup/finalize.rb +5 -5
  25. data/lib/rom/version.rb +1 -1
  26. data/rom.gemspec +2 -0
  27. data/spec/integration/commands/create_spec.rb +1 -1
  28. data/spec/integration/commands/update_spec.rb +1 -1
  29. data/spec/integration/mappers/unwrap_spec.rb +1 -1
  30. data/spec/spec_helper.rb +2 -0
  31. data/spec/unit/rom/{env_spec.rb → container_spec.rb} +5 -5
  32. data/spec/unit/rom/plugin_spec.rb +0 -8
  33. data/spec/unit/rom/relation/composite_spec.rb +2 -2
  34. data/spec/unit/rom/relation/curried_spec.rb +53 -0
  35. data/spec/unit/rom/relation/graph_spec.rb +4 -0
  36. data/spec/unit/rom/relation/lazy/combine_spec.rb +6 -6
  37. data/spec/unit/rom/relation/lazy_spec.rb +4 -8
  38. data/spec/unit/rom/relation_spec.rb +0 -14
  39. data/spec/unit/rom/setup_spec.rb +1 -1
  40. metadata +52 -35
  41. data/lib/rom/header.rb +0 -193
  42. data/lib/rom/header/attribute.rb +0 -184
  43. data/lib/rom/mapper.rb +0 -103
  44. data/lib/rom/mapper/attribute_dsl.rb +0 -477
  45. data/lib/rom/mapper/dsl.rb +0 -119
  46. data/lib/rom/mapper/model_dsl.rb +0 -55
  47. data/lib/rom/model_builder.rb +0 -101
  48. data/lib/rom/processor.rb +0 -28
  49. data/lib/rom/processor/transproc.rb +0 -388
  50. data/lib/rom/relation/lazy.rb +0 -145
  51. data/lib/rom/support/array_dataset.rb +0 -41
  52. data/lib/rom/support/class_builder.rb +0 -44
  53. data/lib/rom/support/class_macros.rb +0 -56
  54. data/lib/rom/support/data_proxy.rb +0 -102
  55. data/lib/rom/support/deprecations.rb +0 -36
  56. data/lib/rom/support/enumerable_dataset.rb +0 -65
  57. data/lib/rom/support/inflector.rb +0 -73
  58. data/lib/rom/support/options.rb +0 -195
  59. data/lib/rom/support/registry.rb +0 -43
  60. data/spec/unit/rom/header_spec.rb +0 -102
  61. data/spec/unit/rom/mapper/dsl_spec.rb +0 -467
  62. data/spec/unit/rom/mapper_spec.rb +0 -84
  63. data/spec/unit/rom/model_builder_spec.rb +0 -46
  64. data/spec/unit/rom/processor/transproc_spec.rb +0 -448
  65. data/spec/unit/rom/support/array_dataset_spec.rb +0 -61
  66. data/spec/unit/rom/support/class_builder_spec.rb +0 -42
  67. data/spec/unit/rom/support/enumerable_dataset_spec.rb +0 -17
  68. data/spec/unit/rom/support/inflector_spec.rb +0 -89
  69. data/spec/unit/rom/support/options_spec.rb +0 -119
@@ -0,0 +1,17 @@
1
+ module ROM
2
+ module EnvironmentPlugins
3
+ # Automatically registers relations, mappers and commands as they are defined
4
+ #
5
+ # For now this plugin is always enabled
6
+ #
7
+ # @api public
8
+ module AutoRegistration
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) }
14
+ end
15
+ end
16
+ end
17
+ end
data/lib/rom/global.rb CHANGED
@@ -1,7 +1,4 @@
1
- require 'rom/setup'
2
- require 'rom/repository'
3
1
  require 'rom/plugin_registry'
4
-
5
2
  require 'rom/global/plugin_dsl'
6
3
 
7
4
  module ROM
@@ -16,7 +13,6 @@ module ROM
16
13
  super
17
14
 
18
15
  rom.instance_variable_set('@adapters', {})
19
- rom.instance_variable_set('@gateways', {})
20
16
  rom.instance_variable_set('@plugin_registry', PluginRegistry.new)
21
17
  end
22
18
 
@@ -27,13 +23,6 @@ module ROM
27
23
  # @api private
28
24
  attr_reader :adapters
29
25
 
30
- # An internal gateway => identifier map used by the setup
31
- #
32
- # @return [Hash]
33
- #
34
- # @api private
35
- attr_reader :gateways
36
-
37
26
  # An internal identifier => plugin map used by the setup
38
27
  #
39
28
  # @return [Hash]
@@ -41,137 +30,6 @@ module ROM
41
30
  # @api private
42
31
  attr_reader :plugin_registry
43
32
 
44
- # Setup object created during env setup phase
45
- #
46
- # This gets set to nil after setup is finalized
47
- #
48
- # @return [Setup]
49
- #
50
- # @api private
51
- attr_reader :boot
52
-
53
- # Return global default ROM environment configured by the setup
54
- #
55
- # @return [Env]
56
- #
57
- # @api public
58
- attr_reader :env
59
-
60
- # Starts the setup process for relations, mappers and commands.
61
- #
62
- # @overload setup(type, *args)
63
- # Sets up a single-gateway environment given a gateway type provided
64
- # under the ROM umbrella. For custom gateways, create an instance and
65
- # pass it directly.
66
- #
67
- # @param [Symbol] type
68
- # @param [Array] *args
69
- #
70
- # @overload setup(gateway)
71
- # @param [Gateway] gateway
72
- #
73
- # @overload setup(gateways)
74
- # Sets up multiple gateways.
75
- #
76
- # @param [Hash{Symbol=>Symbol,Array}] gateways
77
- #
78
- # @return [Setup] boot object
79
- #
80
- # @example
81
- # # Use the in-memory adapter shipped with ROM as the default gateway.
82
- # env = ROM.setup(:memory, 'memory://test')
83
- # # Use `rom-sql` with an in-memory sqlite database as default gateway.
84
- # ROM.setup(:sql, 'sqlite::memory')
85
- # # Registers a `default` and a `warehouse` gateway.
86
- # env = ROM.setup(
87
- # default: [:sql, 'sqlite::memory'],
88
- # warehouse: [:sql, 'postgres://localhost/warehouse']
89
- # )
90
- #
91
- # @example A full environment
92
- #
93
- # ROM.setup(:memory, 'memory://test')
94
- #
95
- # ROM.relation(:users) do
96
- # # ...
97
- # end
98
- #
99
- # ROM.mappers do
100
- # define(:users) do
101
- # # ...
102
- # end
103
- # end
104
- #
105
- # ROM.commands(:users) do
106
- # define(:create) do
107
- # # ...
108
- # end
109
- # end
110
- #
111
- # ROM.finalize # builds the env
112
- # ROM.env # returns the env registry
113
- #
114
- # @api public
115
- def setup(*args, &block)
116
- config = setup_config(*args)
117
- @boot = Setup.new(setup_gateways(config), adapters.keys.first)
118
-
119
- if block
120
- @boot.instance_exec(&block)
121
- @boot.finalize
122
- else
123
- @boot
124
- end
125
- end
126
-
127
- # Global relation setup DSL
128
- #
129
- # @example
130
- # ROM.setup(:memory)
131
- #
132
- # ROM.relation(:users) do
133
- # def by_name(name)
134
- # restrict(name: name)
135
- # end
136
- # end
137
- #
138
- # @api public
139
- def relation(*args, &block)
140
- boot.relation(*args, &block)
141
- end
142
-
143
- # Global commands setup DSL
144
- #
145
- # @example
146
- # ROM.setup(:memory)
147
- #
148
- # ROM.commands(:users) do
149
- # define(:create) do
150
- # # ..
151
- # end
152
- # end
153
- #
154
- # @api public
155
- def commands(*args, &block)
156
- boot.commands(*args, &block)
157
- end
158
-
159
- # Global mapper setup DSL
160
- #
161
- # @example
162
- # ROM.setup(:memory)
163
- #
164
- # ROM.mappers do
165
- # define(:uses) do
166
- # # ..
167
- # end
168
- # end
169
- #
170
- # @api public
171
- def mappers(*args, &block)
172
- boot.mappers(*args, &block)
173
- end
174
-
175
33
  # Global plugin setup DSL
176
34
  #
177
35
  # @example
@@ -184,24 +42,6 @@ module ROM
184
42
  PluginDSL.new(plugin_registry, *args, &block)
185
43
  end
186
44
 
187
- # Finalize the setup and store default global env under ROM.env
188
- #
189
- # @example
190
- # ROM.setup(:memory)
191
- # ROM.finalize # => ROM
192
- # ROM.boot # => nil
193
- # ROM.env # => the env
194
- #
195
- # @return [ROM]
196
- #
197
- # @api public
198
- def finalize
199
- @env = boot.finalize
200
- self
201
- ensure
202
- @boot = nil
203
- end
204
-
205
45
  # Register adapter namespace under a specified identifier
206
46
  #
207
47
  # @param [Symbol] identifier
@@ -214,48 +54,5 @@ module ROM
214
54
  adapters[identifier] = adapter
215
55
  self
216
56
  end
217
-
218
- # Relation subclass registration during setup phase
219
- #
220
- # @api private
221
- def register_relation(klass)
222
- boot.register_relation(klass) if boot
223
- end
224
-
225
- # Mapper subclass registration during setup phase
226
- #
227
- # @api private
228
- def register_mapper(klass)
229
- boot.register_mapper(klass) if boot
230
- end
231
-
232
- # Command subclass registration during setup phase
233
- #
234
- # @api private
235
- def register_command(klass)
236
- boot.register_command(klass) if boot
237
- end
238
-
239
- private
240
-
241
- # Helper method to handle single- or multi-repo setup options
242
- #
243
- # @api private
244
- def setup_config(*args)
245
- args.first.is_a?(Hash) ? args.first : { default: args }
246
- end
247
-
248
- # Build gateways using the setup interface
249
- #
250
- # @api private
251
- def setup_gateways(config)
252
- config.each_with_object({}) do |(name, spec), hash|
253
- identifier, *args = Array(spec)
254
- gateway = Gateway.setup(identifier, *(args.flatten))
255
- hash[name] = gateway
256
-
257
- gateways[gateway] = identifier unless identifier.is_a?(Gateway)
258
- end
259
- end
260
57
  end
261
58
  end
@@ -1,3 +1,5 @@
1
+ require 'rom/support/registry'
2
+
1
3
  module ROM
2
4
  # @private
3
5
  class MapperRegistry < Registry
data/lib/rom/pipeline.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'equalizer'
2
+
1
3
  module ROM
2
4
  # Data pipeline common interface
3
5
  #
data/lib/rom/plugin.rb CHANGED
@@ -1,27 +1,13 @@
1
+ require 'rom/plugin_base'
2
+
1
3
  module ROM
2
4
  # Plugin is a simple object used to store plugin configurations
3
5
  #
4
6
  # @private
5
- class Plugin
6
- # @return [Module] a module representing the plugin
7
- #
8
- # @api private
9
- attr_reader :mod
10
-
11
- # @return [Hash] configuration options
12
- #
13
- # @api private
14
- attr_reader :options
15
-
16
- # @api private
17
- def initialize(mod, options)
18
- @mod = mod
19
- @options = options
20
- end
21
-
7
+ class Plugin < PluginBase
22
8
  # Apply this plugin to the provided class
23
9
  #
24
- # @param klass [Class]
10
+ # @param [Class] klass
25
11
  #
26
12
  # @api private
27
13
  def apply_to(klass)
@@ -0,0 +1,31 @@
1
+ module ROM
2
+ # Abstract plugin base
3
+ #
4
+ # @private
5
+ class PluginBase
6
+ # @return [Module] a module representing the plugin
7
+ #
8
+ # @api private
9
+ attr_reader :mod
10
+
11
+ # @return [Hash] configuration options
12
+ #
13
+ # @api private
14
+ attr_reader :options
15
+
16
+ # @api private
17
+ def initialize(mod, options)
18
+ @mod = mod
19
+ @options = options
20
+ end
21
+
22
+ # Apply this plugin to the provided class
23
+ #
24
+ # @param [Mixed] base
25
+ #
26
+ # @api private
27
+ def apply_to(base)
28
+ raise NotImplementedError, "#{self.class}#apply_to not implemented"
29
+ end
30
+ end
31
+ end
@@ -5,6 +5,12 @@ module ROM
5
5
  #
6
6
  # @api private
7
7
  class PluginRegistry
8
+ # Internal registry for environment plugins
9
+ #
10
+ # @return [EnvironmentPluginRegistry]
11
+ #
12
+ # @api private
13
+ attr_reader :environment
8
14
  # Internal registry for command plugins
9
15
  #
10
16
  # @return [InternalPluginRegistry]
@@ -28,6 +34,7 @@ module ROM
28
34
 
29
35
  # @api private
30
36
  def initialize
37
+ @environment = EnvironmentPluginRegistry.new
31
38
  @mappers = InternalPluginRegistry.new
32
39
  @commands = InternalPluginRegistry.new
33
40
  @relations = InternalPluginRegistry.new
@@ -46,7 +53,7 @@ module ROM
46
53
  type = options.fetch(:type)
47
54
  adapter = options.fetch(:adapter, :default)
48
55
 
49
- plugins_for(type, adapter)[name] = Plugin.new(mod, options)
56
+ plugins_for(type, adapter).register(name, mod, options)
50
57
  end
51
58
 
52
59
  private
@@ -56,27 +63,17 @@ module ROM
56
63
  # @api private
57
64
  def plugins_for(type, adapter)
58
65
  case type
59
- when :command then commands.adapter(adapter)
60
- when :mapper then mappers.adapter(adapter)
61
- when :relation then relations.adapter(adapter)
66
+ when :environment then environment
67
+ when :command then commands.adapter(adapter)
68
+ when :mapper then mappers.adapter(adapter)
69
+ when :relation then relations.adapter(adapter)
62
70
  end
63
71
  end
64
72
  end
65
-
66
- # A registry storing specific plugins
73
+ # Abstract registry defining common behaviour
67
74
  #
68
75
  # @api private
69
- class AdapterPluginRegistry < Registry
70
- # Assign a plugin to this adapter registry
71
- #
72
- # @param [Symbol] name The registered plugin name
73
- # @param [Plugin] plugin The plugin to register
74
- #
75
- # @api private
76
- def []=(name, plugin)
77
- elements[name] = plugin
78
- end
79
-
76
+ class PluginRegistryBase < Registry
80
77
  # Retrieve a registered plugin
81
78
  #
82
79
  # @param [Symbol] name The plugin to retrieve
@@ -88,6 +85,46 @@ module ROM
88
85
  elements[name]
89
86
  end
90
87
  end
88
+ # A registry storing environment specific plugins
89
+ #
90
+ # @api private
91
+ class EnvironmentPluginRegistry < PluginRegistryBase
92
+ # Assign a plugin to this environment registry
93
+ #
94
+ # @param [Symbol] name The registered plugin name
95
+ # @param [Module] mod The plugin to register
96
+ # @param [Hash] options optional configuration data
97
+ #
98
+ # @api private
99
+ def register(name, mod, options)
100
+ elements[name] = EnvironmentPlugin.new(mod, options)
101
+ end
102
+ # Return an environment plugin
103
+ #
104
+ # @param [Symbol] name The name of the environment plugin
105
+ #
106
+ # @raises [UnknownPluginError] if no plugin is found with the given name
107
+ #
108
+ # @api public
109
+ def fetch(name)
110
+ self[name] || raise(UnknownPluginError, name)
111
+ end
112
+ end
113
+ # A registry storing adapter specific plugins
114
+ #
115
+ # @api private
116
+ class AdapterPluginRegistry < PluginRegistryBase
117
+ # Assign a plugin to this adapter registry
118
+ #
119
+ # @param [Symbol] name The registered plugin name
120
+ # @param [Module] mod The plugin to register
121
+ # @param [Hash] options optional configuration data
122
+ #
123
+ # @api private
124
+ def register(name, mod, options)
125
+ elements[name] = Plugin.new(mod, options)
126
+ end
127
+ end
91
128
 
92
129
  # Store a set of registries grouped by adapter
93
130
  #
data/lib/rom/relation.rb CHANGED
@@ -1,7 +1,14 @@
1
+ require 'rom/support/deprecations'
1
2
  require 'rom/relation/class_interface'
2
3
 
3
- require 'rom/relation/lazy'
4
+ require 'rom/pipeline'
5
+ require 'rom/mapper_registry'
6
+
7
+ require 'rom/relation/loaded'
4
8
  require 'rom/relation/curried'
9
+ require 'rom/relation/composite'
10
+ require 'rom/relation/graph'
11
+ require 'rom/relation/materializable'
5
12
 
6
13
  module ROM
7
14
  # Base relation class
@@ -12,17 +19,23 @@ module ROM
12
19
  # however, is considered private and should not be used outside of the
13
20
  # relation instance.
14
21
  #
15
- # ROM builds sub-classes of this class for every relation defined in the env
16
- # for easy inspection and extensibility - every gateway can provide extensions
17
- # for those sub-classes but there is always a vanilla relation instance stored
18
- # in the schema registry.
22
+ # ROM builds sub-classes of this class for every relation defined in the
23
+ # environment for easy inspection and extensibility - every gateway can
24
+ # provide extensions for those sub-classes but there is always a vanilla
25
+ # relation instance stored in the schema registry.
19
26
  #
20
27
  # @api public
21
28
  class Relation
29
+ extend Deprecations
22
30
  extend ClassInterface
31
+ extend ROM::Support::GuardedInheritanceHook
23
32
 
24
33
  include Options
25
34
  include Equalizer.new(:dataset)
35
+ include Materializable
36
+ include Pipeline
37
+
38
+ option :mappers, reader: true, default: proc { MapperRegistry.new }
26
39
 
27
40
  # Dataset used by the relation
28
41
  #
@@ -49,6 +62,26 @@ module ROM
49
62
  dataset.each { |tuple| yield(tuple) }
50
63
  end
51
64
 
65
+ # Eager load other relation(s) for this relation
66
+ #
67
+ # @param [Array<Relation>] others The other relation(s) to eager load
68
+ #
69
+ # @return [Relation::Graph]
70
+ #
71
+ # @api public
72
+ def combine(*others)
73
+ Graph.build(self, others)
74
+ end
75
+
76
+ # Load relation
77
+ #
78
+ # @return [Relation::Loaded]
79
+ #
80
+ # @api public
81
+ def call
82
+ Loaded.new(self)
83
+ end
84
+
52
85
  # Materialize a relation into an array
53
86
  #
54
87
  # @return [Array<Hash>]
@@ -58,15 +91,25 @@ module ROM
58
91
  to_enum.to_a
59
92
  end
60
93
 
61
- # Turn relation into a lazy-loadable and composable relation
94
+ # Return if this relation is curried
62
95
  #
63
- # @see Lazy
64
- #
65
- # @return [Lazy]
96
+ # @return [false]
66
97
  #
98
+ # @api private
99
+ def curried?
100
+ false
101
+ end
102
+
103
+ # @api private
104
+ def with(options)
105
+ __new__(dataset, options)
106
+ end
107
+ deprecate :to_lazy, :with, "to_lazy is no longer needed"
108
+
67
109
  # @api public
68
- def to_lazy(*args)
69
- Lazy.new(self, *args)
110
+ def relation
111
+ Deprecations.announce("#relation", 'all relations are now lazy')
112
+ self
70
113
  end
71
114
 
72
115
  private