Skip to content

Commit 6abbc4e

Browse files
authored
Improve gateway setup (#638)
In summary: - Separate loading adapters from loading gateways - Simplify gateway handling - Simplify configuring gateways - Add Gateway#name - Add Gateway#config (which is *the config* that was used to create a gateway instance) - Move config stuff from gateways environment to Configuration - Move loading of gateways to Setup - Stop memoizing plugins in components - Turn Environment into a standard registry with gateways - Move Configuration#relation_classes to rom/compat
1 parent d8587d0 commit 6abbc4e

File tree

17 files changed

+445
-216
lines changed

17 files changed

+445
-216
lines changed

lib/rom/compat.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,24 @@
55
module ROM
66
class Configuration
77
def_delegators :@setup, :auto_registration
8+
def_delegators :@gateways, :gateways_map
9+
10+
alias_method :environment, :gateways
11+
12+
# @api private
13+
def relation_classes(gateway = nil)
14+
classes = setup.components.relations.map(&:constant)
15+
16+
return classes unless gateway
17+
18+
gw_name = gateway.is_a?(Symbol) ? gateway : gateways_map[gateway]
19+
classes.select { |rel| rel.gateway == gw_name }
20+
end
21+
22+
# @api private
23+
# @deprecated
24+
def gateways_map
25+
@gateways_map ||= gateways.to_a.map(&:reverse).to_h
26+
end
827
end
928
end

lib/rom/components/core.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,12 @@ def apply_plugins
8080
end
8181

8282
# @api public
83-
memoize def plugins
83+
def plugins
8484
configuration.plugins.select { |plugin| plugin.type == self.class.id }
8585
end
8686

8787
# @api public
88-
memoize def plugin_options
88+
def plugin_options
8989
plugins.map(&:config).map(&:to_hash).reduce(:merge) || EMPTY_HASH
9090
end
9191

lib/rom/configuration.rb

Lines changed: 72 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
require "forwardable"
44

55
require "rom/support/notifications"
6-
require "rom/environment"
76
require "rom/setup"
87
require "rom/configuration_dsl"
8+
require "rom/support/configurable"
99
require "rom/support/inflector"
10-
require "rom/relation_registry"
1110

1211
module ROM
1312
class Configuration
@@ -23,68 +22,75 @@ class Configuration
2322
register_event("configuration.commands.class.before_build")
2423

2524
include ROM::ConfigurationDSL
25+
include Configurable
2626

2727
NoDefaultAdapterError = Class.new(StandardError)
2828

29-
# @!attribute [r] environment
30-
# @return [Environment] Environment object with gateways
31-
attr_reader :environment
32-
3329
# @!attribute [r] setup
34-
# @return [Setup] Setup object which collects component classes and plugins
30+
# @return [Setup] Setup object which manages component and plugins
3531
attr_reader :setup
3632

3733
# @!attribute [r] notifications
3834
# @return [Notifications] Notification bus instance
3935
attr_reader :notifications
4036

41-
# @!attribute [r] cache
42-
# @return [Notifications] Cache
43-
attr_reader :cache
44-
45-
# @!attribute [r] relations
46-
# @return [ROM::RelationRegistry] relations
47-
attr_reader :relations
48-
49-
def_delegators :@setup, :register_relation, :register_command,
50-
:register_mapper, :register_plugin, :auto_register,
51-
:inflector, :inflector=, :components, :plugins
52-
53-
def_delegators :@environment, :gateways, :gateways_map, :configure, :config
37+
def_delegators :@setup, :cache, :relations, :gateways,
38+
:register_relation, :register_command, :register_mapper,
39+
:register_plugin, :auto_register, :inflector, :inflector=,
40+
:components, :plugins
5441

5542
# Initialize a new configuration
5643
#
57-
# @see Environment#initialize
58-
#
5944
# @return [Configuration]
6045
#
6146
# @api private
6247
def initialize(*args, &block)
63-
@environment = Environment.new(*args)
64-
@setup = Setup.new
6548
@notifications = Notifications.event_bus(:configuration)
66-
@cache = Cache.new
6749

68-
@relations = RelationRegistry.build
50+
config.gateways = Config.new
51+
@setup = Setup.new(config: config.gateways)
6952

70-
block&.call(self)
53+
configure(*args, &block)
7154
end
7255

73-
# @api private
74-
def finalize
75-
setup.finalize
56+
# @api public
57+
def configure(*args)
58+
unless args.empty?
59+
gateways_config = args.first.is_a?(Hash) ? args.first : {default: args}
60+
61+
gateways_config.each do |name, value|
62+
args = Array(value)
63+
64+
adapter, *rest = args
65+
66+
if rest.size > 1 && rest.last.is_a?(Hash)
67+
load_config(config.gateways[name], {adapter: adapter, args: rest[0..-1], **rest.last})
68+
else
69+
options = rest.first.is_a?(Hash) ? rest.first : {args: rest.flatten(1)}
70+
load_config(config.gateways[name], {adapter: adapter, **options})
71+
end
72+
end
73+
end
74+
75+
# Load adapters explicitly here to ensure their plugins are present already
76+
# while setup loads components and then triggers finalization
77+
setup.load_adapters
78+
79+
yield(self) if block_given?
80+
81+
# No more changes allowed
82+
config.freeze
83+
84+
# Load gateways after yielding config because gateways *need finalized config*
85+
setup.load_gateways
86+
7687
self
7788
end
7889

7990
# @api private
80-
def command_compiler
81-
@command_compiler ||= CommandCompiler.new(
82-
gateways,
83-
relations,
84-
Registry.new,
85-
notifications,
86-
inflector: inflector
87-
)
91+
def finalize
92+
setup.finalize
93+
self
8894
end
8995

9096
# Apply a plugin to the configuration
@@ -96,10 +102,9 @@ def command_compiler
96102
#
97103
# @api public
98104
def use(plugin, options = {})
99-
if plugin.is_a?(Array)
100-
plugin.each { |p| use(p) }
101-
elsif plugin.is_a?(Hash)
102-
plugin.to_a.each { |p| use(*p) }
105+
case plugin
106+
when Array then plugin.each { |p| use(p) }
107+
when Hash then plugin.to_a.each { |p| use(*p) }
103108
else
104109
ROM.plugin_registry[:configuration].fetch(plugin).apply_to(self, options)
105110
end
@@ -116,16 +121,14 @@ def [](name)
116121
gateways.fetch(name)
117122
end
118123

119-
# Hook for respond_to? used internally
120-
#
121124
# @api private
122-
def respond_to?(name, include_all = false)
123-
gateways.key?(name) || super
125+
def default_gateway
126+
@default_gateway ||= gateways[:default] if gateways.key?(:default)
124127
end
125128

126129
# @api private
127-
def default_gateway
128-
@default_gateway ||= gateways[:default]
130+
def default_adapter
131+
@default_adapter ||= adapter_for_gateway(default_gateway) || ROM.adapters.keys.first
129132
end
130133

131134
# @api private
@@ -136,22 +139,34 @@ def adapter_for_gateway(gateway)
136139
end
137140

138141
# @api private
139-
def relation_classes(gateway = nil)
140-
classes = setup.components.relations.map(&:constant)
141-
142-
return classes unless gateway
143-
144-
gw_name = gateway.is_a?(Symbol) ? gateway : gateways_map[gateway]
145-
classes.select { |rel| rel.gateway == gw_name }
142+
def command_compiler
143+
@command_compiler ||= CommandCompiler.new(
144+
gateways,
145+
relations,
146+
Registry.new,
147+
notifications,
148+
inflector: inflector
149+
)
146150
end
147151

148152
# @api private
149-
def default_adapter
150-
@default_adapter ||= adapter_for_gateway(default_gateway) || ROM.adapters.keys.first
153+
def respond_to_missing?(name, include_all = false)
154+
gateways.key?(name) || super
151155
end
152156

153157
private
154158

159+
# @api private
160+
def load_config(config, hash)
161+
hash.each do |key, value|
162+
if value.is_a?(Hash)
163+
load_config(config[key], value)
164+
else
165+
config.send("#{key}=", value)
166+
end
167+
end
168+
end
169+
155170
# Returns gateway if method is a name of a registered gateway
156171
#
157172
# @return [Gateway]

lib/rom/constants.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ def initialize(adapter, component)
2020
end
2121

2222
EnvAlreadyFinalizedError = Class.new(StandardError)
23+
GatewayAlreadyDefinedError = Class.new(StandardError)
2324
RelationAlreadyDefinedError = Class.new(StandardError)
2425
CommandAlreadyDefinedError = Class.new(StandardError)
2526
MapperAlreadyDefinedError = Class.new(StandardError)

lib/rom/environment.rb

Lines changed: 0 additions & 75 deletions
This file was deleted.

0 commit comments

Comments
 (0)