dry-system 0.22.0 → 0.25.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 +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
|
|