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