dry-system 0.15.0 → 0.19.1
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 +142 -2
- data/LICENSE +1 -1
- data/README.md +1 -1
- data/dry-system.gemspec +5 -4
- data/lib/dry-system.rb +1 -1
- data/lib/dry/system.rb +2 -2
- data/lib/dry/system/auto_registrar.rb +17 -59
- data/lib/dry/system/booter.rb +68 -41
- data/lib/dry/system/component.rb +62 -100
- data/lib/dry/system/component_dir.rb +128 -0
- data/lib/dry/system/components.rb +2 -2
- data/lib/dry/system/components/bootable.rb +6 -34
- data/lib/dry/system/components/config.rb +2 -2
- data/lib/dry/system/config/component_dir.rb +202 -0
- data/lib/dry/system/config/component_dirs.rb +184 -0
- data/lib/dry/system/constants.rb +5 -5
- data/lib/dry/system/container.rb +133 -184
- data/lib/dry/system/errors.rb +21 -16
- data/lib/dry/system/identifier.rb +157 -0
- data/lib/dry/system/lifecycle.rb +2 -2
- data/lib/dry/system/loader.rb +40 -41
- data/lib/dry/system/loader/autoloading.rb +26 -0
- data/lib/dry/system/magic_comments_parser.rb +2 -2
- data/lib/dry/system/manual_registrar.rb +1 -1
- data/lib/dry/system/plugins.rb +7 -7
- data/lib/dry/system/plugins/bootsnap.rb +3 -3
- data/lib/dry/system/plugins/dependency_graph.rb +3 -3
- data/lib/dry/system/plugins/dependency_graph/strategies.rb +1 -1
- data/lib/dry/system/plugins/logging.rb +5 -5
- data/lib/dry/system/plugins/monitoring.rb +3 -3
- data/lib/dry/system/plugins/monitoring/proxy.rb +3 -3
- data/lib/dry/system/plugins/notifications.rb +1 -1
- data/lib/dry/system/provider.rb +3 -3
- data/lib/dry/system/settings.rb +6 -6
- data/lib/dry/system/settings/file_loader.rb +2 -2
- data/lib/dry/system/settings/file_parser.rb +1 -1
- data/lib/dry/system/stubs.rb +1 -1
- data/lib/dry/system/system_components/settings.rb +1 -1
- data/lib/dry/system/version.rb +1 -1
- metadata +21 -25
- data/lib/dry/system/auto_registrar/configuration.rb +0 -43
@@ -0,0 +1,184 @@
|
|
1
|
+
require "concurrent/map"
|
2
|
+
require "dry/configurable"
|
3
|
+
require "dry/system/constants"
|
4
|
+
require "dry/system/errors"
|
5
|
+
require_relative "component_dir"
|
6
|
+
|
7
|
+
module Dry
|
8
|
+
module System
|
9
|
+
module Config
|
10
|
+
class ComponentDirs
|
11
|
+
include Dry::Configurable
|
12
|
+
|
13
|
+
# Settings from ComponentDir are configured here as defaults for all added dirs
|
14
|
+
ComponentDir._settings.each do |setting|
|
15
|
+
_settings << setting.dup
|
16
|
+
end
|
17
|
+
|
18
|
+
# @!group Settings
|
19
|
+
|
20
|
+
# @!method auto_register=(value)
|
21
|
+
#
|
22
|
+
# Sets a default `auto_register` for all added component dirs
|
23
|
+
#
|
24
|
+
# @see ComponentDir.auto_register
|
25
|
+
# @see auto_register
|
26
|
+
#
|
27
|
+
# @!method auto_register
|
28
|
+
#
|
29
|
+
# Returns the configured default `auto_register`
|
30
|
+
#
|
31
|
+
# @see auto_register=
|
32
|
+
|
33
|
+
# @!method add_to_load_path=(value)
|
34
|
+
#
|
35
|
+
# Sets a default `add_to_load_path` value for all added component dirs
|
36
|
+
#
|
37
|
+
# @see ComponentDir.add_to_load_path
|
38
|
+
# @see add_to_load_path
|
39
|
+
#
|
40
|
+
# @!method add_to_load_path
|
41
|
+
#
|
42
|
+
# Returns the configured default `add_to_load_path`
|
43
|
+
#
|
44
|
+
# @see add_to_load_path=
|
45
|
+
|
46
|
+
# @!method default_namespace=(value)
|
47
|
+
#
|
48
|
+
# Sets a default `default_namespace` value for all added component dirs
|
49
|
+
#
|
50
|
+
# @see ComponentDir.default_namespace
|
51
|
+
# @see default_namespace
|
52
|
+
#
|
53
|
+
# @!method default_namespace
|
54
|
+
#
|
55
|
+
# Returns the configured default `default_namespace`
|
56
|
+
#
|
57
|
+
# @see default_namespace=
|
58
|
+
|
59
|
+
# @!method loader=(value)
|
60
|
+
#
|
61
|
+
# Sets a default `loader` value for all added component dirs
|
62
|
+
#
|
63
|
+
# @see ComponentDir.loader
|
64
|
+
# @see loader
|
65
|
+
#
|
66
|
+
# @!method loader
|
67
|
+
#
|
68
|
+
# Returns the configured default `loader`
|
69
|
+
#
|
70
|
+
# @see loader=
|
71
|
+
|
72
|
+
# @!method memoize=(value)
|
73
|
+
#
|
74
|
+
# Sets a default `memoize` value for all added component dirs
|
75
|
+
#
|
76
|
+
# @see ComponentDir.memoize
|
77
|
+
# @see memoize
|
78
|
+
#
|
79
|
+
# @!method memoize
|
80
|
+
#
|
81
|
+
# Returns the configured default `memoize`
|
82
|
+
#
|
83
|
+
# @see memoize=
|
84
|
+
|
85
|
+
# @!endgroup
|
86
|
+
|
87
|
+
# @api private
|
88
|
+
def initialize
|
89
|
+
@dirs = Concurrent::Map.new
|
90
|
+
end
|
91
|
+
|
92
|
+
# @api private
|
93
|
+
def initialize_copy(source)
|
94
|
+
super
|
95
|
+
@dirs = source.dirs.dup
|
96
|
+
end
|
97
|
+
|
98
|
+
# Adds and configures a component dir
|
99
|
+
#
|
100
|
+
# @param path [String] the path for the component dir, relative to the configured
|
101
|
+
# container root
|
102
|
+
#
|
103
|
+
# @yieldparam dir [ComponentDir] the component dir to configure
|
104
|
+
#
|
105
|
+
# @return [ComponentDir] the added component dir
|
106
|
+
#
|
107
|
+
# @example
|
108
|
+
# component_dirs.add "lib" do |dir|
|
109
|
+
# dir.default_namespace = "my_app"
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# @see ComponentDir
|
113
|
+
def add(path)
|
114
|
+
raise ComponentDirAlreadyAddedError, path if dirs.key?(path)
|
115
|
+
|
116
|
+
dirs[path] = ComponentDir.new(path).tap do |dir|
|
117
|
+
apply_defaults_to_dir(dir)
|
118
|
+
yield dir if block_given?
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Returns the added component dirs, with default settings applied
|
123
|
+
#
|
124
|
+
# @return [Hash<String, ComponentDir>] the component dirs as a hash, keyed by path
|
125
|
+
def dirs
|
126
|
+
@dirs.each { |_, dir| apply_defaults_to_dir(dir) }
|
127
|
+
end
|
128
|
+
|
129
|
+
# Returns the added component dirs, with default settings applied
|
130
|
+
#
|
131
|
+
# @return [Array<ComponentDir>]
|
132
|
+
def to_a
|
133
|
+
dirs.values
|
134
|
+
end
|
135
|
+
|
136
|
+
# Calls the given block once for each added component dir, passing the dir as an
|
137
|
+
# argument.
|
138
|
+
#
|
139
|
+
# @yieldparam dir [ComponentDir] the yielded component dir
|
140
|
+
def each(&block)
|
141
|
+
to_a.each(&block)
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
# Apply default settings to a component dir. This is run every time the dirs are
|
147
|
+
# accessed to ensure defaults are applied regardless of when new component dirs
|
148
|
+
# are added. This method must be idempotent.
|
149
|
+
#
|
150
|
+
# @return [void]
|
151
|
+
def apply_defaults_to_dir(dir)
|
152
|
+
dir.config.values.each do |key, _value|
|
153
|
+
if configured?(key) && !dir.configured?(key)
|
154
|
+
dir.public_send(:"#{key}=", public_send(key))
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Returns true if a setting has been explicitly configured and is not returning
|
160
|
+
# just a default value.
|
161
|
+
#
|
162
|
+
# This is used to determine which settings should be applied to added component
|
163
|
+
# dirs as additional defaults.
|
164
|
+
#
|
165
|
+
# @api private
|
166
|
+
def configured?(key)
|
167
|
+
config._settings[key].input_defined?
|
168
|
+
end
|
169
|
+
|
170
|
+
def method_missing(name, *args, &block)
|
171
|
+
if config.respond_to?(name)
|
172
|
+
config.public_send(name, *args, &block)
|
173
|
+
else
|
174
|
+
super
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def respond_to_missing?(name, include_all = false)
|
179
|
+
config.respond_to?(name) || super
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
data/lib/dry/system/constants.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/core/constants"
|
4
4
|
|
5
5
|
module Dry
|
6
6
|
module System
|
7
7
|
include Dry::Core::Constants
|
8
8
|
|
9
|
-
RB_EXT =
|
10
|
-
RB_GLOB =
|
11
|
-
PATH_SEPARATOR =
|
12
|
-
DEFAULT_SEPARATOR =
|
9
|
+
RB_EXT = ".rb"
|
10
|
+
RB_GLOB = "*.rb"
|
11
|
+
PATH_SEPARATOR = "/"
|
12
|
+
DEFAULT_SEPARATOR = "."
|
13
13
|
WORD_REGEX = /\w+/.freeze
|
14
14
|
end
|
15
15
|
end
|
data/lib/dry/system/container.rb
CHANGED
@@ -1,24 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
|
10
|
-
require
|
11
|
-
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
-
require
|
20
|
-
require
|
21
|
-
|
3
|
+
require "pathname"
|
4
|
+
|
5
|
+
require "dry-auto_inject"
|
6
|
+
require "dry-configurable"
|
7
|
+
require "dry-container"
|
8
|
+
require "dry/inflector"
|
9
|
+
|
10
|
+
require "dry/core/deprecations"
|
11
|
+
|
12
|
+
require "dry/system"
|
13
|
+
require "dry/system/errors"
|
14
|
+
require "dry/system/booter"
|
15
|
+
require "dry/system/auto_registrar"
|
16
|
+
require "dry/system/manual_registrar"
|
17
|
+
require "dry/system/importer"
|
18
|
+
require "dry/system/component"
|
19
|
+
require "dry/system/constants"
|
20
|
+
require "dry/system/plugins"
|
21
|
+
|
22
|
+
require_relative "component_dir"
|
23
|
+
require_relative "config/component_dirs"
|
22
24
|
|
23
25
|
module Dry
|
24
26
|
module System
|
@@ -48,8 +50,6 @@ module Dry
|
|
48
50
|
#
|
49
51
|
# * `:name` - a unique container identifier
|
50
52
|
# * `:root` - a system root directory (defaults to `pwd`)
|
51
|
-
# * `:system_dir` - directory name relative to root, where bootable components
|
52
|
-
# can be defined in `boot` dir this defaults to `system`
|
53
53
|
#
|
54
54
|
# @example
|
55
55
|
# class MyApp < Dry::System::Container
|
@@ -63,7 +63,7 @@ module Dry
|
|
63
63
|
# end
|
64
64
|
#
|
65
65
|
# # this will configure $LOAD_PATH to include your `lib` dir
|
66
|
-
#
|
66
|
+
# add_dirs_to_load_paths!('lib')
|
67
67
|
# end
|
68
68
|
#
|
69
69
|
# @api public
|
@@ -73,13 +73,12 @@ module Dry
|
|
73
73
|
extend Dry::System::Plugins
|
74
74
|
|
75
75
|
setting :name
|
76
|
-
setting :default_namespace
|
77
76
|
setting(:root, Pathname.pwd.freeze) { |path| Pathname(path) }
|
78
|
-
setting :system_dir,
|
79
|
-
setting :
|
80
|
-
setting :
|
77
|
+
setting :system_dir, "system"
|
78
|
+
setting :bootable_dirs, ["system/boot"]
|
79
|
+
setting :registrations_dir, "container"
|
80
|
+
setting :component_dirs, Config::ComponentDirs.new, cloneable: true
|
81
81
|
setting :inflector, Dry::Inflector.new
|
82
|
-
setting :loader, Dry::System::Loader
|
83
82
|
setting :booter, Dry::System::Booter
|
84
83
|
setting :auto_registrar, Dry::System::AutoRegistrar
|
85
84
|
setting :manual_registrar, Dry::System::ManualRegistrar
|
@@ -95,7 +94,19 @@ module Dry
|
|
95
94
|
end
|
96
95
|
end
|
97
96
|
|
98
|
-
extend Dry::Core::Deprecations[
|
97
|
+
extend Dry::Core::Deprecations["Dry::System::Container"]
|
98
|
+
|
99
|
+
# Define a new configuration setting
|
100
|
+
#
|
101
|
+
# @see https://dry-rb.org/gems/dry-configurable
|
102
|
+
#
|
103
|
+
# @api public
|
104
|
+
def setting(name, *args, &block)
|
105
|
+
super(name, *args, &block)
|
106
|
+
# TODO: dry-configurable needs a public API for this
|
107
|
+
config._settings << _settings[name]
|
108
|
+
self
|
109
|
+
end
|
99
110
|
|
100
111
|
# Configures the container
|
101
112
|
#
|
@@ -114,7 +125,6 @@ module Dry
|
|
114
125
|
def configure(&block)
|
115
126
|
hooks[:before_configure].each { |hook| instance_eval(&hook) }
|
116
127
|
super(&block)
|
117
|
-
load_paths!(config.system_dir)
|
118
128
|
hooks[:after_configure].each { |hook| instance_eval(&hook) }
|
119
129
|
self
|
120
130
|
end
|
@@ -158,9 +168,10 @@ module Dry
|
|
158
168
|
|
159
169
|
# Registers finalization function for a bootable component
|
160
170
|
#
|
161
|
-
# By convention, boot files for components should be placed in
|
162
|
-
#
|
163
|
-
# are loaded in isolation, or during finalization
|
171
|
+
# By convention, boot files for components should be placed in a
|
172
|
+
# `bootable_dirs` entry and they will be loaded on demand when
|
173
|
+
# components are loaded in isolation, or during the finalization
|
174
|
+
# process.
|
164
175
|
#
|
165
176
|
# @example
|
166
177
|
# # system/container.rb
|
@@ -243,30 +254,24 @@ module Dry
|
|
243
254
|
boot_local(name, **opts, &block)
|
244
255
|
end
|
245
256
|
|
257
|
+
booter.register_component component
|
258
|
+
|
246
259
|
components[name] = component
|
247
260
|
end
|
248
261
|
deprecate :finalize, :boot
|
249
262
|
|
250
263
|
# @api private
|
251
264
|
def boot_external(identifier, from:, key: nil, namespace: nil, &block)
|
252
|
-
|
265
|
+
System.providers[from].component(
|
253
266
|
identifier, key: key, namespace: namespace, finalize: block, container: self
|
254
267
|
)
|
255
|
-
|
256
|
-
booter.register_component(component)
|
257
|
-
|
258
|
-
component
|
259
268
|
end
|
260
269
|
|
261
270
|
# @api private
|
262
271
|
def boot_local(identifier, namespace: nil, &block)
|
263
|
-
|
272
|
+
Components::Bootable.new(
|
264
273
|
identifier, container: self, namespace: namespace, &block
|
265
274
|
)
|
266
|
-
|
267
|
-
booter.register_component(component)
|
268
|
-
|
269
|
-
component
|
270
275
|
end
|
271
276
|
|
272
277
|
# Return if a container was finalized
|
@@ -378,7 +383,7 @@ module Dry
|
|
378
383
|
self
|
379
384
|
end
|
380
385
|
|
381
|
-
#
|
386
|
+
# Adds the directories (relative to the container's root) to the Ruby load path
|
382
387
|
#
|
383
388
|
# @example
|
384
389
|
# class MyApp < Dry::System::Container
|
@@ -386,7 +391,7 @@ module Dry
|
|
386
391
|
# # ...
|
387
392
|
# end
|
388
393
|
#
|
389
|
-
#
|
394
|
+
# add_to_load_path!('lib')
|
390
395
|
# end
|
391
396
|
#
|
392
397
|
# @param [Array<String>] dirs
|
@@ -394,12 +399,9 @@ module Dry
|
|
394
399
|
# @return [self]
|
395
400
|
#
|
396
401
|
# @api public
|
397
|
-
def
|
398
|
-
dirs.map(&root.method(:join)).each do |path|
|
399
|
-
|
400
|
-
|
401
|
-
load_paths << path
|
402
|
-
$LOAD_PATH.unshift(path.to_s)
|
402
|
+
def add_to_load_path!(*dirs)
|
403
|
+
dirs.reverse.map(&root.method(:join)).each do |path|
|
404
|
+
$LOAD_PATH.prepend(path.to_s) unless $LOAD_PATH.include?(path.to_s)
|
403
405
|
end
|
404
406
|
self
|
405
407
|
end
|
@@ -410,47 +412,6 @@ module Dry
|
|
410
412
|
self
|
411
413
|
end
|
412
414
|
|
413
|
-
# Auto-registers components from the provided directory
|
414
|
-
#
|
415
|
-
# Typically you want to configure auto_register directories, and it will
|
416
|
-
# work automatically. Use this method in cases where you want to have an
|
417
|
-
# explicit way where some components are auto-registered, or if you want
|
418
|
-
# to exclude some components from being auto-registered
|
419
|
-
#
|
420
|
-
# @example
|
421
|
-
# class MyApp < Dry::System::Container
|
422
|
-
# configure do |config|
|
423
|
-
# # ...
|
424
|
-
# end
|
425
|
-
#
|
426
|
-
# # with a dir
|
427
|
-
# auto_register!('lib/core')
|
428
|
-
#
|
429
|
-
# # with a dir and a custom registration block
|
430
|
-
# auto_register!('lib/core') do |config|
|
431
|
-
# config.instance do |component|
|
432
|
-
# # custom way of initializing a component
|
433
|
-
# end
|
434
|
-
#
|
435
|
-
# config.exclude do |component|
|
436
|
-
# # return true to exclude component from auto-registration
|
437
|
-
# end
|
438
|
-
# end
|
439
|
-
# end
|
440
|
-
#
|
441
|
-
# @param [String] dir The dir name relative to the root dir
|
442
|
-
#
|
443
|
-
# @yield AutoRegistrar::Configuration
|
444
|
-
# @see AutoRegistrar::Configuration
|
445
|
-
#
|
446
|
-
# @return [self]
|
447
|
-
#
|
448
|
-
# @api public
|
449
|
-
def auto_register!(dir, &block)
|
450
|
-
auto_registrar.(dir, &block)
|
451
|
-
self
|
452
|
-
end
|
453
|
-
|
454
415
|
# Builds injector for this container
|
455
416
|
#
|
456
417
|
# An injector is a useful mixin which injects dependencies into
|
@@ -476,7 +437,7 @@ module Dry
|
|
476
437
|
# @param options [Hash] injector options
|
477
438
|
#
|
478
439
|
# @api public
|
479
|
-
def injector(options = {
|
440
|
+
def injector(options = {strategies: strategies})
|
480
441
|
Dry::AutoInject(self, options)
|
481
442
|
end
|
482
443
|
|
@@ -494,7 +455,7 @@ module Dry
|
|
494
455
|
# @api public
|
495
456
|
def require_from_root(*paths)
|
496
457
|
paths.flat_map { |path|
|
497
|
-
path.to_s.include?(
|
458
|
+
path.to_s.include?("*") ? ::Dir[root.join(path)].sort : root.join(path)
|
498
459
|
}.each { |path|
|
499
460
|
Kernel.require path.to_s
|
500
461
|
}
|
@@ -519,8 +480,8 @@ module Dry
|
|
519
480
|
end
|
520
481
|
|
521
482
|
# @api public
|
522
|
-
def resolve(key
|
523
|
-
load_component(key
|
483
|
+
def resolve(key)
|
484
|
+
load_component(key) unless finalized?
|
524
485
|
|
525
486
|
super
|
526
487
|
end
|
@@ -551,18 +512,26 @@ module Dry
|
|
551
512
|
end
|
552
513
|
|
553
514
|
# @api private
|
554
|
-
def
|
555
|
-
|
515
|
+
def component_dirs
|
516
|
+
config.component_dirs.to_a.map { |dir| ComponentDir.new(config: dir, container: self) }
|
556
517
|
end
|
557
518
|
|
558
519
|
# @api private
|
559
520
|
def booter
|
560
|
-
@booter ||= config.booter.new(
|
521
|
+
@booter ||= config.booter.new(boot_paths)
|
561
522
|
end
|
562
523
|
|
563
524
|
# @api private
|
564
|
-
def
|
565
|
-
|
525
|
+
def boot_paths
|
526
|
+
config.bootable_dirs.map { |dir|
|
527
|
+
dir = Pathname(dir)
|
528
|
+
|
529
|
+
if dir.relative?
|
530
|
+
root.join(dir)
|
531
|
+
else
|
532
|
+
dir
|
533
|
+
end
|
534
|
+
}
|
566
535
|
end
|
567
536
|
|
568
537
|
# @api private
|
@@ -580,67 +549,6 @@ module Dry
|
|
580
549
|
@importer ||= config.importer.new(self)
|
581
550
|
end
|
582
551
|
|
583
|
-
# @api private
|
584
|
-
def component(identifier, **options)
|
585
|
-
if (component = booter.components.detect { |c| c.identifier == identifier })
|
586
|
-
component
|
587
|
-
else
|
588
|
-
Component.new(
|
589
|
-
identifier,
|
590
|
-
loader: config.loader,
|
591
|
-
namespace: config.default_namespace,
|
592
|
-
separator: config.namespace_separator,
|
593
|
-
inflector: config.inflector,
|
594
|
-
**options
|
595
|
-
)
|
596
|
-
end
|
597
|
-
end
|
598
|
-
|
599
|
-
# @api private
|
600
|
-
def require_component(component)
|
601
|
-
return if registered?(component.identifier)
|
602
|
-
|
603
|
-
raise FileNotFoundError, component unless component.file_exists?(load_paths)
|
604
|
-
|
605
|
-
require_path(component.path)
|
606
|
-
|
607
|
-
yield
|
608
|
-
end
|
609
|
-
|
610
|
-
# Allows subclasses to use a different strategy for required files.
|
611
|
-
#
|
612
|
-
# E.g. apps that use `ActiveSupport::Dependencies::Loadable#require_dependency`
|
613
|
-
# will override this method to allow container managed dependencies to be reloaded
|
614
|
-
# for non-finalized containers.
|
615
|
-
#
|
616
|
-
# @api private
|
617
|
-
def require_path(path)
|
618
|
-
require path
|
619
|
-
end
|
620
|
-
|
621
|
-
# @api private
|
622
|
-
def load_component(key, &block)
|
623
|
-
return self if registered?(key)
|
624
|
-
|
625
|
-
component(key).tap do |component|
|
626
|
-
if component.boot?
|
627
|
-
booter.start(component)
|
628
|
-
else
|
629
|
-
root_key = component.root_key
|
630
|
-
|
631
|
-
if (bootable_dep = component(root_key)).boot?
|
632
|
-
booter.start(bootable_dep)
|
633
|
-
elsif importer.key?(root_key)
|
634
|
-
load_imported_component(component.namespaced(root_key))
|
635
|
-
end
|
636
|
-
|
637
|
-
load_local_component(component, &block) unless registered?(key)
|
638
|
-
end
|
639
|
-
end
|
640
|
-
|
641
|
-
self
|
642
|
-
end
|
643
|
-
|
644
552
|
# @api private
|
645
553
|
def after(event, &block)
|
646
554
|
hooks[:"after_#{event}"] << block
|
@@ -657,46 +565,87 @@ module Dry
|
|
657
565
|
|
658
566
|
# @api private
|
659
567
|
def inherited(klass)
|
660
|
-
new_hooks = Container.hooks.dup
|
661
|
-
|
662
568
|
hooks.each do |event, blocks|
|
663
|
-
|
664
|
-
new_hooks[event].concat(klass.hooks[event])
|
569
|
+
klass.hooks[event].concat blocks.dup
|
665
570
|
end
|
666
571
|
|
667
|
-
klass.instance_variable_set(:@hooks, new_hooks)
|
668
572
|
klass.instance_variable_set(:@__finalized__, false)
|
573
|
+
|
669
574
|
super
|
670
575
|
end
|
671
576
|
|
672
|
-
|
577
|
+
protected
|
673
578
|
|
674
579
|
# @api private
|
675
|
-
def
|
676
|
-
|
677
|
-
booter.boot_dependency(component) unless finalized?
|
580
|
+
def load_component(key)
|
581
|
+
return self if registered?(key)
|
678
582
|
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
583
|
+
component = component(key)
|
584
|
+
|
585
|
+
if component.bootable?
|
586
|
+
booter.start(component)
|
587
|
+
return self
|
588
|
+
end
|
589
|
+
|
590
|
+
booter.boot_dependency(component)
|
591
|
+
return self if registered?(key)
|
592
|
+
|
593
|
+
if component.file_exists?
|
594
|
+
load_local_component(component)
|
684
595
|
elsif manual_registrar.file_exists?(component)
|
685
596
|
manual_registrar.(component)
|
686
|
-
elsif
|
687
|
-
|
688
|
-
else
|
689
|
-
raise ComponentLoadError, component
|
597
|
+
elsif importer.key?(component.identifier.root_key)
|
598
|
+
load_imported_component(component.identifier)
|
690
599
|
end
|
600
|
+
|
601
|
+
self
|
691
602
|
end
|
692
603
|
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
604
|
+
private
|
605
|
+
|
606
|
+
def load_local_component(component)
|
607
|
+
if component.auto_register?
|
608
|
+
register(component.identifier, memoize: component.memoize?) { component.instance }
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
def load_imported_component(identifier)
|
613
|
+
import_namespace = identifier.root_key
|
614
|
+
|
615
|
+
container = importer[import_namespace]
|
616
|
+
|
617
|
+
container.load_component(identifier.dequalified(import_namespace).key)
|
618
|
+
|
619
|
+
importer.(import_namespace, container)
|
620
|
+
end
|
621
|
+
|
622
|
+
def component(identifier)
|
623
|
+
if (bootable_component = booter.find_component(identifier))
|
624
|
+
return bootable_component
|
625
|
+
end
|
626
|
+
|
627
|
+
# Find the first matching component from within the configured component dirs.
|
628
|
+
# If no matching component is found, return a plain component instance with no
|
629
|
+
# associated file path. This fallback is important because the component may
|
630
|
+
# still be loadable via the manual registrar or an imported container.
|
631
|
+
component_dirs.detect { |dir|
|
632
|
+
if (component = dir.component_for_identifier(identifier))
|
633
|
+
break component
|
634
|
+
end
|
635
|
+
} || Component.new(identifier)
|
698
636
|
end
|
699
637
|
end
|
638
|
+
|
639
|
+
# Default hooks
|
640
|
+
after :configure do
|
641
|
+
# Add appropriately configured component dirs to the load path
|
642
|
+
#
|
643
|
+
# Do this in a single pass to preserve ordering (i.e. earliest dirs win)
|
644
|
+
paths = config.component_dirs.to_a.each_with_object([]) { |dir, arr|
|
645
|
+
arr << dir.path if dir.add_to_load_path
|
646
|
+
}
|
647
|
+
add_to_load_path!(*paths)
|
648
|
+
end
|
700
649
|
end
|
701
650
|
end
|
702
651
|
end
|