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