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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +678 -0
  3. data/LICENSE +1 -1
  4. data/README.md +5 -4
  5. data/dry-system.gemspec +18 -21
  6. data/lib/dry/system/auto_registrar.rb +9 -64
  7. data/lib/dry/system/component.rb +124 -104
  8. data/lib/dry/system/component_dir.rb +171 -0
  9. data/lib/dry/system/config/component_dir.rb +228 -0
  10. data/lib/dry/system/config/component_dirs.rb +289 -0
  11. data/lib/dry/system/config/namespace.rb +75 -0
  12. data/lib/dry/system/config/namespaces.rb +196 -0
  13. data/lib/dry/system/constants.rb +2 -4
  14. data/lib/dry/system/container.rb +305 -345
  15. data/lib/dry/system/errors.rb +73 -56
  16. data/lib/dry/system/identifier.rb +176 -0
  17. data/lib/dry/system/importer.rb +89 -12
  18. data/lib/dry/system/indirect_component.rb +63 -0
  19. data/lib/dry/system/loader/autoloading.rb +24 -0
  20. data/lib/dry/system/loader.rb +49 -41
  21. data/lib/dry/system/{manual_registrar.rb → manifest_registrar.rb} +13 -14
  22. data/lib/dry/system/plugins/bootsnap.rb +3 -2
  23. data/lib/dry/system/plugins/dependency_graph/strategies.rb +38 -2
  24. data/lib/dry/system/plugins/dependency_graph.rb +25 -21
  25. data/lib/dry/system/plugins/env.rb +3 -2
  26. data/lib/dry/system/plugins/logging.rb +9 -8
  27. data/lib/dry/system/plugins/monitoring.rb +1 -2
  28. data/lib/dry/system/plugins/notifications.rb +1 -1
  29. data/lib/dry/system/plugins/plugin.rb +61 -0
  30. data/lib/dry/system/plugins/zeitwerk/compat_inflector.rb +22 -0
  31. data/lib/dry/system/plugins/zeitwerk.rb +109 -0
  32. data/lib/dry/system/plugins.rb +5 -73
  33. data/lib/dry/system/provider/source.rb +276 -0
  34. data/lib/dry/system/provider/source_dsl.rb +55 -0
  35. data/lib/dry/system/provider.rb +261 -23
  36. data/lib/dry/system/provider_registrar.rb +251 -0
  37. data/lib/dry/system/provider_source_registry.rb +56 -0
  38. data/lib/dry/system/provider_sources/settings/config.rb +73 -0
  39. data/lib/dry/system/provider_sources/settings/loader.rb +44 -0
  40. data/lib/dry/system/provider_sources/settings.rb +40 -0
  41. data/lib/dry/system/provider_sources.rb +5 -0
  42. data/lib/dry/system/stubs.rb +6 -2
  43. data/lib/dry/system/version.rb +1 -1
  44. data/lib/dry/system.rb +35 -13
  45. metadata +48 -97
  46. data/lib/dry/system/auto_registrar/configuration.rb +0 -43
  47. data/lib/dry/system/booter/component_registry.rb +0 -35
  48. data/lib/dry/system/booter.rb +0 -181
  49. data/lib/dry/system/components/bootable.rb +0 -289
  50. data/lib/dry/system/components/config.rb +0 -35
  51. data/lib/dry/system/components.rb +0 -8
  52. data/lib/dry/system/lifecycle.rb +0 -135
  53. data/lib/dry/system/provider_registry.rb +0 -27
  54. data/lib/dry/system/settings/file_loader.rb +0 -30
  55. data/lib/dry/system/settings/file_parser.rb +0 -51
  56. data/lib/dry/system/settings.rb +0 -67
  57. data/lib/dry/system/system_components/settings.rb +0 -11
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/system/errors"
4
+
5
+ module Dry
6
+ module System
7
+ module Config
8
+ # The configured namespaces for a ComponentDir
9
+ #
10
+ # @see Config::ComponentDir#namespaces
11
+ #
12
+ # @api private
13
+ class Namespaces
14
+ include Dry::Equalizer(:namespaces)
15
+
16
+ # @api private
17
+ attr_reader :namespaces
18
+
19
+ # @api private
20
+ def initialize
21
+ @namespaces = {}
22
+ end
23
+
24
+ # @api private
25
+ def initialize_copy(source)
26
+ super
27
+ @namespaces = source.namespaces.dup
28
+ end
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
48
+ namespaces[Namespace::ROOT_PATH]
49
+ end
50
+
51
+ # rubocop:disable Layout/LineLength
52
+
53
+ # Adds a component dir namespace
54
+ #
55
+ # A namespace encompasses a given sub-directory of the component dir, and
56
+ # determines (1) the leading segments of its components' registered identifiers,
57
+ # and (2) the expected constant namespace of their class constants.
58
+ #
59
+ # A namespace for a path can only be added once.
60
+ #
61
+ # @example Adding a namespace with top-level identifiers
62
+ # # Components defined within admin/ (e.g. admin/my_component.rb) will be:
63
+ # #
64
+ # # - Registered with top-level identifiers ("my_component")
65
+ # # - Expected to have constants in `Admin`, matching the namespace's path (Admin::MyComponent)
66
+ #
67
+ # namespaces.add "admin", key: nil
68
+ #
69
+ # @example Adding a namespace with top-level class constants
70
+ # # Components defined within adapters/ (e.g. adapters/my_adapter.rb) will be:
71
+ # #
72
+ # # - Registered with leading identifiers matching the namespace's path ("adapters.my_adapter")
73
+ # # - Expected to have top-level constants (::MyAdapter)
74
+ #
75
+ # namespaces.add "adapters", const: nil
76
+ #
77
+ # @example Adding a namespace with distinct identifiers and class constants
78
+ # # Components defined within `bananas/` (e.g. bananas/banana_split.rb) will be:
79
+ # #
80
+ # # - Registered with the given leading identifier ("desserts.banana_split")
81
+ # # - Expected to have constants within the given namespace (EatMe::Now::BananaSplit)
82
+ #
83
+ # namespaces.add "bananas", key: "desserts", const: "eat_me/now"
84
+ #
85
+ # @param path [String] the path to the sub-directory of source files to which this
86
+ # namespace should apply, relative to the component dir
87
+ # @param key [String, nil] the leading namespace to apply to the container keys
88
+ # for the components. Set `nil` for the keys to be top-level.
89
+ # @param const [String, nil] the Ruby constant namespace to expect for constants
90
+ # defined within the components. This should be provided in underscored string
91
+ # form, e.g. "hello_there/world" for a Ruby constant of `HelloThere::World`. Set
92
+ # `nil` for the constants to be top-level.
93
+ #
94
+ # @return [Namespace] the added namespace
95
+ #
96
+ # @see Namespace
97
+ #
98
+ # @api public
99
+ def add(path, key: path, const: path)
100
+ raise NamespaceAlreadyAddedError, path if namespaces.key?(path)
101
+
102
+ namespaces[path] = Namespace.new(path: path, key: key, const: const)
103
+ end
104
+
105
+ # rubocop:enable Layout/LineLength
106
+
107
+ # Adds a root component dir namespace
108
+ #
109
+ # @see #add
110
+ #
111
+ # @api public
112
+ def add_root(key: nil, const: nil)
113
+ add(Namespace::ROOT_PATH, key: key, const: const)
114
+ end
115
+
116
+ # Deletes the configured namespace for the given path and returns the namespace
117
+ #
118
+ # If no namespace was previously configured for the given path, returns nil
119
+ #
120
+ # @param path [String] the path for the namespace
121
+ #
122
+ # @return [Namespace, nil]
123
+ #
124
+ # @api public
125
+ def delete(path)
126
+ namespaces.delete(path)
127
+ end
128
+
129
+ # Deletes the configured root namespace and returns the namespace
130
+ #
131
+ # If no root namespace was previously configured, returns nil
132
+ #
133
+ # @return [Namespace, nil]
134
+ #
135
+ # @api public
136
+ def delete_root
137
+ delete(Namespace::ROOT_PATH)
138
+ end
139
+
140
+ # Returns the paths of the configured namespaces
141
+ #
142
+ # @return [Array<String,nil>] the namespace paths, with nil representing the root
143
+ # namespace
144
+ #
145
+ # @api public
146
+ def paths
147
+ namespaces.keys
148
+ end
149
+
150
+ # Returns the count of configured namespaces
151
+ #
152
+ # @return [Integer]
153
+ #
154
+ # @api public
155
+ def length
156
+ namespaces.length
157
+ end
158
+ alias_method :size, :length
159
+
160
+ # Returns true if there are no configured namespaces
161
+ #
162
+ # @return [Boolean]
163
+ #
164
+ # @api public
165
+ def empty?
166
+ namespaces.empty?
167
+ end
168
+
169
+ # Returns the configured namespaces as an array
170
+ #
171
+ # Adds a default root namespace to the end of the array if one was not added
172
+ # explicitly. This fallback ensures that all components in the component dir can
173
+ # be loaded.
174
+ #
175
+ # @return [Array<Namespace>] the namespaces
176
+ #
177
+ # @api public
178
+ def to_a
179
+ namespaces.values.tap do |arr|
180
+ arr << Namespace.default_root unless arr.any?(&:root?)
181
+ end
182
+ end
183
+
184
+ # Calls the given block once for each configured namespace, passing the namespace
185
+ # as an argument.
186
+ #
187
+ # @yieldparam namespace [Namespace] the yielded namespace
188
+ #
189
+ # @api public
190
+ def each(&block)
191
+ to_a.each(&block)
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
@@ -1,15 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "dry/core/constants"
4
-
5
3
  module Dry
6
4
  module System
7
5
  include Dry::Core::Constants
8
6
 
9
7
  RB_EXT = ".rb"
10
8
  RB_GLOB = "*.rb"
11
- PATH_SEPARATOR = "/"
12
- DEFAULT_SEPARATOR = "."
9
+ PATH_SEPARATOR = File::SEPARATOR
10
+ KEY_SEPARATOR = "."
13
11
  WORD_REGEX = /\w+/.freeze
14
12
  end
15
13
  end