dry-system 0.22.0 → 0.23.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|