dry-system 0.22.0 → 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 +400 -0
- data/LICENSE +1 -1
- data/README.md +2 -2
- data/dry-system.gemspec +2 -2
- data/lib/dry/system/component.rb +2 -3
- data/lib/dry/system/component_dir.rb +8 -34
- data/lib/dry/system/components.rb +8 -4
- data/lib/dry/system/config/component_dir.rb +60 -16
- data/lib/dry/system/config/component_dirs.rb +23 -10
- data/lib/dry/system/config/namespace.rb +4 -6
- data/lib/dry/system/constants.rb +1 -1
- data/lib/dry/system/container.rb +264 -182
- data/lib/dry/system/errors.rb +73 -53
- data/lib/dry/system/identifier.rb +62 -20
- data/lib/dry/system/importer.rb +83 -12
- data/lib/dry/system/indirect_component.rb +1 -1
- data/lib/dry/system/loader.rb +6 -1
- data/lib/dry/system/{manual_registrar.rb → manifest_registrar.rb} +8 -5
- data/lib/dry/system/plugins/bootsnap.rb +2 -1
- 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 +2 -1
- data/lib/dry/system/plugins/logging.rb +2 -2
- 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 +7 -4
- 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 +262 -22
- 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/version.rb +1 -1
- data/lib/dry/system.rb +44 -12
- metadata +18 -18
- 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 -280
- 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 -64
- data/lib/dry/system/system_components/settings.rb +0 -11
data/lib/dry/system/container.rb
CHANGED
@@ -5,22 +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
|
-
require "dry/core/constants"
|
11
8
|
require "dry/core/deprecations"
|
9
|
+
require "dry/inflector"
|
12
10
|
|
13
|
-
require "dry/system"
|
14
11
|
require "dry/system/auto_registrar"
|
15
|
-
require "dry/system/booter"
|
16
12
|
require "dry/system/component"
|
17
13
|
require "dry/system/constants"
|
18
14
|
require "dry/system/errors"
|
19
15
|
require "dry/system/identifier"
|
20
16
|
require "dry/system/importer"
|
21
17
|
require "dry/system/indirect_component"
|
22
|
-
require "dry/system/
|
18
|
+
require "dry/system/manifest_registrar"
|
23
19
|
require "dry/system/plugins"
|
20
|
+
require "dry/system/provider_registrar"
|
21
|
+
require "dry/system/provider"
|
22
|
+
require "dry/system/provider/source"
|
24
23
|
|
25
24
|
require_relative "component_dir"
|
26
25
|
require_relative "config/component_dirs"
|
@@ -77,61 +76,97 @@ module Dry
|
|
77
76
|
|
78
77
|
setting :name
|
79
78
|
setting :root, default: Pathname.pwd.freeze, constructor: -> path { Pathname(path) }
|
80
|
-
setting :
|
81
|
-
setting :bootable_dirs,
|
82
|
-
setting :registrations_dir, default: "
|
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"
|
83
82
|
setting :component_dirs, default: Config::ComponentDirs.new, cloneable: true
|
83
|
+
setting :exports, reader: true
|
84
84
|
setting :inflector, default: Dry::Inflector.new
|
85
|
-
setting :booter, default: Dry::System::Booter
|
86
85
|
setting :auto_registrar, default: Dry::System::AutoRegistrar
|
87
|
-
setting :
|
86
|
+
setting :manifest_registrar, default: Dry::System::ManifestRegistrar
|
87
|
+
setting :provider_registrar, default: Dry::System::ProviderRegistrar
|
88
88
|
setting :importer, default: Dry::System::Importer
|
89
|
-
setting :components, default: {}, reader: true, constructor: :dup.to_proc
|
90
89
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
@strategies = value
|
95
|
-
else
|
96
|
-
@strategies ||= Dry::AutoInject::Strategies
|
97
|
-
end
|
98
|
-
end
|
90
|
+
# We presume "." as key namespace separator. This is not intended to be
|
91
|
+
# user-configurable.
|
92
|
+
config.namespace_separator = KEY_SEPARATOR
|
99
93
|
|
94
|
+
class << self
|
100
95
|
extend Dry::Core::Deprecations["Dry::System::Container"]
|
101
96
|
|
102
|
-
#
|
97
|
+
# @!method config
|
98
|
+
# Returns the configuration for the container
|
103
99
|
#
|
104
|
-
#
|
100
|
+
# @example
|
101
|
+
# container.config.root = "/path/to/app"
|
102
|
+
# container.config.root # => #<Pathname:/path/to/app>
|
105
103
|
#
|
106
|
-
#
|
107
|
-
|
108
|
-
|
109
|
-
# TODO: dry-configurable needs a public API for this
|
110
|
-
config._settings << _settings[name]
|
111
|
-
self
|
112
|
-
end
|
104
|
+
# @return [Dry::Configurable::Config]
|
105
|
+
#
|
106
|
+
# @api public
|
113
107
|
|
114
|
-
#
|
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`
|
115
113
|
#
|
116
114
|
# @example
|
117
115
|
# class MyApp < Dry::System::Container
|
118
116
|
# configure do |config|
|
119
117
|
# config.root = Pathname("/path/to/app")
|
120
118
|
# config.name = :my_app
|
121
|
-
# config.auto_register = %w(lib/apis lib/core)
|
122
119
|
# end
|
123
120
|
# end
|
124
121
|
#
|
122
|
+
# @param finalize_config [Boolean]
|
123
|
+
#
|
125
124
|
# @return [self]
|
126
125
|
#
|
126
|
+
# @see after
|
127
|
+
#
|
127
128
|
# @api public
|
128
|
-
def configure(&block)
|
129
|
-
hooks[:before_configure].each { |hook| instance_eval(&hook) }
|
129
|
+
def configure(finalize_config: true, &block)
|
130
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
|
+
|
131
159
|
hooks[:after_configure].each { |hook| instance_eval(&hook) }
|
160
|
+
config.finalize! if finalize_config
|
161
|
+
@__configured__ = true
|
162
|
+
|
132
163
|
self
|
133
164
|
end
|
134
165
|
|
166
|
+
def configured?
|
167
|
+
@__configured__.equal?(true)
|
168
|
+
end
|
169
|
+
|
135
170
|
# Registers another container for import
|
136
171
|
#
|
137
172
|
# @example
|
@@ -158,122 +193,142 @@ module Dry
|
|
158
193
|
# @param other [Hash, Dry::Container::Namespace]
|
159
194
|
#
|
160
195
|
# @api public
|
161
|
-
def import(
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
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"
|
169
213
|
end
|
214
|
+
|
215
|
+
importer.register(container: from, namespace: as, keys: keys)
|
216
|
+
|
217
|
+
self
|
170
218
|
end
|
171
219
|
|
172
|
-
#
|
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
|
173
224
|
#
|
174
|
-
#
|
175
|
-
# `
|
176
|
-
#
|
177
|
-
# 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.
|
178
228
|
#
|
179
|
-
#
|
180
|
-
#
|
181
|
-
#
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
185
|
-
# 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
|
186
235
|
# end
|
187
236
|
#
|
188
|
-
#
|
189
|
-
#
|
190
|
-
#
|
191
|
-
#
|
192
|
-
#
|
193
|
-
#
|
194
|
-
#
|
195
|
-
#
|
196
|
-
#
|
197
|
-
# # system/boot/db.rb
|
198
|
-
# #
|
199
|
-
# # Component registration with lifecycle triggers
|
200
|
-
# MyApp.boot(:db) do |container|
|
201
|
-
# init do
|
202
|
-
# require 'db'
|
203
|
-
# DB.configure(ENV['DB_URL'])
|
204
|
-
# 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
|
205
245
|
# end
|
206
246
|
#
|
207
|
-
#
|
208
|
-
#
|
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
|
209
264
|
# end
|
210
265
|
#
|
211
|
-
#
|
212
|
-
#
|
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
|
213
277
|
# end
|
214
|
-
# end
|
215
278
|
#
|
216
|
-
#
|
217
|
-
#
|
218
|
-
#
|
219
|
-
#
|
220
|
-
#
|
221
|
-
#
|
222
|
-
#
|
223
|
-
#
|
224
|
-
#
|
225
|
-
#
|
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
|
226
289
|
# end
|
227
|
-
# end
|
228
290
|
#
|
229
|
-
#
|
230
|
-
#
|
231
|
-
#
|
232
|
-
#
|
233
|
-
#
|
234
|
-
#
|
235
|
-
#
|
236
|
-
#
|
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
|
-
|
245
|
-
|
246
|
-
def boot(name, **opts, &block)
|
247
|
-
if components.key?(name)
|
248
|
-
raise DuplicatedComponentKeyError, <<-STR
|
249
|
-
Bootable component #{name.inspect} was already registered
|
250
|
-
STR
|
251
|
-
end
|
252
|
-
|
253
|
-
component =
|
254
|
-
if opts[:from]
|
255
|
-
boot_external(name, **opts, &block)
|
256
|
-
else
|
257
|
-
boot_local(name, **opts, &block)
|
258
|
-
end
|
259
|
-
|
260
|
-
booter.register_component component
|
261
|
-
|
262
|
-
components[name] = component
|
306
|
+
# @api public
|
307
|
+
def register_provider(...)
|
308
|
+
providers.register_provider(...)
|
263
309
|
end
|
264
|
-
deprecate :finalize, :boot
|
265
310
|
|
266
|
-
#
|
267
|
-
|
268
|
-
|
269
|
-
|
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
|
270
321
|
)
|
271
|
-
end
|
272
322
|
|
273
|
-
|
274
|
-
|
275
|
-
|
323
|
+
register_provider(
|
324
|
+
name,
|
325
|
+
namespace: opts[:namespace],
|
326
|
+
from: opts[:from],
|
327
|
+
source: opts[:key],
|
328
|
+
&block
|
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]
|
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
|
-
if (
|
585
|
-
|
666
|
+
if (provider = providers.find_and_load_provider(key))
|
667
|
+
provider.start
|
586
668
|
return self
|
587
669
|
end
|
588
670
|
|
589
671
|
component = find_component(key)
|
590
672
|
|
591
|
-
|
673
|
+
providers.start_provider_dependency(component)
|
592
674
|
return self if registered?(key)
|
593
675
|
|
594
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,23 +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
705
|
def find_component(key)
|
624
706
|
# Find the first matching component from within the configured component dirs.
|
625
707
|
# If no matching component is found, return a null component; this fallback is
|
626
|
-
# important because the component may still be loadable via the
|
627
|
-
# or an imported container.
|
708
|
+
# important because the component may still be loadable via the manifest
|
709
|
+
# registrar or an imported container.
|
628
710
|
component_dirs.detect { |dir|
|
629
711
|
if (component = dir.component_for_key(key))
|
630
712
|
break component
|
631
713
|
end
|
632
|
-
} || IndirectComponent.new(Identifier.new(key
|
714
|
+
} || IndirectComponent.new(Identifier.new(key))
|
633
715
|
end
|
634
716
|
end
|
635
717
|
|