dry-system 0.18.1 → 1.0.1

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