dry-system 0.18.1 → 1.0.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 +678 -0
- data/LICENSE +1 -1
- data/README.md +5 -4
- data/dry-system.gemspec +18 -21
- data/lib/dry/system/auto_registrar.rb +9 -64
- data/lib/dry/system/component.rb +124 -104
- data/lib/dry/system/component_dir.rb +171 -0
- data/lib/dry/system/config/component_dir.rb +228 -0
- data/lib/dry/system/config/component_dirs.rb +289 -0
- data/lib/dry/system/config/namespace.rb +75 -0
- data/lib/dry/system/config/namespaces.rb +196 -0
- data/lib/dry/system/constants.rb +2 -4
- data/lib/dry/system/container.rb +305 -345
- data/lib/dry/system/errors.rb +73 -56
- data/lib/dry/system/identifier.rb +176 -0
- data/lib/dry/system/importer.rb +89 -12
- data/lib/dry/system/indirect_component.rb +63 -0
- data/lib/dry/system/loader/autoloading.rb +24 -0
- data/lib/dry/system/loader.rb +49 -41
- data/lib/dry/system/{manual_registrar.rb → manifest_registrar.rb} +13 -14
- data/lib/dry/system/plugins/bootsnap.rb +3 -2
- data/lib/dry/system/plugins/dependency_graph/strategies.rb +38 -2
- data/lib/dry/system/plugins/dependency_graph.rb +25 -21
- data/lib/dry/system/plugins/env.rb +3 -2
- data/lib/dry/system/plugins/logging.rb +9 -8
- data/lib/dry/system/plugins/monitoring.rb +1 -2
- data/lib/dry/system/plugins/notifications.rb +1 -1
- data/lib/dry/system/plugins/plugin.rb +61 -0
- 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 +5 -73
- data/lib/dry/system/provider/source.rb +276 -0
- data/lib/dry/system/provider/source_dsl.rb +55 -0
- data/lib/dry/system/provider.rb +261 -23
- data/lib/dry/system/provider_registrar.rb +251 -0
- data/lib/dry/system/provider_source_registry.rb +56 -0
- data/lib/dry/system/provider_sources/settings/config.rb +73 -0
- data/lib/dry/system/provider_sources/settings/loader.rb +44 -0
- data/lib/dry/system/provider_sources/settings.rb +40 -0
- data/lib/dry/system/provider_sources.rb +5 -0
- data/lib/dry/system/stubs.rb +6 -2
- data/lib/dry/system/version.rb +1 -1
- data/lib/dry/system.rb +35 -13
- metadata +48 -97
- data/lib/dry/system/auto_registrar/configuration.rb +0 -43
- data/lib/dry/system/booter/component_registry.rb +0 -35
- data/lib/dry/system/booter.rb +0 -181
- data/lib/dry/system/components/bootable.rb +0 -289
- data/lib/dry/system/components/config.rb +0 -35
- data/lib/dry/system/components.rb +0 -8
- 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 -67
- data/lib/dry/system/system_components/settings.rb +0 -11
@@ -0,0 +1,228 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/system/constants"
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
module System
|
7
|
+
module Config
|
8
|
+
# @api public
|
9
|
+
class ComponentDir
|
10
|
+
include Dry::Configurable
|
11
|
+
|
12
|
+
# @!group Settings
|
13
|
+
|
14
|
+
# @!method auto_register=(policy)
|
15
|
+
#
|
16
|
+
# Sets the auto-registration policy for the component dir.
|
17
|
+
#
|
18
|
+
# This may be a simple boolean to enable or disable auto-registration for all
|
19
|
+
# components, or a proc accepting a {Dry::System::Component} and returning a
|
20
|
+
# boolean to configure auto-registration on a per-component basis
|
21
|
+
#
|
22
|
+
# Defaults to `true`.
|
23
|
+
#
|
24
|
+
# @param policy [Boolean, Proc]
|
25
|
+
# @return [Boolean, Proc]
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# dir.auto_register = false
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# dir.auto_register = proc do |component|
|
32
|
+
# !component.identifier.start_with?("entities")
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# @see auto_register
|
36
|
+
# @see Component
|
37
|
+
# @api public
|
38
|
+
#
|
39
|
+
# @!method auto_register
|
40
|
+
#
|
41
|
+
# Returns the configured auto-registration policy.
|
42
|
+
#
|
43
|
+
# @return [Boolean, Proc] the configured policy
|
44
|
+
#
|
45
|
+
# @see auto_register=
|
46
|
+
# @api public
|
47
|
+
setting :auto_register, default: true
|
48
|
+
|
49
|
+
# @!method instance=(instance_proc)
|
50
|
+
#
|
51
|
+
# Sets a proc used to return the instance of any component within the component
|
52
|
+
# dir.
|
53
|
+
#
|
54
|
+
# This proc should accept a {Dry::System::Component} and return the object to
|
55
|
+
# serve as the component's instance.
|
56
|
+
#
|
57
|
+
# When you provide an instance proc, it will be used in preference to the
|
58
|
+
# {loader} (either the default loader or an explicitly configured one). Provide
|
59
|
+
# an instance proc when you want a simple way to customize the instance for
|
60
|
+
# certain components. For complete control, provide a replacement loader via
|
61
|
+
# {loader=}.
|
62
|
+
#
|
63
|
+
# Defaults to `nil`.
|
64
|
+
#
|
65
|
+
# @param instance_proc [Proc, nil]
|
66
|
+
# @return [Proc]
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# dir.instance = proc do |component|
|
70
|
+
# if component.key.match?(/workers\./)
|
71
|
+
# # Register classes for jobs
|
72
|
+
# component.loader.constant(component)
|
73
|
+
# else
|
74
|
+
# # Otherwise register regular instances per default loader
|
75
|
+
# component.loader.call(component)
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# @see Component, Loader
|
80
|
+
# @api public
|
81
|
+
#
|
82
|
+
# @!method instance
|
83
|
+
#
|
84
|
+
# Returns the configured instance proc.
|
85
|
+
#
|
86
|
+
# @return [Proc, nil]
|
87
|
+
#
|
88
|
+
# @see instance=
|
89
|
+
# @api public
|
90
|
+
setting :instance
|
91
|
+
|
92
|
+
# @!method loader=(loader)
|
93
|
+
#
|
94
|
+
# Sets the loader to use when registering components from the dir in the
|
95
|
+
# container.
|
96
|
+
#
|
97
|
+
# Defaults to `Dry::System::Loader`.
|
98
|
+
#
|
99
|
+
# When using an autoloader like Zeitwerk, consider using
|
100
|
+
# `Dry::System::Loader::Autoloading`
|
101
|
+
#
|
102
|
+
# @param loader [#call] the loader
|
103
|
+
# @return [#call] the configured loader
|
104
|
+
#
|
105
|
+
# @see loader
|
106
|
+
# @see Loader
|
107
|
+
# @see Loader::Autoloading
|
108
|
+
# @api public
|
109
|
+
#
|
110
|
+
# @!method loader
|
111
|
+
#
|
112
|
+
# Returns the configured loader.
|
113
|
+
#
|
114
|
+
# @return [#call]
|
115
|
+
#
|
116
|
+
# @see loader=
|
117
|
+
# @api public
|
118
|
+
setting :loader, default: Dry::System::Loader
|
119
|
+
|
120
|
+
# @!method memoize=(policy)
|
121
|
+
#
|
122
|
+
# Sets whether to memoize components from the dir when registered in the
|
123
|
+
# container.
|
124
|
+
#
|
125
|
+
# This may be a simple boolean to enable or disable memoization for all
|
126
|
+
# components, or a proc accepting a `Dry::Sytem::Component` and returning a
|
127
|
+
# boolean to configure memoization on a per-component basis
|
128
|
+
#
|
129
|
+
# Defaults to `false`.
|
130
|
+
#
|
131
|
+
# @param policy [Boolean, Proc]
|
132
|
+
# @return [Boolean, Proc] the configured memoization policy
|
133
|
+
#
|
134
|
+
# @example
|
135
|
+
# dir.memoize = true
|
136
|
+
#
|
137
|
+
# @example
|
138
|
+
# dir.memoize = proc do |component|
|
139
|
+
# !component.identifier.start_with?("providers")
|
140
|
+
# end
|
141
|
+
#
|
142
|
+
# @see memoize
|
143
|
+
# @see Component
|
144
|
+
# @api public
|
145
|
+
#
|
146
|
+
# @!method memoize
|
147
|
+
#
|
148
|
+
# Returns the configured memoization policy.
|
149
|
+
#
|
150
|
+
# @return [Boolean, Proc] the configured memoization policy
|
151
|
+
#
|
152
|
+
# @see memoize=
|
153
|
+
# @api public
|
154
|
+
setting :memoize, default: false
|
155
|
+
|
156
|
+
# @!method namespaces
|
157
|
+
#
|
158
|
+
# Returns the configured namespaces for the component dir.
|
159
|
+
#
|
160
|
+
# Allows namespaces to added on the returned object via {Namespaces#add}.
|
161
|
+
#
|
162
|
+
# @return [Namespaces] the namespaces
|
163
|
+
#
|
164
|
+
# @see Namespaces#add
|
165
|
+
# @api public
|
166
|
+
setting :namespaces, default: Namespaces.new, cloneable: true
|
167
|
+
|
168
|
+
# @!method add_to_load_path=(policy)
|
169
|
+
#
|
170
|
+
# Sets whether the dir should be added to the `$LOAD_PATH` after the container
|
171
|
+
# is configured.
|
172
|
+
#
|
173
|
+
# Defaults to `true`. This may need to be set to `false` when using a class
|
174
|
+
# autoloading system.
|
175
|
+
#
|
176
|
+
# @param policy [Boolean]
|
177
|
+
# @return [Boolean]
|
178
|
+
#
|
179
|
+
# @see add_to_load_path
|
180
|
+
# @see Container.configure
|
181
|
+
# @api public
|
182
|
+
#
|
183
|
+
# @!method add_to_load_path
|
184
|
+
#
|
185
|
+
# Returns the configured value.
|
186
|
+
#
|
187
|
+
# @return [Boolean]
|
188
|
+
#
|
189
|
+
# @see add_to_load_path=
|
190
|
+
# @api public
|
191
|
+
setting :add_to_load_path, default: true
|
192
|
+
|
193
|
+
# @!endgroup
|
194
|
+
|
195
|
+
# Returns the component dir path, relative to the configured container root
|
196
|
+
#
|
197
|
+
# @return [String] the path
|
198
|
+
attr_reader :path
|
199
|
+
|
200
|
+
# @api public
|
201
|
+
def initialize(path)
|
202
|
+
super()
|
203
|
+
@path = path
|
204
|
+
yield self if block_given?
|
205
|
+
end
|
206
|
+
|
207
|
+
# @api private
|
208
|
+
def auto_register?
|
209
|
+
!!config.auto_register
|
210
|
+
end
|
211
|
+
|
212
|
+
private
|
213
|
+
|
214
|
+
def method_missing(name, *args, &block)
|
215
|
+
if config.respond_to?(name)
|
216
|
+
config.public_send(name, *args, &block)
|
217
|
+
else
|
218
|
+
super
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def respond_to_missing?(name, include_all = false)
|
223
|
+
config.respond_to?(name) || super
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
@@ -0,0 +1,289 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/system/constants"
|
4
|
+
require "dry/system/errors"
|
5
|
+
|
6
|
+
module Dry
|
7
|
+
module System
|
8
|
+
module Config
|
9
|
+
# The configured component dirs for a container
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
class ComponentDirs
|
13
|
+
# @!group Settings
|
14
|
+
|
15
|
+
# @!method auto_register=(value)
|
16
|
+
#
|
17
|
+
# Sets a default `auto_register` for all added component dirs
|
18
|
+
#
|
19
|
+
# @see ComponentDir.auto_register=
|
20
|
+
# @see auto_register
|
21
|
+
#
|
22
|
+
# @!method auto_register
|
23
|
+
#
|
24
|
+
# Returns the configured default `auto_register`
|
25
|
+
#
|
26
|
+
# @see auto_register=
|
27
|
+
|
28
|
+
# @!method instance=(value)
|
29
|
+
#
|
30
|
+
# Sets a default `instance` for all added component dirs
|
31
|
+
#
|
32
|
+
# @see ComponentDir.instance=
|
33
|
+
# @see auto_register
|
34
|
+
#
|
35
|
+
# @!method auto_register
|
36
|
+
#
|
37
|
+
# Returns the configured default `instance`
|
38
|
+
#
|
39
|
+
# @see instance=
|
40
|
+
|
41
|
+
# @!method loader=(value)
|
42
|
+
#
|
43
|
+
# Sets a default `loader` value for all added component dirs
|
44
|
+
#
|
45
|
+
# @see ComponentDir.loader=
|
46
|
+
# @see loader
|
47
|
+
#
|
48
|
+
# @!method loader
|
49
|
+
#
|
50
|
+
# Returns the configured default `loader`
|
51
|
+
#
|
52
|
+
# @see loader=
|
53
|
+
|
54
|
+
# @!method memoize=(value)
|
55
|
+
#
|
56
|
+
# Sets a default `memoize` value for all added component dirs
|
57
|
+
#
|
58
|
+
# @see ComponentDir.memoize=
|
59
|
+
# @see memoize
|
60
|
+
#
|
61
|
+
# @!method memoize
|
62
|
+
#
|
63
|
+
# Returns the configured default `memoize`
|
64
|
+
#
|
65
|
+
# @see memoize=
|
66
|
+
|
67
|
+
# rubocop:disable Layout/LineLength
|
68
|
+
|
69
|
+
# @!method namespaces
|
70
|
+
#
|
71
|
+
# Returns the default configured namespaces for all added component dirs
|
72
|
+
#
|
73
|
+
# Allows namespaces to added on the returned object via {Dry::System::Config::Namespaces#add}.
|
74
|
+
#
|
75
|
+
# @see Dry::System::Config::Namespaces#add
|
76
|
+
#
|
77
|
+
# @return [Namespaces] the namespaces
|
78
|
+
|
79
|
+
# @!method add_to_load_path=(value)
|
80
|
+
#
|
81
|
+
# Sets a default `add_to_load_path` value for all added component dirs
|
82
|
+
#
|
83
|
+
# @see ComponentDir.add_to_load_path=
|
84
|
+
# @see add_to_load_path
|
85
|
+
#
|
86
|
+
# @!method add_to_load_path
|
87
|
+
#
|
88
|
+
# Returns the configured default `add_to_load_path`
|
89
|
+
#
|
90
|
+
# @see add_to_load_path=
|
91
|
+
|
92
|
+
# rubocop:enable Layout/LineLength
|
93
|
+
|
94
|
+
# @!endgroup
|
95
|
+
|
96
|
+
# A ComponentDir for configuring the default values to apply to all added
|
97
|
+
# component dirs
|
98
|
+
#
|
99
|
+
# @see #method_missing
|
100
|
+
# @api private
|
101
|
+
attr_reader :defaults
|
102
|
+
|
103
|
+
# Creates a new component dirs
|
104
|
+
#
|
105
|
+
# @api private
|
106
|
+
def initialize
|
107
|
+
@dirs = {}
|
108
|
+
@defaults = ComponentDir.new(nil)
|
109
|
+
end
|
110
|
+
|
111
|
+
# @api private
|
112
|
+
def initialize_copy(source)
|
113
|
+
@dirs = source.dirs.map { |path, dir| [path, dir.dup] }.to_h
|
114
|
+
@defaults = source.defaults.dup
|
115
|
+
end
|
116
|
+
|
117
|
+
# Returns and optionally yields a previously added component dir
|
118
|
+
#
|
119
|
+
# @param path [String] the path for the component dir
|
120
|
+
# @yieldparam dir [ComponentDir] the component dir
|
121
|
+
#
|
122
|
+
# @return [ComponentDir] the component dir
|
123
|
+
#
|
124
|
+
# @api public
|
125
|
+
def dir(path)
|
126
|
+
dirs[path].tap do |dir|
|
127
|
+
# Defaults can be (re-)applied first, since the dir has already been added
|
128
|
+
apply_defaults_to_dir(dir) if dir
|
129
|
+
yield dir if block_given?
|
130
|
+
end
|
131
|
+
end
|
132
|
+
alias_method :[], :dir
|
133
|
+
|
134
|
+
# @overload add(path)
|
135
|
+
# Adds and configures a component dir for the given path
|
136
|
+
#
|
137
|
+
# @param path [String] the path for the component dir, relative to the configured
|
138
|
+
# container root
|
139
|
+
# @yieldparam dir [ComponentDir] the component dir to configure
|
140
|
+
#
|
141
|
+
# @return [ComponentDir] the added component dir
|
142
|
+
#
|
143
|
+
# @example
|
144
|
+
# component_dirs.add "lib" do |dir|
|
145
|
+
# dir.default_namespace = "my_app"
|
146
|
+
# end
|
147
|
+
#
|
148
|
+
# @see ComponentDir
|
149
|
+
# @api public
|
150
|
+
#
|
151
|
+
# @overload add(dir)
|
152
|
+
# Adds a configured component dir
|
153
|
+
#
|
154
|
+
# @param dir [ComponentDir] the configured component dir
|
155
|
+
#
|
156
|
+
# @return [ComponentDir] the added component dir
|
157
|
+
#
|
158
|
+
# @example
|
159
|
+
# dir = Dry::System::ComponentDir.new("lib")
|
160
|
+
# component_dirs.add dir
|
161
|
+
#
|
162
|
+
# @see ComponentDir
|
163
|
+
# @api public
|
164
|
+
def add(path_or_dir)
|
165
|
+
path, dir_to_add = path_and_dir(path_or_dir)
|
166
|
+
|
167
|
+
raise ComponentDirAlreadyAddedError, path if dirs.key?(path)
|
168
|
+
|
169
|
+
dirs[path] = dir_to_add.tap do |dir|
|
170
|
+
# Defaults must be applied after yielding, since the dir is being newly added,
|
171
|
+
# and must have its configuration fully in place before we can know which
|
172
|
+
# defaults to apply
|
173
|
+
yield dir if path_or_dir == path && block_given?
|
174
|
+
apply_defaults_to_dir(dir)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Deletes and returns a previously added component dir
|
179
|
+
#
|
180
|
+
# @param path [String] the path for the component dir
|
181
|
+
#
|
182
|
+
# @return [ComponentDir] the removed component dir
|
183
|
+
#
|
184
|
+
# @api public
|
185
|
+
def delete(path)
|
186
|
+
dirs.delete(path)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Returns the paths of the component dirs
|
190
|
+
#
|
191
|
+
# @return [Array<String>] the component dir paths
|
192
|
+
#
|
193
|
+
# @api public
|
194
|
+
def paths
|
195
|
+
dirs.keys
|
196
|
+
end
|
197
|
+
|
198
|
+
# Returns the count of component dirs
|
199
|
+
#
|
200
|
+
# @return [Integer]
|
201
|
+
#
|
202
|
+
# @api public
|
203
|
+
def length
|
204
|
+
dirs.length
|
205
|
+
end
|
206
|
+
alias_method :size, :length
|
207
|
+
|
208
|
+
# Returns the added component dirs, with default settings applied
|
209
|
+
#
|
210
|
+
# @return [Array<ComponentDir>]
|
211
|
+
#
|
212
|
+
# @api public
|
213
|
+
def to_a
|
214
|
+
dirs.each { |_, dir| apply_defaults_to_dir(dir) }
|
215
|
+
dirs.values
|
216
|
+
end
|
217
|
+
|
218
|
+
# Calls the given block once for each added component dir, passing the dir as an
|
219
|
+
# argument.
|
220
|
+
#
|
221
|
+
# @yieldparam dir [ComponentDir] the yielded component dir
|
222
|
+
#
|
223
|
+
# @api public
|
224
|
+
def each(&block)
|
225
|
+
to_a.each(&block)
|
226
|
+
end
|
227
|
+
|
228
|
+
protected
|
229
|
+
|
230
|
+
# Returns the hash of component dirs, keyed by their paths
|
231
|
+
#
|
232
|
+
# Recently changed default configuration may not be applied to these dirs. Use
|
233
|
+
# #to_a or #each to access dirs with default configuration fully applied.
|
234
|
+
#
|
235
|
+
# This method exists to encapsulate the instance variable and to serve the needs
|
236
|
+
# of #initialize_copy
|
237
|
+
#
|
238
|
+
# @return [Hash{String => ComponentDir}]
|
239
|
+
#
|
240
|
+
# @api private
|
241
|
+
attr_reader :dirs
|
242
|
+
|
243
|
+
private
|
244
|
+
|
245
|
+
# Converts a path string or pre-built component dir into a path and dir tuple
|
246
|
+
#
|
247
|
+
# @param path_or_dir [String,ComponentDir]
|
248
|
+
#
|
249
|
+
# @return [Array<(String, ComponentDir)>]
|
250
|
+
#
|
251
|
+
# @see #add
|
252
|
+
def path_and_dir(path_or_dir)
|
253
|
+
if path_or_dir.is_a?(ComponentDir)
|
254
|
+
dir = path_or_dir
|
255
|
+
[dir.path, dir]
|
256
|
+
else
|
257
|
+
path = path_or_dir
|
258
|
+
[path, ComponentDir.new(path)]
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# Applies default settings to a component dir. This is run every time the dirs are
|
263
|
+
# accessed to ensure defaults are applied regardless of when new component dirs
|
264
|
+
# are added. This method must be idempotent.
|
265
|
+
#
|
266
|
+
# @return [void]
|
267
|
+
def apply_defaults_to_dir(dir)
|
268
|
+
defaults.config.values.each do |key, _|
|
269
|
+
if defaults.configured?(key) && !dir.configured?(key)
|
270
|
+
dir.public_send(:"#{key}=", defaults.public_send(key).dup)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def method_missing(name, *args, &block)
|
276
|
+
if defaults.respond_to?(name)
|
277
|
+
defaults.public_send(name, *args, &block)
|
278
|
+
else
|
279
|
+
super
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def respond_to_missing?(name, include_all = false)
|
284
|
+
defaults.respond_to?(name) || super
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/system/constants"
|
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 public
|
25
|
+
class Namespace
|
26
|
+
ROOT_PATH = nil
|
27
|
+
|
28
|
+
include Dry::Equalizer(:path, :key, :const)
|
29
|
+
|
30
|
+
# @api public
|
31
|
+
attr_reader :path
|
32
|
+
|
33
|
+
# @api public
|
34
|
+
attr_reader :key
|
35
|
+
|
36
|
+
# @api public
|
37
|
+
attr_reader :const
|
38
|
+
|
39
|
+
# Returns a namespace configured to serve as the default root namespace for a
|
40
|
+
# component dir, ensuring that all code within the dir can be loaded, regardless
|
41
|
+
# of any other explictly configured namespaces
|
42
|
+
#
|
43
|
+
# @return [Namespace] the root namespace
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
def self.default_root
|
47
|
+
new(
|
48
|
+
path: ROOT_PATH,
|
49
|
+
key: nil,
|
50
|
+
const: nil
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
# @api private
|
55
|
+
def initialize(path:, key:, const:)
|
56
|
+
@path = path
|
57
|
+
# Default keys (i.e. when the user does not explicitly provide one) for non-root
|
58
|
+
# paths will include path separators, which we must convert into key separators
|
59
|
+
@key = key && key == path ? key.gsub(PATH_SEPARATOR, KEY_SEPARATOR) : key
|
60
|
+
@const = const
|
61
|
+
end
|
62
|
+
|
63
|
+
# @api public
|
64
|
+
def root?
|
65
|
+
path == ROOT_PATH
|
66
|
+
end
|
67
|
+
|
68
|
+
# @api public
|
69
|
+
def path?
|
70
|
+
!root?
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|