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