dry-system 0.19.2 → 0.23.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 +4 -4
- data/CHANGELOG.md +472 -1
- data/LICENSE +1 -1
- data/README.md +4 -3
- data/dry-system.gemspec +16 -15
- data/lib/dry/system/auto_registrar.rb +1 -13
- data/lib/dry/system/component.rb +104 -47
- data/lib/dry/system/component_dir.rb +88 -47
- data/lib/dry/system/components.rb +8 -4
- data/lib/dry/system/config/component_dir.rb +141 -53
- data/lib/dry/system/config/component_dirs.rb +176 -70
- data/lib/dry/system/config/namespace.rb +76 -0
- data/lib/dry/system/config/namespaces.rb +208 -0
- data/lib/dry/system/constants.rb +2 -2
- data/lib/dry/system/container.rb +279 -201
- data/lib/dry/system/errors.rb +72 -61
- data/lib/dry/system/identifier.rb +99 -79
- data/lib/dry/system/importer.rb +83 -12
- data/lib/dry/system/indirect_component.rb +65 -0
- data/lib/dry/system/loader.rb +8 -4
- data/lib/dry/system/{manual_registrar.rb → manifest_registrar.rb} +12 -13
- data/lib/dry/system/plugins/bootsnap.rb +3 -2
- data/lib/dry/system/plugins/dependency_graph/strategies.rb +37 -1
- data/lib/dry/system/plugins/dependency_graph.rb +26 -20
- data/lib/dry/system/plugins/env.rb +3 -2
- data/lib/dry/system/plugins/logging.rb +9 -5
- data/lib/dry/system/plugins/monitoring.rb +1 -1
- data/lib/dry/system/plugins/notifications.rb +1 -1
- data/lib/dry/system/plugins/zeitwerk/compat_inflector.rb +22 -0
- data/lib/dry/system/plugins/zeitwerk.rb +109 -0
- data/lib/dry/system/plugins.rb +8 -7
- data/lib/dry/system/provider/source.rb +324 -0
- data/lib/dry/system/provider/source_dsl.rb +94 -0
- data/lib/dry/system/provider.rb +264 -24
- data/lib/dry/system/provider_registrar.rb +276 -0
- data/lib/dry/system/provider_source_registry.rb +70 -0
- data/lib/dry/system/provider_sources/settings/config.rb +86 -0
- data/lib/dry/system/provider_sources/settings/loader.rb +53 -0
- data/lib/dry/system/provider_sources/settings.rb +40 -0
- data/lib/dry/system/provider_sources.rb +5 -0
- data/lib/dry/system/stubs.rb +1 -1
- data/lib/dry/system/version.rb +1 -1
- data/lib/dry/system.rb +45 -13
- metadata +25 -22
- data/lib/dry/system/booter/component_registry.rb +0 -35
- data/lib/dry/system/booter.rb +0 -200
- data/lib/dry/system/components/bootable.rb +0 -289
- data/lib/dry/system/components/config.rb +0 -35
- data/lib/dry/system/lifecycle.rb +0 -135
- data/lib/dry/system/provider_registry.rb +0 -27
- data/lib/dry/system/settings/file_loader.rb +0 -30
- data/lib/dry/system/settings/file_parser.rb +0 -51
- data/lib/dry/system/settings.rb +0 -67
- data/lib/dry/system/system_components/settings.rb +0 -11
data/lib/dry/system/container.rb
CHANGED
@@ -5,19 +5,21 @@ require "pathname"
|
|
5
5
|
require "dry-auto_inject"
|
6
6
|
require "dry-configurable"
|
7
7
|
require "dry-container"
|
8
|
-
require "dry/inflector"
|
9
|
-
|
10
8
|
require "dry/core/deprecations"
|
9
|
+
require "dry/inflector"
|
11
10
|
|
12
|
-
require "dry/system"
|
13
|
-
require "dry/system/errors"
|
14
|
-
require "dry/system/booter"
|
15
11
|
require "dry/system/auto_registrar"
|
16
|
-
require "dry/system/manual_registrar"
|
17
|
-
require "dry/system/importer"
|
18
12
|
require "dry/system/component"
|
19
13
|
require "dry/system/constants"
|
14
|
+
require "dry/system/errors"
|
15
|
+
require "dry/system/identifier"
|
16
|
+
require "dry/system/importer"
|
17
|
+
require "dry/system/indirect_component"
|
18
|
+
require "dry/system/manifest_registrar"
|
20
19
|
require "dry/system/plugins"
|
20
|
+
require "dry/system/provider_registrar"
|
21
|
+
require "dry/system/provider"
|
22
|
+
require "dry/system/provider/source"
|
21
23
|
|
22
24
|
require_relative "component_dir"
|
23
25
|
require_relative "config/component_dirs"
|
@@ -48,7 +50,7 @@ module Dry
|
|
48
50
|
#
|
49
51
|
# Every container needs to be configured with following settings:
|
50
52
|
#
|
51
|
-
# * `:name` - a unique container
|
53
|
+
# * `:name` - a unique container name
|
52
54
|
# * `:root` - a system root directory (defaults to `pwd`)
|
53
55
|
#
|
54
56
|
# @example
|
@@ -73,63 +75,98 @@ module Dry
|
|
73
75
|
extend Dry::System::Plugins
|
74
76
|
|
75
77
|
setting :name
|
76
|
-
setting
|
77
|
-
setting :
|
78
|
-
setting :bootable_dirs,
|
79
|
-
setting :registrations_dir, "
|
80
|
-
setting :component_dirs, Config::ComponentDirs.new, cloneable: true
|
81
|
-
setting :
|
82
|
-
setting :
|
83
|
-
setting :auto_registrar, Dry::System::AutoRegistrar
|
84
|
-
setting :
|
85
|
-
setting :
|
86
|
-
setting
|
78
|
+
setting :root, default: Pathname.pwd.freeze, constructor: -> path { Pathname(path) }
|
79
|
+
setting :provider_dirs, default: ["system/providers"]
|
80
|
+
setting :bootable_dirs # Deprecated for provider_dirs, see .provider_paths below
|
81
|
+
setting :registrations_dir, default: "system/registrations"
|
82
|
+
setting :component_dirs, default: Config::ComponentDirs.new, cloneable: true
|
83
|
+
setting :exports, reader: true
|
84
|
+
setting :inflector, default: Dry::Inflector.new
|
85
|
+
setting :auto_registrar, default: Dry::System::AutoRegistrar
|
86
|
+
setting :manifest_registrar, default: Dry::System::ManifestRegistrar
|
87
|
+
setting :provider_registrar, default: Dry::System::ProviderRegistrar
|
88
|
+
setting :importer, default: Dry::System::Importer
|
89
|
+
|
90
|
+
# We presume "." as key namespace separator. This is not intended to be
|
91
|
+
# user-configurable.
|
92
|
+
config.namespace_separator = KEY_SEPARATOR
|
87
93
|
|
88
94
|
class << self
|
89
|
-
def strategies(value = nil)
|
90
|
-
if value
|
91
|
-
@strategies = value
|
92
|
-
else
|
93
|
-
@strategies ||= Dry::AutoInject::Strategies
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
95
|
extend Dry::Core::Deprecations["Dry::System::Container"]
|
98
96
|
|
99
|
-
#
|
97
|
+
# @!method config
|
98
|
+
# Returns the configuration for the container
|
100
99
|
#
|
101
|
-
#
|
100
|
+
# @example
|
101
|
+
# container.config.root = "/path/to/app"
|
102
|
+
# container.config.root # => #<Pathname:/path/to/app>
|
102
103
|
#
|
103
|
-
#
|
104
|
-
|
105
|
-
|
106
|
-
# TODO: dry-configurable needs a public API for this
|
107
|
-
config._settings << _settings[name]
|
108
|
-
self
|
109
|
-
end
|
110
|
-
ruby2_keywords(:setting) if respond_to?(:ruby2_keywords, true)
|
104
|
+
# @return [Dry::Configurable::Config]
|
105
|
+
#
|
106
|
+
# @api public
|
111
107
|
|
112
|
-
#
|
108
|
+
# Yields a configuration object for the container, which you can use to modify the
|
109
|
+
# configuration, then runs the after-`configured` hooks and finalizes (freezes)
|
110
|
+
# the {config}.
|
111
|
+
#
|
112
|
+
# Does not finalize the config when given `finalize_config: false`
|
113
113
|
#
|
114
114
|
# @example
|
115
115
|
# class MyApp < Dry::System::Container
|
116
116
|
# configure do |config|
|
117
117
|
# config.root = Pathname("/path/to/app")
|
118
118
|
# config.name = :my_app
|
119
|
-
# config.auto_register = %w(lib/apis lib/core)
|
120
119
|
# end
|
121
120
|
# end
|
122
121
|
#
|
122
|
+
# @param finalize_config [Boolean]
|
123
|
+
#
|
123
124
|
# @return [self]
|
124
125
|
#
|
126
|
+
# @see after
|
127
|
+
#
|
125
128
|
# @api public
|
126
|
-
def configure(&block)
|
127
|
-
hooks[:before_configure].each { |hook| instance_eval(&hook) }
|
129
|
+
def configure(finalize_config: true, &block)
|
128
130
|
super(&block)
|
131
|
+
|
132
|
+
unless configured?
|
133
|
+
hooks[:after_configure].each { |hook| instance_eval(&hook) }
|
134
|
+
config.finalize! if finalize_config
|
135
|
+
@__configured__ = true
|
136
|
+
end
|
137
|
+
|
138
|
+
self
|
139
|
+
end
|
140
|
+
|
141
|
+
# Marks the container as configured, runs the after-`configured` hooks, then
|
142
|
+
# finalizes (freezes) the {config}.
|
143
|
+
#
|
144
|
+
# This method is useful to call if you're modifying the container's {config}
|
145
|
+
# directly, rather than via the config object yielded when calling {configure}.
|
146
|
+
#
|
147
|
+
# Does not finalize the config if given `finalize_config: false`.
|
148
|
+
#
|
149
|
+
# @param finalize_config [Boolean]
|
150
|
+
#
|
151
|
+
# @return [self]
|
152
|
+
#
|
153
|
+
# @see after
|
154
|
+
#
|
155
|
+
# @api public
|
156
|
+
def configured!(finalize_config: true)
|
157
|
+
return self if configured?
|
158
|
+
|
129
159
|
hooks[:after_configure].each { |hook| instance_eval(&hook) }
|
160
|
+
config.finalize! if finalize_config
|
161
|
+
@__configured__ = true
|
162
|
+
|
130
163
|
self
|
131
164
|
end
|
132
165
|
|
166
|
+
def configured?
|
167
|
+
@__configured__.equal?(true)
|
168
|
+
end
|
169
|
+
|
133
170
|
# Registers another container for import
|
134
171
|
#
|
135
172
|
# @example
|
@@ -156,124 +193,142 @@ module Dry
|
|
156
193
|
# @param other [Hash, Dry::Container::Namespace]
|
157
194
|
#
|
158
195
|
# @api public
|
159
|
-
def import(
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
196
|
+
def import(keys: nil, from: nil, as: nil, **deprecated_import_hash)
|
197
|
+
if deprecated_import_hash.any?
|
198
|
+
Dry::Core::Deprecations.announce(
|
199
|
+
"Dry::System::Container.import with {namespace => container} hash",
|
200
|
+
"Use Dry::System::Container.import(from: container, as: namespace) instead",
|
201
|
+
tag: "dry-system",
|
202
|
+
uplevel: 1
|
203
|
+
)
|
204
|
+
|
205
|
+
deprecated_import_hash.each do |namespace, container|
|
206
|
+
importer.register(container: container, namespace: namespace)
|
207
|
+
end
|
208
|
+
return self
|
209
|
+
elsif from.nil? || as.nil?
|
210
|
+
# These keyword arguments can become properly required in the params list once
|
211
|
+
# we remove the deprecation shim above
|
212
|
+
raise ArgumentError, "required keyword arguments: :from, :as"
|
167
213
|
end
|
214
|
+
|
215
|
+
importer.register(container: from, namespace: as, keys: keys)
|
216
|
+
|
217
|
+
self
|
168
218
|
end
|
169
219
|
|
170
|
-
#
|
220
|
+
# rubocop:disable Layout/LineLength
|
221
|
+
|
222
|
+
# @overload register_provider(name, namespace: nil, from: nil, source: nil, if: true, &block)
|
223
|
+
# Registers a provider and its lifecycle hooks
|
171
224
|
#
|
172
|
-
#
|
173
|
-
# `
|
174
|
-
#
|
175
|
-
# process.
|
225
|
+
# By convention, you should place a file for each provider in one of the
|
226
|
+
# configured `provider_dirs`, and they will be loaded on demand when components
|
227
|
+
# are loaded in isolation, or during container finalization.
|
176
228
|
#
|
177
|
-
#
|
178
|
-
#
|
179
|
-
#
|
180
|
-
#
|
181
|
-
#
|
182
|
-
#
|
183
|
-
# config.auto_register = %w(lib/apis lib/core)
|
229
|
+
# @example
|
230
|
+
# # system/container.rb
|
231
|
+
# class MyApp < Dry::System::Container
|
232
|
+
# configure do |config|
|
233
|
+
# config.root = Pathname("/path/to/app")
|
234
|
+
# end
|
184
235
|
# end
|
185
236
|
#
|
186
|
-
#
|
187
|
-
#
|
188
|
-
#
|
189
|
-
#
|
190
|
-
#
|
191
|
-
#
|
192
|
-
#
|
193
|
-
#
|
194
|
-
#
|
195
|
-
# # system/boot/db.rb
|
196
|
-
# #
|
197
|
-
# # Component registration with lifecycle triggers
|
198
|
-
# MyApp.boot(:db) do |container|
|
199
|
-
# init do
|
200
|
-
# require 'db'
|
201
|
-
# DB.configure(ENV['DB_URL'])
|
202
|
-
# container.register(:db, DB.new)
|
237
|
+
# # system/providers/db.rb
|
238
|
+
# #
|
239
|
+
# # Simple provider registration
|
240
|
+
# MyApp.register_provider(:db) do
|
241
|
+
# start do
|
242
|
+
# require "db"
|
243
|
+
# register("db", DB.new)
|
244
|
+
# end
|
203
245
|
# end
|
204
246
|
#
|
205
|
-
#
|
206
|
-
#
|
247
|
+
# # system/providers/db.rb
|
248
|
+
# #
|
249
|
+
# # Provider registration with lifecycle triggers
|
250
|
+
# MyApp.register_provider(:db) do |container|
|
251
|
+
# init do
|
252
|
+
# require "db"
|
253
|
+
# DB.configure(ENV["DB_URL"])
|
254
|
+
# container.register("db", DB.new)
|
255
|
+
# end
|
256
|
+
#
|
257
|
+
# start do
|
258
|
+
# container["db"].establish_connection
|
259
|
+
# end
|
260
|
+
#
|
261
|
+
# stop do
|
262
|
+
# container["db"].close_connection
|
263
|
+
# end
|
207
264
|
# end
|
208
265
|
#
|
209
|
-
#
|
210
|
-
#
|
266
|
+
# # system/providers/db.rb
|
267
|
+
# #
|
268
|
+
# # Provider registration which uses another provider
|
269
|
+
# MyApp.register_provider(:db) do |container|
|
270
|
+
# start do
|
271
|
+
# use :logger
|
272
|
+
#
|
273
|
+
# require "db"
|
274
|
+
# DB.configure(ENV['DB_URL'], logger: logger)
|
275
|
+
# container.register("db", DB.new)
|
276
|
+
# end
|
211
277
|
# end
|
212
|
-
# end
|
213
278
|
#
|
214
|
-
#
|
215
|
-
#
|
216
|
-
#
|
217
|
-
#
|
218
|
-
#
|
219
|
-
#
|
220
|
-
#
|
221
|
-
#
|
222
|
-
#
|
223
|
-
#
|
279
|
+
# # system/providers/db.rb
|
280
|
+
# #
|
281
|
+
# # Provider registration under a namespace. This will register the
|
282
|
+
# # db object with the "persistence.db" key
|
283
|
+
# MyApp.register_provider(:persistence, namespace: "db") do
|
284
|
+
# start do
|
285
|
+
# require "db"
|
286
|
+
# DB.configure(ENV["DB_URL"])
|
287
|
+
# register("db", DB.new)
|
288
|
+
# end
|
224
289
|
# end
|
225
|
-
# end
|
226
|
-
#
|
227
|
-
# # system/boot/db.rb
|
228
|
-
# #
|
229
|
-
# # Component registration under a namespace. This will register the
|
230
|
-
# # db object under `persistence.db` key
|
231
|
-
# MyApp.namespace(:persistence) do |persistence|
|
232
|
-
# require 'db'
|
233
|
-
# DB.configure(ENV['DB_URL'], logger: logger)
|
234
|
-
# persistence.register(:db, DB.new)
|
235
|
-
# end
|
236
290
|
#
|
237
|
-
#
|
291
|
+
# @param name [Symbol] a unique name for the provider
|
292
|
+
# @param namespace [String, nil] the key namespace to use for any registrations
|
293
|
+
# made during the provider's lifecycle
|
294
|
+
# @param from [Symbol, nil] the group for the external provider source (with the
|
295
|
+
# provider source name inferred from `name` or passsed explicitly as
|
296
|
+
# `source:`)
|
297
|
+
# @param source [Symbol, nil] the name of the external provider source to use
|
298
|
+
# (if different from the value provided as `name`)
|
299
|
+
# @param if [Boolean] a boolean to determine whether to register the provider
|
238
300
|
#
|
239
|
-
#
|
301
|
+
# @see Provider
|
302
|
+
# @see Provider::Source
|
240
303
|
#
|
241
|
-
#
|
304
|
+
# @return [self]
|
242
305
|
#
|
243
|
-
#
|
244
|
-
def
|
245
|
-
|
246
|
-
raise DuplicatedComponentKeyError, <<-STR
|
247
|
-
Bootable component #{name.inspect} was already registered
|
248
|
-
STR
|
249
|
-
end
|
250
|
-
|
251
|
-
component =
|
252
|
-
if opts[:from]
|
253
|
-
boot_external(name, **opts, &block)
|
254
|
-
else
|
255
|
-
boot_local(name, **opts, &block)
|
256
|
-
end
|
257
|
-
|
258
|
-
booter.register_component component
|
259
|
-
|
260
|
-
components[name] = component
|
306
|
+
# @api public
|
307
|
+
def register_provider(...)
|
308
|
+
providers.register_provider(...)
|
261
309
|
end
|
262
|
-
deprecate :finalize, :boot
|
263
310
|
|
264
|
-
#
|
265
|
-
|
266
|
-
|
267
|
-
|
311
|
+
# rubocop:enable Layout/LineLength
|
312
|
+
|
313
|
+
# @see .register_provider
|
314
|
+
# @api public
|
315
|
+
def boot(name, **opts, &block)
|
316
|
+
Dry::Core::Deprecations.announce(
|
317
|
+
"Dry::System::Container.boot",
|
318
|
+
"Use `Dry::System::Container.register_provider` instead",
|
319
|
+
tag: "dry-system",
|
320
|
+
uplevel: 1
|
268
321
|
)
|
269
|
-
end
|
270
322
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
323
|
+
register_provider(
|
324
|
+
name,
|
325
|
+
namespace: opts[:namespace],
|
326
|
+
from: opts[:from],
|
327
|
+
source: opts[:key],
|
328
|
+
&block
|
275
329
|
)
|
276
330
|
end
|
331
|
+
deprecate :finalize, :boot
|
277
332
|
|
278
333
|
# Return if a container was finalized
|
279
334
|
#
|
@@ -316,71 +371,77 @@ module Dry
|
|
316
371
|
def finalize!(freeze: true, &block)
|
317
372
|
return self if finalized?
|
318
373
|
|
374
|
+
configured!
|
375
|
+
|
376
|
+
hooks[:before_finalize].each { |hook| instance_eval(&hook) }
|
319
377
|
yield(self) if block
|
320
378
|
|
321
379
|
importer.finalize!
|
322
|
-
|
323
|
-
|
380
|
+
providers.finalize!
|
381
|
+
manifest_registrar.finalize!
|
324
382
|
auto_registrar.finalize!
|
325
383
|
|
326
384
|
@__finalized__ = true
|
327
385
|
|
328
386
|
self.freeze if freeze
|
387
|
+
hooks[:after_finalize].each { |hook| instance_eval(&hook) }
|
329
388
|
self
|
330
389
|
end
|
331
390
|
|
332
|
-
#
|
391
|
+
# Starts a provider
|
333
392
|
#
|
334
|
-
# As a result, `
|
393
|
+
# As a result, the provider's `prepare` and `start` lifecycle triggers are called
|
335
394
|
#
|
336
395
|
# @example
|
337
396
|
# MyApp.start(:persistence)
|
338
397
|
#
|
339
|
-
# @param name [Symbol] the name of a registered
|
398
|
+
# @param name [Symbol] the name of a registered provider to start
|
340
399
|
#
|
341
400
|
# @return [self]
|
342
401
|
#
|
343
402
|
# @api public
|
344
403
|
def start(name)
|
345
|
-
|
404
|
+
providers.start(name)
|
346
405
|
self
|
347
406
|
end
|
348
407
|
|
349
|
-
#
|
408
|
+
# Prepares a provider using its `prepare` lifecycle trigger
|
350
409
|
#
|
351
|
-
#
|
352
|
-
# needed but its started environment
|
410
|
+
# Preparing (as opposed to starting) a provider is useful in places where some
|
411
|
+
# aspects of a heavier dependency are needed, but its fully started environment
|
353
412
|
#
|
354
413
|
# @example
|
355
|
-
# MyApp.
|
414
|
+
# MyApp.prepare(:persistence)
|
356
415
|
#
|
357
|
-
# @param [Symbol]
|
416
|
+
# @param name [Symbol] The name of the registered provider to prepare
|
358
417
|
#
|
359
418
|
# @return [self]
|
360
419
|
#
|
361
420
|
# @api public
|
362
|
-
def
|
363
|
-
|
421
|
+
def prepare(name)
|
422
|
+
providers.prepare(name)
|
364
423
|
self
|
365
424
|
end
|
425
|
+
deprecate :init, :prepare
|
366
426
|
|
367
427
|
# Stop a specific component but calls only `stop` lifecycle trigger
|
368
428
|
#
|
369
429
|
# @example
|
370
430
|
# MyApp.stop(:persistence)
|
371
431
|
#
|
372
|
-
# @param [Symbol]
|
432
|
+
# @param name [Symbol] The name of a registered bootable component
|
373
433
|
#
|
374
434
|
# @return [self]
|
375
435
|
#
|
376
436
|
# @api public
|
377
437
|
def stop(name)
|
378
|
-
|
438
|
+
providers.stop(name)
|
379
439
|
self
|
380
440
|
end
|
381
441
|
|
442
|
+
# @api public
|
382
443
|
def shutdown!
|
383
|
-
|
444
|
+
providers.shutdown
|
384
445
|
self
|
385
446
|
end
|
386
447
|
|
@@ -395,7 +456,7 @@ module Dry
|
|
395
456
|
# add_to_load_path!('lib')
|
396
457
|
# end
|
397
458
|
#
|
398
|
-
# @param [Array<String>]
|
459
|
+
# @param dirs [Array<String>]
|
399
460
|
#
|
400
461
|
# @return [self]
|
401
462
|
#
|
@@ -409,7 +470,7 @@ module Dry
|
|
409
470
|
|
410
471
|
# @api public
|
411
472
|
def load_registrations!(name)
|
412
|
-
|
473
|
+
manifest_registrar.(name)
|
413
474
|
self
|
414
475
|
end
|
415
476
|
|
@@ -438,8 +499,8 @@ module Dry
|
|
438
499
|
# @param options [Hash] injector options
|
439
500
|
#
|
440
501
|
# @api public
|
441
|
-
def injector(options
|
442
|
-
Dry::AutoInject(self, options)
|
502
|
+
def injector(**options)
|
503
|
+
Dry::AutoInject(self, **options)
|
443
504
|
end
|
444
505
|
|
445
506
|
# Requires one or more files relative to the container's root
|
@@ -491,7 +552,7 @@ module Dry
|
|
491
552
|
#
|
492
553
|
# @!method registered?(key)
|
493
554
|
# Whether a +key+ is registered (doesn't trigger loading)
|
494
|
-
# @param [String,Symbol] key
|
555
|
+
# @param key [String,Symbol] The key
|
495
556
|
# @return [Boolean]
|
496
557
|
# @api public
|
497
558
|
#
|
@@ -499,7 +560,7 @@ module Dry
|
|
499
560
|
# Check if identifier is registered.
|
500
561
|
# If not, try to load the component
|
501
562
|
#
|
502
|
-
# @param [String,Symbol]
|
563
|
+
# @param key [String,Symbol] Identifier
|
503
564
|
# @return [Boolean]
|
504
565
|
#
|
505
566
|
# @api public
|
@@ -518,22 +579,10 @@ module Dry
|
|
518
579
|
end
|
519
580
|
|
520
581
|
# @api private
|
521
|
-
def
|
522
|
-
@
|
523
|
-
end
|
524
|
-
|
525
|
-
# @api private
|
526
|
-
def boot_paths
|
527
|
-
config.bootable_dirs.map { |dir|
|
528
|
-
dir = Pathname(dir)
|
529
|
-
|
530
|
-
if dir.relative?
|
531
|
-
root.join(dir)
|
532
|
-
else
|
533
|
-
dir
|
534
|
-
end
|
535
|
-
}
|
582
|
+
def providers
|
583
|
+
@providers ||= config.provider_registrar.new(self)
|
536
584
|
end
|
585
|
+
deprecate :booter, :providers
|
537
586
|
|
538
587
|
# @api private
|
539
588
|
def auto_registrar
|
@@ -541,8 +590,8 @@ module Dry
|
|
541
590
|
end
|
542
591
|
|
543
592
|
# @api private
|
544
|
-
def
|
545
|
-
@
|
593
|
+
def manifest_registrar
|
594
|
+
@manifest_registrar ||= config.manifest_registrar.new(self)
|
546
595
|
end
|
547
596
|
|
548
597
|
# @api private
|
@@ -550,13 +599,45 @@ module Dry
|
|
550
599
|
@importer ||= config.importer.new(self)
|
551
600
|
end
|
552
601
|
|
553
|
-
#
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
602
|
+
# Registers a callback hook to run before container lifecycle events.
|
603
|
+
#
|
604
|
+
# Currently, the only supported event is `:finalized`. This hook is called when
|
605
|
+
# you run `{finalize!}`.
|
606
|
+
#
|
607
|
+
# When the given block is called, `self` is the container class, and no block
|
608
|
+
# arguments are given.
|
609
|
+
#
|
610
|
+
# @param event [Symbol] the event name
|
611
|
+
# @param block [Proc] the callback hook to run
|
612
|
+
#
|
613
|
+
# @return [self]
|
614
|
+
#
|
615
|
+
# @api public
|
558
616
|
def before(event, &block)
|
559
617
|
hooks[:"before_#{event}"] << block
|
618
|
+
self
|
619
|
+
end
|
620
|
+
|
621
|
+
# Registers a callback hook to run after container lifecycle events.
|
622
|
+
#
|
623
|
+
# The supported events are:
|
624
|
+
#
|
625
|
+
# - `:configured`, called when you run {configure} or {configured!}, or when
|
626
|
+
# running {finalize!} and neither of the prior two methods have been called.
|
627
|
+
# - `:finalized`, called when you run {finalize!}.
|
628
|
+
#
|
629
|
+
# When the given block is called, `self` is the container class, and no block
|
630
|
+
# arguments are given.
|
631
|
+
#
|
632
|
+
# @param event [Symbol] the event name
|
633
|
+
# @param block [Proc] the callback hook to run
|
634
|
+
#
|
635
|
+
# @return [self]
|
636
|
+
#
|
637
|
+
# @api public
|
638
|
+
def after(event, &block)
|
639
|
+
hooks[:"after_#{event}"] << block
|
640
|
+
self
|
560
641
|
end
|
561
642
|
|
562
643
|
# @api private
|
@@ -570,6 +651,7 @@ module Dry
|
|
570
651
|
klass.hooks[event].concat blocks.dup
|
571
652
|
end
|
572
653
|
|
654
|
+
klass.instance_variable_set(:@__configured__, false)
|
573
655
|
klass.instance_variable_set(:@__finalized__, false)
|
574
656
|
|
575
657
|
super
|
@@ -581,21 +663,21 @@ module Dry
|
|
581
663
|
def load_component(key)
|
582
664
|
return self if registered?(key)
|
583
665
|
|
584
|
-
|
585
|
-
|
586
|
-
if component.bootable?
|
587
|
-
booter.start(component)
|
666
|
+
if (provider = providers.find_and_load_provider(key))
|
667
|
+
provider.start
|
588
668
|
return self
|
589
669
|
end
|
590
670
|
|
591
|
-
|
671
|
+
component = find_component(key)
|
672
|
+
|
673
|
+
providers.start_provider_dependency(component)
|
592
674
|
return self if registered?(key)
|
593
675
|
|
594
|
-
if component.
|
676
|
+
if component.loadable?
|
595
677
|
load_local_component(component)
|
596
|
-
elsif
|
597
|
-
|
598
|
-
elsif importer.
|
678
|
+
elsif manifest_registrar.file_exists?(component)
|
679
|
+
manifest_registrar.(component)
|
680
|
+
elsif importer.namespace?(component.identifier.root_key)
|
599
681
|
load_imported_component(component.identifier)
|
600
682
|
end
|
601
683
|
|
@@ -613,27 +695,23 @@ module Dry
|
|
613
695
|
def load_imported_component(identifier)
|
614
696
|
import_namespace = identifier.root_key
|
615
697
|
|
616
|
-
|
698
|
+
return unless importer.namespace?(import_namespace)
|
617
699
|
|
618
|
-
|
700
|
+
import_key = identifier.namespaced(from: import_namespace, to: nil).key
|
619
701
|
|
620
|
-
importer.(import_namespace,
|
702
|
+
importer.import(import_namespace, keys: [import_key])
|
621
703
|
end
|
622
704
|
|
623
|
-
def
|
624
|
-
if (bootable_component = booter.find_component(identifier))
|
625
|
-
return bootable_component
|
626
|
-
end
|
627
|
-
|
705
|
+
def find_component(key)
|
628
706
|
# Find the first matching component from within the configured component dirs.
|
629
|
-
# If no matching component is found, return a
|
630
|
-
#
|
631
|
-
#
|
707
|
+
# If no matching component is found, return a null component; this fallback is
|
708
|
+
# important because the component may still be loadable via the manifest
|
709
|
+
# registrar or an imported container.
|
632
710
|
component_dirs.detect { |dir|
|
633
|
-
if (component = dir.
|
711
|
+
if (component = dir.component_for_key(key))
|
634
712
|
break component
|
635
713
|
end
|
636
|
-
} ||
|
714
|
+
} || IndirectComponent.new(Identifier.new(key))
|
637
715
|
end
|
638
716
|
end
|
639
717
|
|