dry-system 0.21.0 → 0.24.0

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c0977524fa33277150e8611a851c557461c14357e1a5d9c1f1929c283f3c9b3
4
- data.tar.gz: 12de5eaa25ede9f5f959cd77e2af8f1d3b4b287aaebea1554c2915433743c290
3
+ metadata.gz: 374dd39e2ef3e67b1a337af6d71aed0ebb5de9ebb31e8a16072ce37170576e88
4
+ data.tar.gz: 8c3fc432ccaba83593018b09cf0d24f9d2c145057a18b9266c49dc8f5919ed8e
5
5
  SHA512:
6
- metadata.gz: 6976cb749c98ed536c5fb3e6ca67674aee2707b40cd5d196b6b82472edadfa10877bebac77631b0ebcc5fabe008514ed60e7d9be17ccd1343e8967836f319a11
7
- data.tar.gz: fd894f982bf214dac3ccfa0de1d4fd7f95beeea1f91234cd2868dfab4687b76ea831c153b429d8ba9bd9f04bcb46dd2815f87a7829e6b347b2d8992cf0ebd478
6
+ metadata.gz: 9d855078f7dff3cd01a23e5cbfca252c3b801d2d7b3406d9c12038c01268de6c334c59c97e3d14ae333b5e2a76c6bde90d0c4b57bcc43c8310e1e9b41796e1be
7
+ data.tar.gz: 2bf41708e4da839a1ba447231e32313ecb77acaad87499a85394c2d39f1cea6bc4f3b5581cb25de806ece5621734874354e82a1edb94bf26b89a890a5904db00
data/CHANGELOG.md CHANGED
@@ -1,5 +1,428 @@
1
1
  <!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
2
2
 
