dry-system 0.20.0 → 0.21.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 +32 -0
- data/README.md +1 -1
- data/lib/dry/system/auto_registrar.rb +1 -13
- data/lib/dry/system/booter/component_registry.rb +3 -3
- data/lib/dry/system/booter.rb +4 -4
- data/lib/dry/system/component.rb +103 -45
- data/lib/dry/system/component_dir.rb +112 -45
- data/lib/dry/system/components/bootable.rb +10 -19
- data/lib/dry/system/config/component_dir.rb +70 -38
- data/lib/dry/system/config/component_dirs.rb +28 -41
- data/lib/dry/system/config/namespace.rb +71 -0
- data/lib/dry/system/config/namespaces.rb +121 -0
- data/lib/dry/system/constants.rb +1 -1
- data/lib/dry/system/container.rb +25 -29
- data/lib/dry/system/errors.rb +11 -20
- data/lib/dry/system/identifier.rb +57 -80
- data/lib/dry/system/indirect_component.rb +65 -0
- data/lib/dry/system/loader.rb +2 -3
- data/lib/dry/system/manual_registrar.rb +4 -8
- data/lib/dry/system/plugins.rb +1 -3
- data/lib/dry/system/provider.rb +6 -6
- data/lib/dry/system/provider_registry.rb +4 -4
- data/lib/dry/system/settings.rb +1 -4
- data/lib/dry/system/version.rb +1 -1
- data/lib/dry/system.rb +5 -5
- metadata +5 -2
@@ -1,5 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "dry/configurable"
|
4
|
+
require "dry/core/deprecations"
|
5
|
+
require "dry/system/constants"
|
2
6
|
require "dry/system/loader"
|
7
|
+
require_relative "namespaces"
|
3
8
|
|
4
9
|
module Dry
|
5
10
|
module System
|
@@ -27,7 +32,7 @@ module Dry
|
|
27
32
|
#
|
28
33
|
# @example
|
29
34
|
# dir.auto_register = proc do |component|
|
30
|
-
# !component.start_with?("entities")
|
35
|
+
# !component.identifier.start_with?("entities")
|
31
36
|
# end
|
32
37
|
#
|
33
38
|
# @see auto_register
|
@@ -65,39 +70,10 @@ module Dry
|
|
65
70
|
# @see add_to_load_path=
|
66
71
|
setting :add_to_load_path, default: true
|
67
72
|
|
68
|
-
# @!method default_namespace=(leading_namespace)
|
69
|
-
#
|
70
|
-
# Sets the leading namespace segments to be stripped when registering components
|
71
|
-
# from the dir in the container.
|
72
|
-
#
|
73
|
-
# This is useful to configure when the dir contains components in a module
|
74
|
-
# namespace that you don't want repeated in their identifiers.
|
75
|
-
#
|
76
|
-
# Defaults to `nil`.
|
77
|
-
#
|
78
|
-
# @param leading_namespace [String, nil]
|
79
|
-
# @return [String, nil]
|
80
|
-
#
|
81
|
-
# @example
|
82
|
-
# dir.default_namespace = "my_app"
|
83
|
-
#
|
84
|
-
# @example
|
85
|
-
# dir.default_namespace = "my_app.admin"
|
86
|
-
#
|
87
|
-
# @see default_namespace
|
88
|
-
#
|
89
|
-
# @!method default_namespace
|
90
|
-
#
|
91
|
-
# Returns the configured value.
|
92
|
-
#
|
93
|
-
# @return [String, nil]
|
94
|
-
#
|
95
|
-
# @see default_namespace=
|
96
|
-
setting :default_namespace
|
97
|
-
|
98
73
|
# @!method loader=(loader)
|
99
74
|
#
|
100
|
-
# Sets the loader to use when registering
|
75
|
+
# Sets the loader to use when registering components from the dir in the
|
76
|
+
# container.
|
101
77
|
#
|
102
78
|
# Defaults to `Dry::System::Loader`.
|
103
79
|
#
|
@@ -138,7 +114,7 @@ module Dry
|
|
138
114
|
#
|
139
115
|
# @example
|
140
116
|
# dir.memoize = proc do |component|
|
141
|
-
# !component.start_with?("providers")
|
117
|
+
# !component.identifier.start_with?("providers")
|
142
118
|
# end
|
143
119
|
#
|
144
120
|
# @see memoize
|
@@ -153,6 +129,49 @@ module Dry
|
|
153
129
|
# @see memoize=
|
154
130
|
setting :memoize, default: false
|
155
131
|
|
132
|
+
# @!method namespaces
|
133
|
+
#
|
134
|
+
# Returns the configured namespaces for the component dir.
|
135
|
+
#
|
136
|
+
# Allows namespaces to added on the returned object via {Namespaces#add}.
|
137
|
+
#
|
138
|
+
# @see Namespaces#add
|
139
|
+
#
|
140
|
+
# @return [Namespaces] the namespaces
|
141
|
+
setting :namespaces, default: Namespaces.new, cloneable: true
|
142
|
+
|
143
|
+
def default_namespace=(namespace)
|
144
|
+
Dry::Core::Deprecations.announce(
|
145
|
+
"Dry::System::Config::ComponentDir#default_namespace=",
|
146
|
+
"Add a namespace instead: `dir.namespaces.add #{namespace.to_s.inspect}, key: nil`",
|
147
|
+
tag: "dry-system",
|
148
|
+
uplevel: 1
|
149
|
+
)
|
150
|
+
|
151
|
+
# We don't have the configured separator here, so the best we can do is guess
|
152
|
+
# that it's a dot
|
153
|
+
namespace_path = namespace.gsub(".", PATH_SEPARATOR)
|
154
|
+
|
155
|
+
return if namespaces.namespaces[namespace_path]
|
156
|
+
|
157
|
+
namespaces.add namespace_path, key: nil
|
158
|
+
end
|
159
|
+
|
160
|
+
def default_namespace
|
161
|
+
Dry::Core::Deprecations.announce(
|
162
|
+
"Dry::System::Config::ComponentDir#default_namespace",
|
163
|
+
"Use namespaces instead, e.g. `dir.namespaces`",
|
164
|
+
tag: "dry-system",
|
165
|
+
uplevel: 1
|
166
|
+
)
|
167
|
+
|
168
|
+
ns_path = namespaces.to_a.reject(&:root?).first&.path
|
169
|
+
|
170
|
+
# We don't have the configured separator here, so the best we can do is guess
|
171
|
+
# that it's a dot
|
172
|
+
ns_path&.gsub(PATH_SEPARATOR, ".")
|
173
|
+
end
|
174
|
+
|
156
175
|
# @!endgroup
|
157
176
|
|
158
177
|
# Returns the component dir path, relative to the configured container root
|
@@ -172,15 +191,28 @@ module Dry
|
|
172
191
|
!!config.auto_register
|
173
192
|
end
|
174
193
|
|
175
|
-
# Returns true if
|
176
|
-
# just a default value.
|
194
|
+
# Returns true if the given setting has been explicitly configured by the user
|
177
195
|
#
|
178
|
-
# This is used
|
179
|
-
#
|
196
|
+
# This is used when determining whether to apply system-wide default values to a
|
197
|
+
# component dir (explicitly configured settings will not be overridden by
|
198
|
+
# defaults)
|
180
199
|
#
|
200
|
+
# @param key [Symbol] the setting name
|
201
|
+
#
|
202
|
+
# @return [Boolean]
|
203
|
+
#
|
204
|
+
# @see Dry::System::Config::ComponentDirs#apply_defaults_to_dir
|
181
205
|
# @api private
|
182
206
|
def configured?(key)
|
183
|
-
|
207
|
+
case key
|
208
|
+
when :namespaces
|
209
|
+
# Because we mutate the default value for the `namespaces` setting, rather
|
210
|
+
# than assign a new one, to check if it's configured we must see whether any
|
211
|
+
# namespaces have been added
|
212
|
+
!config.namespaces.empty?
|
213
|
+
else
|
214
|
+
config._settings[key].input_defined?
|
215
|
+
end
|
184
216
|
end
|
185
217
|
|
186
218
|
private
|
@@ -1,5 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "concurrent/map"
|
2
|
-
require "dry/configurable"
|
3
4
|
require "dry/system/constants"
|
4
5
|
require "dry/system/errors"
|
5
6
|
require_relative "component_dir"
|
@@ -8,13 +9,6 @@ module Dry
|
|
8
9
|
module System
|
9
10
|
module Config
|
10
11
|
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
12
|
# @!group Settings
|
19
13
|
|
20
14
|
# @!method auto_register=(value)
|
@@ -43,19 +37,6 @@ module Dry
|
|
43
37
|
#
|
44
38
|
# @see add_to_load_path=
|
45
39
|
|
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
40
|
# @!method loader=(value)
|
60
41
|
#
|
61
42
|
# Sets a default `loader` value for all added component dirs
|
@@ -82,17 +63,34 @@ module Dry
|
|
82
63
|
#
|
83
64
|
# @see memoize=
|
84
65
|
|
66
|
+
# @!method namespaces
|
67
|
+
#
|
68
|
+
# Returns the default configured namespaces for all added component dirs
|
69
|
+
#
|
70
|
+
# Allows namespaces to added on the returned object via {Namespaces#add}.
|
71
|
+
#
|
72
|
+
# @see Namespaces#add
|
73
|
+
#
|
74
|
+
# @return [Namespaces] the namespaces
|
75
|
+
|
85
76
|
# @!endgroup
|
86
77
|
|
78
|
+
# A ComponentDir for configuring the default values to apply to all added
|
79
|
+
# component dirs
|
80
|
+
#
|
81
|
+
# @api private
|
82
|
+
attr_reader :defaults
|
83
|
+
|
87
84
|
# @api private
|
88
85
|
def initialize
|
89
86
|
@dirs = Concurrent::Map.new
|
87
|
+
@defaults = ComponentDir.new(nil)
|
90
88
|
end
|
91
89
|
|
92
90
|
# @api private
|
93
91
|
def initialize_copy(source)
|
94
|
-
super
|
95
92
|
@dirs = source.dirs.dup
|
93
|
+
@defaults = source.defaults.dup
|
96
94
|
end
|
97
95
|
|
98
96
|
# Adds and configures a component dir
|
@@ -114,8 +112,8 @@ module Dry
|
|
114
112
|
raise ComponentDirAlreadyAddedError, path if dirs.key?(path)
|
115
113
|
|
116
114
|
dirs[path] = ComponentDir.new(path).tap do |dir|
|
117
|
-
apply_defaults_to_dir(dir)
|
118
115
|
yield dir if block_given?
|
116
|
+
apply_defaults_to_dir(dir)
|
119
117
|
end
|
120
118
|
end
|
121
119
|
|
@@ -143,40 +141,29 @@ module Dry
|
|
143
141
|
|
144
142
|
private
|
145
143
|
|
146
|
-
#
|
144
|
+
# Applies default settings to a component dir. This is run every time the dirs are
|
147
145
|
# accessed to ensure defaults are applied regardless of when new component dirs
|
148
146
|
# are added. This method must be idempotent.
|
149
147
|
#
|
150
148
|
# @return [void]
|
151
149
|
def apply_defaults_to_dir(dir)
|
152
|
-
|
153
|
-
if configured?(key) && !dir.configured?(key)
|
154
|
-
dir.public_send(:"#{key}=", public_send(key))
|
150
|
+
defaults.config.values.each do |key, _|
|
151
|
+
if defaults.configured?(key) && !dir.configured?(key)
|
152
|
+
dir.public_send(:"#{key}=", defaults.public_send(key).dup)
|
155
153
|
end
|
156
154
|
end
|
157
155
|
end
|
158
156
|
|
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
157
|
def method_missing(name, *args, &block)
|
171
|
-
if
|
172
|
-
|
158
|
+
if defaults.respond_to?(name)
|
159
|
+
defaults.public_send(name, *args, &block)
|
173
160
|
else
|
174
161
|
super
|
175
162
|
end
|
176
163
|
end
|
177
164
|
|
178
165
|
def respond_to_missing?(name, include_all = false)
|
179
|
-
|
166
|
+
defaults.respond_to?(name) || super
|
180
167
|
end
|
181
168
|
end
|
182
169
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/core/equalizer"
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
module System
|
7
|
+
module Config
|
8
|
+
# A configured namespace for a component dir
|
9
|
+
#
|
10
|
+
# Namespaces consist of three elements:
|
11
|
+
#
|
12
|
+
# - The `path` within the component dir to which its namespace rules should apply.
|
13
|
+
# - A `key`, which determines the leading part of the key used to register
|
14
|
+
# each component in the container.
|
15
|
+
# - A `const`, which is the Ruby namespace expected to contain the class constants
|
16
|
+
# defined within each component's source file. This value is expected to be an
|
17
|
+
# "underscored" string, intended to be run through the configured inflector to be
|
18
|
+
# converted into a real constant (e.g. `"foo_bar/baz"` will become `FooBar::Baz`)
|
19
|
+
#
|
20
|
+
# Namespaces are added and configured for a component dir via {Namespaces#add}.
|
21
|
+
#
|
22
|
+
# @see Namespaces#add
|
23
|
+
#
|
24
|
+
# @api private
|
25
|
+
class Namespace
|
26
|
+
ROOT_PATH = nil
|
27
|
+
|
28
|
+
include Dry::Equalizer(:path, :key, :const)
|
29
|
+
|
30
|
+
attr_reader :path
|
31
|
+
|
32
|
+
attr_reader :key
|
33
|
+
|
34
|
+
attr_reader :const
|
35
|
+
|
36
|
+
# Returns a namespace configured to serve as the default root namespace for a
|
37
|
+
# component dir, ensuring that all code within the dir can be loaded, regardless
|
38
|
+
# of any other explictly configured namespaces
|
39
|
+
#
|
40
|
+
# @return [Namespace] the root namespace
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
def self.default_root
|
44
|
+
new(
|
45
|
+
path: ROOT_PATH,
|
46
|
+
key: nil,
|
47
|
+
const: nil
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize(path:, key:, const:)
|
52
|
+
@path = path
|
53
|
+
@key = key
|
54
|
+
@const = const
|
55
|
+
end
|
56
|
+
|
57
|
+
def root?
|
58
|
+
path == ROOT_PATH
|
59
|
+
end
|
60
|
+
|
61
|
+
def path?
|
62
|
+
!root?
|
63
|
+
end
|
64
|
+
|
65
|
+
def default_key?
|
66
|
+
key == path
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/system/errors"
|
4
|
+
require_relative "namespace"
|
5
|
+
|
6
|
+
module Dry
|
7
|
+
module System
|
8
|
+
module Config
|
9
|
+
# The configured namespaces for a ComponentDir
|
10
|
+
#
|
11
|
+
# @see Config::ComponentDir#namespaces
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
class Namespaces
|
15
|
+
# @api private
|
16
|
+
attr_reader :namespaces
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
def initialize
|
20
|
+
@namespaces = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
# @api private
|
24
|
+
def initialize_copy(source)
|
25
|
+
super
|
26
|
+
@namespaces = source.namespaces.dup
|
27
|
+
end
|
28
|
+
|
29
|
+
# rubocop:disable Layout/LineLength
|
30
|
+
|
31
|
+
# Adds a component dir namespace
|
32
|
+
#
|
33
|
+
# A namespace encompasses a given sub-directory of the component dir, and
|
34
|
+
# determines (1) the leading segments of its components' registered identifiers,
|
35
|
+
# and (2) the expected constant namespace of their class constants.
|
36
|
+
#
|
37
|
+
# A namespace for a path can only be added once.
|
38
|
+
#
|
39
|
+
# @example Adding a namespace with top-level identifiers
|
40
|
+
# # Components defined within admin/ (e.g. admin/my_component.rb) will be:
|
41
|
+
# #
|
42
|
+
# # - Registered with top-level identifiers ("my_component")
|
43
|
+
# # - Expected to have constants in `Admin`, matching the namespace's path (Admin::MyComponent)
|
44
|
+
#
|
45
|
+
# namespaces.add "admin", key: nil
|
46
|
+
#
|
47
|
+
# @example Adding a namespace with top-level class constants
|
48
|
+
# # Components defined within adapters/ (e.g. adapters/my_adapter.rb) will be:
|
49
|
+
# #
|
50
|
+
# # - Registered with leading identifiers matching the namespace's path ("adapters.my_adapter")
|
51
|
+
# # - Expected to have top-level constants (::MyAdapter)
|
52
|
+
#
|
53
|
+
# namespaces.add "adapters", const: nil
|
54
|
+
#
|
55
|
+
# @example Adding a namespace with distinct identifiers and class constants
|
56
|
+
# # Components defined within `bananas/` (e.g. bananas/banana_split.rb) will be:
|
57
|
+
# #
|
58
|
+
# # - Registered with the given leading identifier ("desserts.banana_split")
|
59
|
+
# # - Expected to have constants within the given namespace (EatMe::Now::BananaSplit)
|
60
|
+
#
|
61
|
+
# namespaces.add "bananas", key: "desserts", const: "eat_me/now"
|
62
|
+
#
|
63
|
+
# @param path [String] the path to the sub-directory of source files to which this
|
64
|
+
# namespace should apply, relative to the component dir
|
65
|
+
# @param identifier [String, nil] the leading namespace to apply to the registered
|
66
|
+
# identifiers for the components. Set `nil` for the identifiers to be top-level.
|
67
|
+
# @param const [String, nil] the Ruby constant namespace to expect for constants
|
68
|
+
# defined within the components. This should be provided in underscored string
|
69
|
+
# form, e.g. "hello_there/world" for a Ruby constant of `HelloThere::World`. Set
|
70
|
+
# `nil` for the constants to be top-level.
|
71
|
+
#
|
72
|
+
# @return [Namespace] the added namespace
|
73
|
+
#
|
74
|
+
# @see Namespace
|
75
|
+
#
|
76
|
+
# @api public
|
77
|
+
def add(path, key: path, const: path)
|
78
|
+
raise NamespaceAlreadyAddedError, path if namespaces.key?(path)
|
79
|
+
|
80
|
+
namespaces[path] = Namespace.new(path: path, key: key, const: const)
|
81
|
+
end
|
82
|
+
|
83
|
+
# rubocop:enable Layout/LineLength
|
84
|
+
|
85
|
+
# Adds a root component dir namespace
|
86
|
+
#
|
87
|
+
# @see #add
|
88
|
+
#
|
89
|
+
# @api public
|
90
|
+
def root(key: nil, const: nil)
|
91
|
+
add(Namespace::ROOT_PATH, key: key, const: const)
|
92
|
+
end
|
93
|
+
|
94
|
+
# @api private
|
95
|
+
def empty?
|
96
|
+
namespaces.empty?
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns the configured namespaces as an array
|
100
|
+
#
|
101
|
+
# This adds a root namespace to the end of the array if one was not configured
|
102
|
+
# manually. This fallback ensures that all components in the component dir can be
|
103
|
+
# loaded.
|
104
|
+
#
|
105
|
+
# @return [Array<Namespace>] the namespaces
|
106
|
+
#
|
107
|
+
# @api private
|
108
|
+
def to_a
|
109
|
+
namespaces.values.tap do |arr|
|
110
|
+
arr << Namespace.default_root unless arr.any?(&:root?)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# @api private
|
115
|
+
def each(&block)
|
116
|
+
to_a.each(&block)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/lib/dry/system/constants.rb
CHANGED
data/lib/dry/system/container.rb
CHANGED
@@ -11,13 +11,15 @@ require "dry/core/constants"
|
|
11
11
|
require "dry/core/deprecations"
|
12
12
|
|
13
13
|
require "dry/system"
|
14
|
-
require "dry/system/errors"
|
15
|
-
require "dry/system/booter"
|
16
14
|
require "dry/system/auto_registrar"
|
17
|
-
require "dry/system/
|
18
|
-
require "dry/system/importer"
|
15
|
+
require "dry/system/booter"
|
19
16
|
require "dry/system/component"
|
20
17
|
require "dry/system/constants"
|
18
|
+
require "dry/system/errors"
|
19
|
+
require "dry/system/identifier"
|
20
|
+
require "dry/system/importer"
|
21
|
+
require "dry/system/indirect_component"
|
22
|
+
require "dry/system/manual_registrar"
|
21
23
|
require "dry/system/plugins"
|
22
24
|
|
23
25
|
require_relative "component_dir"
|
@@ -49,7 +51,7 @@ module Dry
|
|
49
51
|
#
|
50
52
|
# Every container needs to be configured with following settings:
|
51
53
|
#
|
52
|
-
# * `:name` - a unique container
|
54
|
+
# * `:name` - a unique container name
|
53
55
|
# * `:root` - a system root directory (defaults to `pwd`)
|
54
56
|
#
|
55
57
|
# @example
|
@@ -234,7 +236,7 @@ module Dry
|
|
234
236
|
# persistence.register(:db, DB.new)
|
235
237
|
# end
|
236
238
|
#
|
237
|
-
# @param name [Symbol] a unique
|
239
|
+
# @param name [Symbol] a unique name for a bootable component
|
238
240
|
#
|
239
241
|
# @see Lifecycle
|
240
242
|
#
|
@@ -262,17 +264,15 @@ module Dry
|
|
262
264
|
deprecate :finalize, :boot
|
263
265
|
|
264
266
|
# @api private
|
265
|
-
def boot_external(
|
267
|
+
def boot_external(name, from:, key: nil, namespace: nil, &block)
|
266
268
|
System.providers[from].component(
|
267
|
-
|
269
|
+
name, key: key, namespace: namespace, finalize: block, container: self
|
268
270
|
)
|
269
271
|
end
|
270
272
|
|
271
273
|
# @api private
|
272
|
-
def boot_local(
|
273
|
-
Components::Bootable.new(
|
274
|
-
identifier, container: self, namespace: namespace, &block
|
275
|
-
)
|
274
|
+
def boot_local(name, namespace: nil, &block)
|
275
|
+
Components::Bootable.new(name, container: self, namespace: namespace, &block)
|
276
276
|
end
|
277
277
|
|
278
278
|
# Return if a container was finalized
|
@@ -491,7 +491,7 @@ module Dry
|
|
491
491
|
#
|
492
492
|
# @!method registered?(key)
|
493
493
|
# Whether a +key+ is registered (doesn't trigger loading)
|
494
|
-
# @param [String,Symbol] key
|
494
|
+
# @param [String,Symbol] key The key
|
495
495
|
# @return [Boolean]
|
496
496
|
# @api public
|
497
497
|
#
|
@@ -581,17 +581,17 @@ module Dry
|
|
581
581
|
def load_component(key)
|
582
582
|
return self if registered?(key)
|
583
583
|
|
584
|
-
|
585
|
-
|
586
|
-
if component.bootable?
|
587
|
-
booter.start(component)
|
584
|
+
if (bootable_component = booter.find_component(key))
|
585
|
+
booter.start(bootable_component)
|
588
586
|
return self
|
589
587
|
end
|
590
588
|
|
589
|
+
component = find_component(key)
|
590
|
+
|
591
591
|
booter.boot_dependency(component)
|
592
592
|
return self if registered?(key)
|
593
593
|
|
594
|
-
if component.
|
594
|
+
if component.loadable?
|
595
595
|
load_local_component(component)
|
596
596
|
elsif manual_registrar.file_exists?(component)
|
597
597
|
manual_registrar.(component)
|
@@ -615,25 +615,21 @@ module Dry
|
|
615
615
|
|
616
616
|
container = importer[import_namespace]
|
617
617
|
|
618
|
-
container.load_component(identifier.
|
618
|
+
container.load_component(identifier.namespaced(from: import_namespace, to: nil).key)
|
619
619
|
|
620
620
|
importer.(import_namespace, container)
|
621
621
|
end
|
622
622
|
|
623
|
-
def
|
624
|
-
if (bootable_component = booter.find_component(identifier))
|
625
|
-
return bootable_component
|
626
|
-
end
|
627
|
-
|
623
|
+
def find_component(key)
|
628
624
|
# Find the first matching component from within the configured component dirs.
|
629
|
-
# If no matching component is found, return a
|
630
|
-
#
|
631
|
-
#
|
625
|
+
# If no matching component is found, return a null component; this fallback is
|
626
|
+
# important because the component may still be loadable via the manual registrar
|
627
|
+
# or an imported container.
|
632
628
|
component_dirs.detect { |dir|
|
633
|
-
if (component = dir.
|
629
|
+
if (component = dir.component_for_key(key))
|
634
630
|
break component
|
635
631
|
end
|
636
|
-
} ||
|
632
|
+
} || IndirectComponent.new(Identifier.new(key, separator: config.namespace_separator))
|
637
633
|
end
|
638
634
|
end
|
639
635
|
|
data/lib/dry/system/errors.rb
CHANGED
@@ -11,13 +11,13 @@ module Dry
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
# Error raised when
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
super("
|
14
|
+
# Error raised when a namespace for a component dir is added to configuration more
|
15
|
+
# than once
|
16
|
+
NamespaceAlreadyAddedError = Class.new(StandardError) do
|
17
|
+
def initialize(path)
|
18
|
+
path_label = path ? "path #{path.inspect}" : "root path"
|
19
|
+
|
20
|
+
super("Namespace for #{path_label} already added")
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -27,7 +27,7 @@ module Dry
|
|
27
27
|
ComponentFileMismatchError = Class.new(StandardError) do
|
28
28
|
def initialize(component)
|
29
29
|
super(<<-STR)
|
30
|
-
Bootable component '#{component.
|
30
|
+
Bootable component '#{component.name}' not found
|
31
31
|
STR
|
32
32
|
end
|
33
33
|
end
|
@@ -43,26 +43,17 @@ module Dry
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
# Error raised when component's
|
46
|
+
# Error raised when component's name is not valid
|
47
47
|
#
|
48
48
|
# @api public
|
49
|
-
|
49
|
+
InvalidComponentNameError = Class.new(ArgumentError) do
|
50
50
|
def initialize(name)
|
51
51
|
super(
|
52
|
-
"component
|
52
|
+
"component +#{name}+ is invalid or boot file is missing"
|
53
53
|
)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
# Error raised when component's identifier for booting is not a symbol
|
58
|
-
#
|
59
|
-
# @api public
|
60
|
-
InvalidComponentIdentifierTypeError = Class.new(ArgumentError) do
|
61
|
-
def initialize(name)
|
62
|
-
super("component identifier #{name.inspect} must be a symbol")
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
57
|
# Error raised when trying to stop a component that hasn't started yet
|
67
58
|
#
|
68
59
|
# @api public
|