3
+ ## 0.24.0
4
+
5
+
6
+ ### Changed
7
+
8
+ - dry-struct depedency was removed (@flash-gordon)
9
+
10
+ [Compare v0.23.0...master](https://github.com/dry-rb/dry-system/compare/v0.23.0...master)
11
+
12
+ ## 0.23.0 2022-02-08
13
+
14
+ This is a major overhaul of bootable components (now known as “Providers”), and brings major advancements to other areas, including container imports and exports.
15
+
16
+ Deprecations are in place for otherwise breaking changes to commonly used parts of dry-system, though some breaking changes remain.
17
+
18
+ This prepares the way for dry-system 1.0, which will be released in the coming months.
19
+
20
+
21
+ ### Added
22
+
23
+ - Containers can configure specific components for export using `config.exports` (@timriley in #209).
24
+
25
+ ```ruby
26
+ class MyContainer < Dry::System::Container
27
+ configure do |config|
28
+ config.exports = %w[component_a component_b]
29
+ end
30
+ end
31
+ ```
32
+
33
+ Containers importing another container with configured exports will import only those components.
34
+
35
+ When importing a specific set of components (see the note in the “Changed” section below), only those components whose keys intersect with the configured exports will be imported.
36
+ - A `:zeitwerk` plugin, to set up [Zeitwerk](https://github.com/fxn/zeitwerk) and integrate it with your container configuration (@ianks and @timriley in #197, #222, 13f8c87, #223)
37
+
38
+ This makes it possible to enable Zeitwerk with a one-liner:
39
+
40
+ ```ruby
41
+ class MyContainer < Dry::System::Container
42
+ use :zeitwerk
43
+
44
+ configure do |config|
45
+ config.component_dirs.add "lib"
46
+ # ...
47
+ end
48
+ end
49
+ ```
50
+
51
+ The plugin makes a `Zeitwerk::Loader` instance available at `config.autoloader`, and then in an after-`:configure` hook, the plugin will set up the loader to work with all of your configured component dirs and their namespaces. It will also enable the `Dry::System::Loader::Autoloading` loader for all component dirs, plus disable those dirs from being added to the `$LOAD_PATH`.
52
+
53
+ The plugin accepts the following options:
54
+
55
+ - `loader:` - (optional) to use a pre-initialized loader, if required.
56
+ - `run_setup:` - (optional) a bool to determine whether to run `Zeitwerk::Loader#setup` as part of the after-`:configure` hook. This may be useful to disable in advanced cases when integrating with an externally managed loader.
57
+ - `eager_load:` - (optional) a bool to determine whether to run `Zeitwerk::Loader#eager_load` as part of an after-`:finalize` hook. When not provided, it will default to true if the `:env` plugin is enabled and the env is set to `:production`.
58
+ - `debug:` - (optional) a bool to set whether Zeitwerk should log to `$stdout`.
59
+ - New `Identifier#end_with?` and `Identifier#include?` predicates (@timriley in #219)
60
+
61
+ These are key segment-aware predicates that can be useful when checking components as part of container configuration.
62
+
63
+ ```ruby
64
+ identifier.key # => "articles.operations.create"
65
+
66
+ identifier.end_with?("create") # => true
67
+ identifier.end_with?("operations.create") # => true
68
+ identifier.end_with?("ate") # => false, not a whole segment
69
+ identifier.end_with?("nope") # => false, not part of the key at all
70
+
71
+ identifier.include?("operations") # => true
72
+ identifier.include?("articles.operations") # => true
73
+ identifier.include?("operations.create") # => true
74
+ identifier.include?("article") # false, not a whole segment
75
+ identifier.include?("update") # => false, not part of the key at all
76
+ ```
77
+ - An `instance` setting for component dirs allows simpler per-dir control over component instantiation (@timriley in #215)
78
+
79
+ This optional setting should be provided a proc that receives a single `Dry::System::Component` instance as an argument, and should return the instance for the given component.
80
+
81
+ ```ruby
82
+ configure do |config|
83
+ config.component_dirs.add "lib" do |dir|
84
+ dir.instance = proc do |component|
85
+ if component.identifier.include?("workers")
86
+ # Register classes for jobs
87
+ component.loader.constant(component)
88
+ else
89
+ # Otherwise register regular instances per default loader
90
+ component.loader.call(component)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ ```
96
+
97
+ For complete control of component loading, you should continue to configure the component dir’s `loader` instead.
98
+ - A new `ComponentNotLoadableError` error and helpful message is raised when resolving a component and an unexpected class is defined in the component’s source file (@cllns in #217).
99
+
100
+ The error shows expected and found class names, and inflector configuration that may be required in the case of class names containing acronyms.
101
+
102
+ ### Fixed
103
+
104
+ - Registrations made in providers (by calling `register` inside a provider step) have all their registration options preserved (such as a block-based registration, or the `memoize:` option) when having their registration merged into the target container after the provider lifecycle steps complete (@timriley in #212).
105
+ - Providers can no longer implicitly re-start themselves while in the process of starting and cause an infinite loop (@timriley #213).
106
+
107
+ This was possible before when a provider resolved a component from the target container that auto-injected dependencies with container keys sharing the same base key as the provider name.
108
+
109
+ ### Changed
110
+
111
+ - “Bootable components” (also referred to in some places simply as “components”) have been renamed to “Providers” (@timriley in #200).
112
+
113
+ Register a provider with `Dry::System::Container.register_provider` (`Dry::System::Container.boot` has been deprecated):
114
+
115
+ ```ruby
116
+ MyContainer.register_provider(:mailer) do
117
+ # ...
118
+ end
119
+ ```
120
+ - Provider `init` lifecycle step has been deprecated and renamed to `prepare` (@timriley in #200).
121
+
122
+ ```ruby
123
+ MyContainer.reigster_provider(:mailer) do
124
+ # Rename `init` to `prepare`
125
+ prepare do
126
+ require "some/third_party/mailer"
127
+ end
128
+ end
129
+ ```
130
+ - Provider behavior is now backed by a class per provider, known as the “Provider source” (@timriley in #202).
131
+
132
+ The provider source class is created for each provider as a subclass of `Dry::System::Provider::Source`.
133
+
134
+ You can still register simple providers using the block-based DSL, but the class backing means you can share state between provider steps using regular instance variables:
135
+
136
+ ```ruby
137
+ MyContainer.reigster_provider(:mailer) do
138
+ prepare do
139
+ require "some/third_party/mailer"
140
+ @some_config = ThirdParty::Mailer::Config.new
141
+ end
142
+
143
+ start do
144
+ # Since the `prepare` step will always run before start, we can access
145
+ # @some_config here
146
+ register "mailer", ThirdParty::Mailer.new(@some_config)
147
+ end
148
+ end
149
+ ```
150
+
151
+ Inside this `register_provider` block, `self` is the source subclass itself, and inside each of the step blocks (i.e. `prepare do`), `self` will be the _instance_ of that provider source.
152
+
153
+ For more complex providers, you can define your own source subclass and register it directly with the `source:` option for `register_provider`. This allows you to more readily use standard arrangements for factoring your logic within a class, such as extraction to another method:
154
+
155
+ ```ruby
156
+ MyContainer.register_provider(:mailer, source: Class.new(Dry::System::Provider::Source) {
157
+ # The provider lifecycle steps are ordinary methods
158
+ def prepare
159
+ end
160
+
161
+ def start
162
+ mailer = some_complex_logic_to_build_the_mailer(some: "config")
163
+ register(:mailer, mailer)
164
+ end
165
+
166
+ private
167
+
168
+ def some_complex_logic_to_build_the_mailer(**options)
169
+ # ...
170
+ end
171
+ })
172
+ ```
173
+ - The block argument to `Dry::System::Container.register_provider` (previously `.boot`) has been deprecated. (@timriley in #202).
174
+
175
+ This argument was used to give you access to the provider's target container (i.e. the container on which you were registering the provider).
176
+
177
+ To access the target container, you can use `#target_container` (or `#target` as a convenience alias) instead.
178
+
179
+ You can also access the provider's own container (which is where the provider's components are registered when you call `register` directly inside a provider step) as `#provider_container` (or `#container` as a convenience alias).
180
+ - `use(provider_name)` inside a provider step has been deprecated. Use `target_container.start(provider_name)` instead (@timriley in #211 and #224)
181
+
182
+ Now that you can access `target_container` consistently within all provider steps, you can use it to also start any other providers as you require without any special additional method. This also allows you to invoke other provider lifecycle steps, like `target_container.prepare(provider_name)`.
183
+ - `method_missing`-based delegation within providers to target container registrations has been removed (**BREAKING**) (@timriley in #202)
184
+
185
+ Delegation to registrations with the provider's own container has been kept, since it can be a convenient way to access registrations made in a prior lifecycle step:
186
+
187
+ ```ruby
188
+ MyContainer.register_provider(:mailer, namespace: true) do
189
+ prepare do
190
+ register :config, "mailer config here"
191
+ end
192
+
193
+ start do
194
+ config # => "mailer config here"
195
+ end
196
+ end
197
+ ```
198
+ - The previous "external component" and "provider" concepts have been renamed to "external provider sources", in keeping with the new provider terminology outlined above (@timriley in #200 and #202).
199
+
200
+ You can register a collection of external provider sources defined in their own source files via `Dry::System.register_provider_sources` (`Dry::System.register_provider` has been deprecated):
201
+
202
+ ```ruby
203
+ require "dry/system"
204
+
205
+ Dry::System.register_provider_sources(path)
206
+ ```
207
+
208
+ You can register an individual external provider source via `Dry::System.register_provider_source` (`Dry::System.register_component` has been deprecated):
209
+
210
+ ```ruby
211
+ Dry::System.register_provider_source(:something, group: :my_gem) do
212
+ start do
213
+ # ...
214
+ end
215
+ end
216
+ ```
217
+
218
+ Just like providers, you can also register a class as an external provider source:
219
+
220
+ ```ruby
221
+ module MyGem
222
+ class MySource < Dry::System::Provider::Source
223
+ def start
224
+ # ...
225
+ end
226
+ end
227
+ end
228
+
229
+ Dry::System.register_provider_source(:something, group: :my_gem, source: MyGem::MySource)
230
+ ```
231
+
232
+ The `group:` argument when registering an external provider sources is for preventing name clashes between provider sources. You should use an underscored version of your gem name or namespace when registering your own provider sources.
233
+ - Registering a provider using an explicitly named external provider source via `key:` argument is deprecated, use the `source:` argument instead (@timriley in #202).
234
+
235
+ You can register a provider using the same name as an external provider source by specifying the `from:` argument only, as before:
236
+
237
+ ```ruby
238
+ # Elsewhere
239
+ Dry::System.register_provider_source(:something, group: :my_gem) { ... }
240
+
241
+ # In your app:
242
+ MyContainer.register_provider(:something, from: :my_gem)
243
+ ```
244
+
245
+ When you wish the name your provider differently, this is when you need to use the `source:` argument:
246
+
247
+ ```ruby
248
+ MyContainer.register_provider(:differently_named, from: :my_gem, source: :something)
249
+ ```
250
+
251
+ When you're registering a provider using an external provider source, you cannot provie your own `Dry::System::Provider::Source` subclass as the `source:`, since that source class is being provided by the external provider source.
252
+ - Provider source settings are now defined using dry-configurable’s `setting` API at the top-level scope (@timriley in #202).
253
+
254
+ Use the top-level `setting` method to define your settings (the `settings` block and settings defined inside the block using `key` is deprecated). Inside the provider steps, the configured settings can be accessed as `config`:
255
+
256
+ ```ruby
257
+ # In the external provider source
258
+ Dry::System.register_provider_source(:something, group: :my_gem) do
259
+ setting :my_option
260
+
261
+ start do
262
+ # Do something with `config.my_option` here
263
+ end
264
+ end
265
+ ```
266
+
267
+ When using an external provider source, configure the source via the `#configure`:
268
+
269
+ ```ruby
270
+ # In your application's provider using the external source
271
+ MyContainer.register_provider(:something, from: :my_gem) do
272
+ configure do |config|
273
+ config.my_option = "some value"
274
+ end
275
+ end
276
+ ```
277
+
278
+ To provide default values and type checking or constraints for your settings, use the dry-configurable’s `default:` and `constructor:` arguments:
279
+
280
+ ```ruby
281
+ # Constructor can take any proc being passed the provided value
282
+ setting :my_option, default: "hello", constructor: -> (v) { v.to_s.upcase }
283
+
284
+ # Constructor will also work with dry-types objects
285
+ setting :my_option, default: "hello", constructor: Types::String.constrained(min_size: 3)
286
+ ```
287
+ - External provider sources can define their own methods for use by the providers alongside lifecycle steps (@timriley in #202).
288
+
289
+ Now that provider sources are class-backed, external provider sources can define their own methods to be made available when that provider source is used. This makes it possible to define your own extended API for interacting with the provider source:
290
+
291
+ ```ruby
292
+ # In the external provider source
293
+
294
+ module MyGem
295
+ class MySource < Dry::System::Provider::Source
296
+ # Standard lifecycle steps
297
+ def start
298
+ # Do something with @on_start here
299
+ end
300
+
301
+ # Custom behavior available when this provider source is used in a provider
302
+ def on_start(&block)
303
+ @on_start = block
304
+ end
305
+ end
306
+ end
307
+
308
+ Dry::System.register_provider_source(:something, group: :my_gem, source: MyGem::MySource)
309
+
310
+ # In your application's provider using the external source
311
+
312
+ MyContainer.register_provider(:something, from: :my_gem) do
313
+ # Use the custom method!
314
+ on_start do
315
+ # ...
316
+ end
317
+ end
318
+ ```
319
+ - Providers can be registered conditionally using the `if:` option (@timriley in #218).
320
+
321
+ You should provide a simple truthy or falsey value to `if:`, and in the case of falsey value, the provider will not be registered.
322
+
323
+ This is useful in cases where you have providers that are loaded explicitly for specific runtime configurations of your app (e.g. when they are needed for specific tasks or processes only), but you do not need them for your primaary app process, for which you may finalize your container.
324
+ - `bootable_dirs` container setting has been deprecated and replaced by `provider_dirs` (@timriley in #200).
325
+
326
+ The default value for `provider_dirs` is now `"system/providers`".
327
+ - Removed the unused `system_dir` container setting (**BREAKING**) (@timriley in #200)
328
+
329
+ If you’ve configured this inside your container, you can remove it.
330
+ - dry-system’s first-party external provider sources now available via `require "dry/system/provider_sources"`, with the previous `require "dry/system/components"` deprecated (@timriley in #202).
331
+ - When using registering a provider using a first-party dry-system provider source, `from: :dry_system` instead of `from: :system` (which is now deprecated) (@timriley in #202).
332
+
333
+ ```ruby
334
+ MyContainer.register_provider(:settings, from: :dry_system) do
335
+ # ...
336
+ end
337
+ - When registering a provider using the `:settings` provider source, settings are now defined using `setting` inside a `settings` block, rather than `key`, which is deprecated (@timriley in #202).
338
+
339
+ This `setting` method uses the dry-configurable setting API:
340
+
341
+ ```ruby
342
+ MyContainer.register_provider(:settings, from: :dry_system) do
343
+ settings do
344
+ # Previously:
345
+ # key :my_int_setting, MyTypes::Coercible::Integer
346
+
347
+ # Now:
348
+ setting :my_setting, default: 0, constructor: MyTypes::Coercible::Integer
349
+ end
350
+ end
351
+ ```
352
+ - The `:settings` provider source now requires the dotenv gem to load settings from `.env*` files (**BREAKING**) (@timriley in #204)
353
+
354
+ To ensure you can load your settings from these `.env*` files, add `gem "dotenv"` to your `Gemfile`.
355
+ - `Dry::System::Container` can be now be configured direclty using the setting writer methods on the class-level `.config` object, without going the `.configure(&block)` API (@timriley in #207).
356
+
357
+ If configuring via the class-level `.config` object, you should call `.configured!` after you're completed your configuration, which will finalize (freeze) the `config` object and then run any after-`:configure` hooks.
358
+ - `Dry::System::Container.configure(&block)` will now finalize (freeze) the `config` object by default, before returning (@timriley in #207).
359
+
360
+ You can opt out of this behavior by passing the `finalize_config: false` option:
361
+
362
+ ```ruby
363
+ class MyContainer < Dry::System::Container
364
+ configure(finalize_config: false) do |config|
365
+ # ...
366
+ end
367
+
368
+ # `config` is still non-finalized here
369
+ end
370
+ ```
371
+ - `Dry::System::Container.finalize!` will call `.configured!` (if it has not yet been called) before doing its work (@timriley in #207)
372
+
373
+ This ensures config finalization is an intrinsic part of the overall container finalization process.
374
+ - The `Dry::System::Container` `before(:configure)` hook has been removed (**BREAKING**) (@timriley in #207).
375
+
376
+ This was previously used for plugins to register their own settings, but this was not necessary given that plugins are modules, and can use their ordinary `.extended(container_class)` hook to register their settings. Essentially, any time after container subclass definition is "before configure" in nature.
377
+ - Container plugins should define their settings on the container using their module `.extended` hook, no longer in a `before(:configure)` hook (as above) (**BREAKING**) (@timriley in #207).
378
+
379
+ This ensures the plugin settings are available immediately after you’ve enabled the plugin via `Dry::System::Container.use`.
380
+ - The `Dry::System::Container` key `namespace_separator` setting is no longer expected to be user-configured. A key namespace separator of "." is hard-coded and expected to remain the separator string. (@timriley in #206)
381
+ - Containers can import a specific subset of another container’s components via changes to `.import`, which is now `.import(keys: nil, from:, as:)` (with prior API deprecated) (@timriley in #209)
382
+
383
+ To import specific components:
384
+
385
+ ```ruby
386
+ class MyContainer < Dry::System::Container
387
+ # config, etc.
388
+
389
+ # Will import components with keys "other.component_a", "other.component_b"
390
+ import(
391
+ keys: %w[component_a component_b],
392
+ from: OtherContainer,
393
+ as: :other
394
+ )
395
+ ```
396
+
397
+ Omitting `keys:` will import all the components available from the other container.
398
+ - Components imported into a container from another will be protected from subsequent export unless explicitly configured in `config.exports` (@timriley in #209)
399
+
400
+ Imported components are considered “private” by default because they did not originate in container that imported them.
401
+
402
+ This ensures there are no redundant imports in arrangements where multiple all containers import a common “base” container, and then some of those containers then import each other.
403
+ - Container imports are now made without finalizing the exporting container in most cases, ensuring more efficient imports (@timriley in #209)
404
+
405
+ Now, the only time the exporting container will be finalized is when a container is importing all components, and the exporting container has not declared any components in `config.exports`.
406
+ - [Internal] The `manual_registrar` container setting and associated `ManualRegistrar` class have been renamed to `manifest_registrar` and `ManifestRegistrar` respectively (**BREAKING**) (@timriley in #208).
407
+ - The default value for the container `registrations_dir` setting has been changed from `"container"` to `"system/registrations"` (**BREAKING**) (@timriley in #208)
408
+ - The `:dependency_graph` plugin now supports all dry-auto_inject injector strategies (@davydovanton and @timriley in #214)
409
+
410
+ [Compare v0.22.0...v0.23.0](https://github.com/dry-rb/dry-system/compare/v0.22.0...v0.23.0)
411
+
412
+ ## 0.22.0 2022-01-06
413
+
414
+
415
+ ### Added
416
+
417
+ - Expanded public interfaces for `Dry::System::Config::ComponentDirs` and `Dry::System::Config::Namespaces` to better support programmatic construction and inspection of these configs (@timriley in #195)
418
+
419
+ ### Changed
420
+
421
+ - Deprecated `Dry::System::Config::Namespaces#root` as the way to add and configure a root namespace. Use `#add_root` instead (@timriley in #195)
422
+ - Allow bootsnap plugin to use bootsnap on Ruby versions up to 3.0 (pusewicz in #196)
423
+
424
+ [Compare v0.21.0...v0.22.0](https://github.com/dry-rb/dry-system/compare/v0.21.0...v0.22.0)
425
+
3
426
  ## 0.21.0 2021-11-01
4
427
 
5
428
 
@@ -29,6 +452,7 @@
29
452
  (@timriley in #181)
30
453
  - `Dry::System::Component#path` has been removed and replaced by `Component#require_path` and `Component#const_path` (@timriley in #181)
31
454
  - Unused `Dry::System::FileNotFoundError` and `Dry::System::InvalidComponentIdentifierTypeError` errors have been removed (@timriley in #194)
455
+ - Allow bootsnap for Rubies up to 3.0.x (via #196) (@pusewicz)
32
456
 
33
457
  [Compare v0.20.0...v0.21.0](https://github.com/dry-rb/dry-system/compare/v0.20.0...v0.21.0)
34
458
 
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2021 dry-rb team
3
+ Copyright (c) 2015-2022 dry-rb team
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
data/README.md CHANGED
@@ -8,10 +8,10 @@
8
8
  # dry-system [![Join the chat at https://dry-rb.zulipchat.com](https://img.shields.io/badge/dry--rb-join%20chat-%23346b7a.svg)][chat]
9
9
 
10
10
  [![Gem Version](https://badge.fury.io/rb/dry-system.svg)][gem]
11
- [![CI Status](https://github.com/dry-rb/dry-system/workflows/CI/badge.svg)][actions]
11
+ [![CI Status](https://github.com/dry-rb/dry-system/workflows/ci/badge.svg)][actions]
12
12
  [![Codacy Badge](https://api.codacy.com/project/badge/Grade/3a0e30d0ae2542c7ba047ba5f923c0bb)][codacy]
13
13
  [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/3a0e30d0ae2542c7ba047ba5f923c0bb)][codacy]
14
- [![Inline docs](http://inch-ci.org/github/dry-rb/dry-system.svg?branch=master)][inchpages]
14
+ [![Inline docs](http://inch-ci.org/github/dry-rb/dry-system.svg?branch=main)][inchpages]
15
15
 
16
16
  ## Links
17
17
 
@@ -22,8 +22,8 @@
22
22
 
23
23
  This library officially supports the following Ruby versions:
24
24
 
25
- * MRI `>= 2.6.0`
26
- * jruby `>= 9.3`
25
+ * MRI `>= 2.7.0`
26
+ * jruby `>= 9.3` (postponed until 2.7 is supported)
27
27
 
28
28
  ## License
29
29
 
data/dry-system.gemspec CHANGED
@@ -22,20 +22,19 @@ Gem::Specification.new do |spec|
22
22
  spec.require_paths = ["lib"]
23
23
 
24
24
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
25
- spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-system/blob/master/CHANGELOG.md"
25
+ spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-system/blob/main/CHANGELOG.md"
26
26
  spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-system"
27
27
  spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-system/issues"
28
28
 
29
- spec.required_ruby_version = ">= 2.6.0"
29
+ spec.required_ruby_version = ">= 2.7.0"
30
30
 
31
31
  # to update dependencies edit project.yml
32
32
  spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
33
33
  spec.add_runtime_dependency "dry-auto_inject", ">= 0.4.0"
34
- spec.add_runtime_dependency "dry-configurable", "~> 0.13", ">= 0.13.0"
34
+ spec.add_runtime_dependency "dry-configurable", "~> 0.14", ">= 0.14.0"
35
35
  spec.add_runtime_dependency "dry-container", "~> 0.9", ">= 0.9.0"
36
36
  spec.add_runtime_dependency "dry-core", "~> 0.5", ">= 0.5"
37
37
  spec.add_runtime_dependency "dry-inflector", "~> 0.1", ">= 0.1.2"
38
- spec.add_runtime_dependency "dry-struct", "~> 1.0"
39
38
 
40
39
  spec.add_development_dependency "bundler"
41
40
  spec.add_development_dependency "rake"
@@ -20,7 +20,6 @@ module Dry
20
20
  include Dry::Equalizer(:identifier, :namespace, :options)
21
21
 
22
22
  DEFAULT_OPTIONS = {
23
- separator: DEFAULT_SEPARATOR,
24
23
  inflector: Dry::Inflector.new,
25
24
  loader: Loader
26
25
  }.freeze
@@ -61,7 +60,7 @@ module Dry
61
60
  # @return [Object] component's class instance
62
61
  # @api public
63
62
  def instance(*args)
64
- loader.call(self, *args)
63
+ options[:instance]&.call(self, *args) || loader.call(self, *args)
65
64
  end
66
65
  ruby2_keywords(:instance) if respond_to?(:ruby2_keywords, true)
67
66
 
@@ -137,7 +136,7 @@ module Dry
137
136
  #
138
137
  # @api public
139
138
  def const_path
140
- namespace_const_path = namespace.const&.gsub(identifier.separator, PATH_SEPARATOR)
139
+ namespace_const_path = namespace.const&.gsub(KEY_SEPARATOR, PATH_SEPARATOR)
141
140
 
142
141
  if namespace_const_path
143
142
  "#{namespace_const_path}#{PATH_SEPARATOR}#{path_in_namespace}"
@@ -42,8 +42,8 @@ module Dry
42
42
  #
43
43
  # @api private
44
44
  def component_for_key(key)
45
- namespaces.each do |namespace|
46
- identifier = Identifier.new(key, separator: container.config.namespace_separator)
45
+ config.namespaces.each do |namespace|
46
+ identifier = Identifier.new(key)
47
47
 
48
48
  next unless identifier.start_with?(namespace.key)
49
49
 
@@ -65,37 +65,12 @@ module Dry
65
65
 
66
66
  private
67
67
 
68
- def namespaces
69
- config.namespaces.to_a.map { |namespace| normalize_namespace(namespace) }
70
- end
71
-
72
- # Returns an array of "normalized" namespaces, safe for loading components
73
- #
74
- # This works around the issue of a namespace being added for a nested path but
75
- # _without_ specifying a key namespace. In this case, the key namespace will defaut
76
- # to match the path, meaning it will contain path separators instead of the
77
- # container's configured `namespace_separator` (due to `Config::Namespaces` not
78
- # being able to know the configured `namespace_separator`), so we need to replace
79
- # the path separators with the proper `namespace_separator` here (where we _do_ know
80
- # what it is).
81
- def normalize_namespace(namespace)
82
- if namespace.path&.include?(PATH_SEPARATOR) && namespace.default_key?
83
- namespace = namespace.class.new(
84
- path: namespace.path,
85
- key: namespace.key.gsub(PATH_SEPARATOR, container.config.namespace_separator),
86
- const: namespace.const
87
- )
88
- end
89
-
90
- namespace
91
- end
92
-
93
68
  def each_file
94
69
  return enum_for(:each_file) unless block_given?
95
70
 
96
71
  raise ComponentDirNotFoundError, full_path unless Dir.exist?(full_path)
97
72
 
98
- namespaces.each do |namespace|
73
+ config.namespaces.each do |namespace|
99
74
  files(namespace).each do |file|
100
75
  yield file, namespace
101
76
  end
@@ -106,7 +81,7 @@ module Dry
106
81
  if namespace.path?
107
82
  Dir[File.join(full_path, namespace.path, "**", RB_GLOB)].sort
108
83
  else
109
- non_root_paths = namespaces.to_a.reject(&:root?).map(&:path)
84
+ non_root_paths = config.namespaces.to_a.reject(&:root?).map(&:path)
110
85
 
111
86
  Dir[File.join(full_path, "**", RB_GLOB)].reject { |file_path|
112
87
  Pathname(file_path).relative_path_from(full_path).to_s.start_with?(*non_root_paths)
@@ -126,16 +101,14 @@ module Dry
126
101
  # @param path [String] the full path to the file
127
102
  # @return [Dry::System::Component] the component
128
103
  def component_for_path(path, namespace)
129
- separator = container.config.namespace_separator
130
-
131
104
  key = Pathname(path).relative_path_from(full_path).to_s
132
105
  .sub(RB_EXT, EMPTY_STRING)
133
106
  .scan(WORD_REGEX)
134
- .join(separator)
107
+ .join(KEY_SEPARATOR)
135
108
 
136
- identifier = Identifier.new(key, separator: separator)
109
+ identifier = Identifier.new(key)
137
110
  .namespaced(
138
- from: namespace.path&.gsub(PATH_SEPARATOR, separator),
111
+ from: namespace.path&.gsub(PATH_SEPARATOR, KEY_SEPARATOR),
139
112
  to: namespace.key
140
113
  )
141
114
 
@@ -175,6 +148,7 @@ module Dry
175
148
  {
176
149
  auto_register: auto_register,
177
150
  loader: loader,
151
+ instance: instance,
178
152
  memoize: memoize
179
153
  }
180
154
  end
@@ -1,8 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "dry/system"
3
+ require "dry/core/deprecations"
4
4
 
5
- Dry::System.register_provider(
6
- :system,
7
- boot_path: Pathname(__dir__).join("system_components").realpath
5
+ Dry::Core::Deprecations.announce(
6
+ "require \"dry/system/components\"",
7
+ "Use `require \"dry/system/provider_sources\"` instead",
8
+ tag: "dry-system",
9
+ uplevel: 1
8
10
  )
11
+
12
+ require_relative "provider_sources"