dry-system 1.0.1 → 1.2.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d867a0c8708ea863edb44b5f93453c5d986925c921af51d747b605d6f4d3bbb
4
- data.tar.gz: 1ee2e7a02c48bd9feb02a018aea1c81f59a5bda1ca7351d62a008162a62d1471
3
+ metadata.gz: f6e2bd6b5eeb03f260f1bf95def5a6dd7b1a419aa2e57301805fc37f43ffa08c
4
+ data.tar.gz: 18d1e11ad33a6e725b3eb049662957652120edcc2ce5da31847d13f511df65d8
5
5
  SHA512:
6
- metadata.gz: 75e76f0ff522306b18b38c17c4bdfdae39280cbf4507beff3233bfc7cd10af752de605d0af619b6528a237f6860a4baee3754afedd890d66d50ac54a2880b4bf
7
- data.tar.gz: aa31996c109cee9a6b05f61b127d7b9a6ec04cc30fe2e10ecf3f14f8948b2c34be7e687ec6ba6565bd06b9874816cf33d150a5b7499c9e125540e920159a7531
6
+ metadata.gz: b80e0a016030c542c963155140f30d15eb62c463c29ed1ba94d79378371fd11d2f2a7c4ea13cd0c11bbea3210cda2262cacde67ce9f8c50412e25a98c292a3a7
7
+ data.tar.gz: 35473d55c1434e8427c1d297868d65d2a31c2ebf559c50618712e97293f0d1c8ecd726945a94e4bde6bcbcfd7ef50837590f5e36c4a3a8396d52bce99a988e80
data/CHANGELOG.md CHANGED
@@ -1,5 +1,102 @@
1
1
  <!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
2
2
 
3
+ ## 1.2.3 2025-07-29
4
+
5
+
6
+ ### Fixed
7
+
8
+ - Re-register components from manifest registrars in apps that reload the container (e.g. when
9
+ using dry-rails and Rails development mode) (via #286, @alassek)
10
+
11
+
12
+ [Compare v1.2.2...v1.2.3](https://github.com/dry-rb/dry-system/compare/v1.2.2...v1.2.3)
13
+
14
+ ## 1.2.2 2025-01-31
15
+
16
+
17
+ ### Fixed
18
+
19
+ - Syntax errors on 3.3.0 (@flash-gordon, see #284)
20
+
21
+
22
+ [Compare v1.2.1...v1.2.2](https://github.com/dry-rb/dry-system/compare/v1.2.1...v1.2.2)
23
+
24
+ ## 1.2.1 2025-01-08
25
+
26
+
27
+ ### Fixed
28
+
29
+ - `eager_load` was removed from `finalize!`. It was introduced with `true` by default that
30
+ wasn't the intention #281 (via #282) (@flash-gordon)
31
+
32
+
33
+ [Compare v1.2.0...v1.2.1](https://github.com/dry-rb/dry-system/compare/v1.2.0...v1.2.1)
34
+
35
+ ## 1.2.0 2025-01-07
36
+
37
+
38
+ ### Added
39
+
40
+ - Option to skip eager loading during finalize with `eager_load: false` (via #276) (@cllns)
41
+
42
+ ### Changed
43
+
44
+ - Update required Ruby version to 3.1 (@flash-gordon)
45
+
46
+ [Compare v1.1.1...v1.2.0](https://github.com/dry-rb/dry-system/compare/v1.1.1...v1.2.0)
47
+
48
+ ## 1.1.1 2024-11-03
49
+
50
+
51
+ ### Fixed
52
+
53
+ - Restore `ProviderRegistrar#find_and_load_provider` as an alias of `#[]`
54
+
55
+
56
+ [Compare v1.1.0...v1.1.1](https://github.com/dry-rb/dry-system/compare/v1.1.0...v1.1.1)
57
+
58
+ ## 1.1.0 2024-10-31
59
+
60
+
61
+
62
+ [Compare v1.1.0.beta2...v1.1.0](https://github.com/dry-rb/dry-system/compare/v1.1.0.beta2...v1.1.0)
63
+
64
+ ## 1.1.0.beta2 2024-09-25
65
+
66
+
67
+ ### Changed
68
+
69
+ - Allow provider sources to use a custom superclass. This requires a custom provider registrar
70
+ to be configured, with its own implementations of `#provider_source_class` (the superclass to
71
+ use) and `#provider_source_options` (custom initialization args to pass to the provider
72
+ source). (via #275) (@alassek, @timriley)
73
+
74
+ [Compare v1.1.0.beta1...v1.1.0.beta2](https://github.com/dry-rb/dry-system/compare/v1.1.0.beta1...v1.1.0.beta2)
75
+
76
+ ## 1.1.0.beta1 2024-07-03
77
+
78
+
79
+ ### Added
80
+
81
+ - Add `Dry::System::ProviderRegistrar#target_container`, to be passed when initializing
82
+ providers. By default this is an alias of `#container`. This allows for custom provider
83
+ registrars to override `#target_container` to provide a custom `#target` within providers.
84
+ An overridden value **MUST** still wrap the original `#target_container` to ensure components
85
+ are registered in the right place. (via #270) (@timriley)
86
+
87
+ ### Changed
88
+
89
+ - Make `Dry::System::ProviderRegistrar` public API (via #270) (@timriley)
90
+ - When registering a provider source, you can now provide a `provider_options:` hash of default
91
+ options for providers to be registered using that source. The one provider option currently
92
+ supported is `namespace:`. (via #271) (@timriley)
93
+ - Load providers when accessing them via `Dry::System::ProviderRegistrar#[]`. The previous,
94
+ behavior of `#[]` returning `nil` if a provider had not been explicitly loaded was a
95
+ potential source of confusion. Now `#[]` can serve as the one and only interface for fetching
96
+ a provider. (via #273) (@timriley)
97
+
98
+ [Compare v1.0.1...v1.1.0.beta1](https://github.com/dry-rb/dry-system/compare/v1.0.1...v1.1.0.beta1)
99
+
3
100
  ## 1.0.1 2022-11-18
4
101
 
5
102
 
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2022 dry-rb team
3
+ Copyright (c) 2015-2023 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
@@ -1,29 +1,22 @@
1
1
  <!--- this file is synced from dry-rb/template-gem project -->
2
+
2
3
  [gem]: https://rubygems.org/gems/dry-system
3
4
  [actions]: https://github.com/dry-rb/dry-system/actions
4
- [codacy]: https://www.codacy.com/gh/dry-rb/dry-system
5
- [chat]: https://dry-rb.zulipchat.com
6
- [inchpages]: http://inch-ci.org/github/dry-rb/dry-system
7
-
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
5
 
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]
12
- [![Codacy Badge](https://api.codacy.com/project/badge/Grade/3a0e30d0ae2542c7ba047ba5f923c0bb)][codacy]
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=main)][inchpages]
6
+ # dry-system [![Gem Version](https://badge.fury.io/rb/dry-system.svg)][gem] [![CI Status](https://github.com/dry-rb/dry-system/workflows/CI/badge.svg)][actions]
15
7
 
16
8
  ## Links
17
9
 
18
10
  * [User documentation](https://dry-rb.org/gems/dry-system)
19
11
  * [API documentation](http://rubydoc.info/gems/dry-system)
12
+ * [Forum](https://discourse.dry-rb.org)
20
13
 
21
14
  ## Supported Ruby versions
22
15
 
23
16
  This library officially supports the following Ruby versions:
24
17
 
25
- * MRI `>= 2.7.0`
26
- * jruby `>= 9.3` (postponed until 2.7 is supported)
18
+ * MRI `>= 3.1`
19
+ * jruby `>= 9.4` (not tested on CI)
27
20
 
28
21
  ## License
29
22
 
data/dry-system.gemspec CHANGED
@@ -21,20 +21,17 @@ Gem::Specification.new do |spec|
21
21
  spec.executables = []
22
22
  spec.require_paths = ["lib"]
23
23
 
24
- spec.metadata["allowed_push_host"] = "https://rubygems.org"
25
- spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-system/blob/main/CHANGELOG.md"
26
- spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-system"
27
- spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-system/issues"
24
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
25
+ spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-system/blob/main/CHANGELOG.md"
26
+ spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-system"
27
+ spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-system/issues"
28
+ spec.metadata["rubygems_mfa_required"] = "true"
28
29
 
29
- spec.required_ruby_version = ">= 2.7.0"
30
+ spec.required_ruby_version = ">= 3.1"
30
31
 
31
32
  # to update dependencies edit project.yml
32
- spec.add_runtime_dependency "dry-auto_inject", "~> 1.0", "< 2"
33
- spec.add_runtime_dependency "dry-configurable", "~> 1.0", "< 2"
34
- spec.add_runtime_dependency "dry-core", "~> 1.0", "< 2"
35
- spec.add_runtime_dependency "dry-inflector", "~> 1.0", "< 2"
36
-
37
- spec.add_development_dependency "bundler"
38
- spec.add_development_dependency "rake"
39
- spec.add_development_dependency "rspec"
33
+ spec.add_dependency "dry-auto_inject", "~> 1.1"
34
+ spec.add_dependency "dry-configurable", "~> 1.3"
35
+ spec.add_dependency "dry-core", "~> 1.1"
36
+ spec.add_dependency "dry-inflector", "~> 1.1"
40
37
  end
@@ -60,10 +60,9 @@ module Dry
60
60
  #
61
61
  # @return [Object] component's class instance
62
62
  # @api public
63
- def instance(*args)
64
- options[:instance]&.call(self, *args) || loader.call(self, *args)
63
+ def instance(*args, **kwargs)
64
+ options[:instance]&.call(self, *args, **kwargs) || loader.call(self, *args, **kwargs)
65
65
  end
66
- ruby2_keywords(:instance) if respond_to?(:ruby2_keywords, true)
67
66
 
68
67
  # Returns the component's unique key
69
68
  #
@@ -76,13 +76,13 @@ module Dry
76
76
 
77
77
  def files(namespace)
78
78
  if namespace.path?
79
- Dir[File.join(full_path, namespace.path, "**", RB_GLOB)].sort
79
+ ::Dir[::File.join(full_path, namespace.path, "**", RB_GLOB)]
80
80
  else
81
81
  non_root_paths = config.namespaces.to_a.reject(&:root?).map(&:path)
82
82
 
83
- Dir[File.join(full_path, "**", RB_GLOB)].reject { |file_path|
83
+ ::Dir[::File.join(full_path, "**", RB_GLOB)].reject { |file_path|
84
84
  Pathname(file_path).relative_path_from(full_path).to_s.start_with?(*non_root_paths)
85
- }.sort
85
+ }
86
86
  end
87
87
  end
88
88
 
@@ -155,9 +155,9 @@ module Dry
155
155
  }
156
156
  end
157
157
 
158
- def method_missing(name, *args, &block)
158
+ def method_missing(name, ...)
159
159
  if config.respond_to?(name)
160
- config.public_send(name, *args, &block)
160
+ config.public_send(name, ...)
161
161
  else
162
162
  super
163
163
  end
@@ -7,7 +7,7 @@ module Dry
7
7
  module Config
8
8
  # @api public
9
9
  class ComponentDir
10
- include Dry::Configurable
10
+ include ::Dry::Configurable
11
11
 
12
12
  # @!group Settings
13
13
 
@@ -211,9 +211,9 @@ module Dry
211
211
 
212
212
  private
213
213
 
214
- def method_missing(name, *args, &block)
214
+ def method_missing(name, ...)
215
215
  if config.respond_to?(name)
216
- config.public_send(name, *args, &block)
216
+ config.public_send(name, ...)
217
217
  else
218
218
  super
219
219
  end
@@ -110,7 +110,7 @@ module Dry
110
110
 
111
111
  # @api private
112
112
  def initialize_copy(source)
113
- @dirs = source.dirs.map { |path, dir| [path, dir.dup] }.to_h
113
+ @dirs = source.dirs.to_h { |path, dir| [path, dir.dup] }
114
114
  @defaults = source.defaults.dup
115
115
  end
116
116
 
@@ -221,8 +221,8 @@ module Dry
221
221
  # @yieldparam dir [ComponentDir] the yielded component dir
222
222
  #
223
223
  # @api public
224
- def each(&block)
225
- to_a.each(&block)
224
+ def each(&)
225
+ to_a.each(&)
226
226
  end
227
227
 
228
228
  protected
@@ -272,9 +272,9 @@ module Dry
272
272
  end
273
273
  end
274
274
 
275
- def method_missing(name, *args, &block)
275
+ def method_missing(name, ...)
276
276
  if defaults.respond_to?(name)
277
- defaults.public_send(name, *args, &block)
277
+ defaults.public_send(name, ...)
278
278
  else
279
279
  super
280
280
  end
@@ -187,8 +187,8 @@ module Dry
187
187
  # @yieldparam namespace [Namespace] the yielded namespace
188
188
  #
189
189
  # @api public
190
- def each(&block)
191
- to_a.each(&block)
190
+ def each(&)
191
+ to_a.each(&)
192
192
  end
193
193
  end
194
194
  end
@@ -8,6 +8,6 @@ module Dry
8
8
  RB_GLOB = "*.rb"
9
9
  PATH_SEPARATOR = File::SEPARATOR
10
10
  KEY_SEPARATOR = "."
11
- WORD_REGEX = /\w+/.freeze
11
+ WORD_REGEX = /\w+/
12
12
  end
13
13
  end
@@ -103,8 +103,8 @@ module Dry
103
103
  # @see after
104
104
  #
105
105
  # @api public
106
- def configure(finalize_config: true, &block)
107
- super(&block)
106
+ def configure(finalize_config: true, &)
107
+ super(&)
108
108
  configured!(finalize_config: finalize_config)
109
109
  end
110
110
 
@@ -148,7 +148,7 @@ module Dry
148
148
  #
149
149
  # @example
150
150
  # # system/container.rb
151
- # require "dry/system/container"
151
+ # require "dry/system"
152
152
  # require "logger"
153
153
  #
154
154
  # class Core < Dry::System::Container
@@ -314,23 +314,21 @@ module Dry
314
314
  # @return [self] frozen container
315
315
  #
316
316
  # @api public
317
- def finalize!(freeze: true, &block)
317
+ def finalize!(freeze: true, &)
318
318
  return self if finalized?
319
319
 
320
320
  configured!
321
321
 
322
- hooks[:before_finalize].each { |hook| instance_eval(&hook) }
323
- yield(self) if block
322
+ run_hooks(:finalize) do
323
+ yield(self) if block_given?
324
324
 
325
- providers.finalize!
326
- auto_registrar.finalize!
327
- manifest_registrar.finalize!
328
- importer.finalize!
325
+ [providers, auto_registrar, manifest_registrar, importer].each(&:finalize!)
329
326
 
330
- @__finalized__ = true
327
+ @__finalized__ = true
328
+ end
331
329
 
332
330
  self.freeze if freeze
333
- hooks[:after_finalize].each { |hook| instance_eval(&hook) }
331
+
334
332
  self
335
333
  end
336
334
 
@@ -462,7 +460,7 @@ module Dry
462
460
  # @api public
463
461
  def require_from_root(*paths)
464
462
  paths.flat_map { |path|
465
- path.to_s.include?("*") ? ::Dir[root.join(path)].sort : root.join(path)
463
+ path.to_s.include?("*") ? ::Dir[root.join(path)] : root.join(path)
466
464
  }.each { |path|
467
465
  Kernel.require path.to_s
468
466
  }
@@ -486,6 +484,15 @@ module Dry
486
484
  config.root
487
485
  end
488
486
 
487
+ # @api public
488
+ def register(key, *)
489
+ super
490
+
491
+ hooks[:after_register].each { |hook| instance_exec(key, &hook) }
492
+
493
+ self
494
+ end
495
+
489
496
  # @api public
490
497
  def resolve(key)
491
498
  load_component(key) unless finalized?
@@ -608,22 +615,22 @@ module Dry
608
615
  def load_component(key)
609
616
  return self if registered?(key)
610
617
 
611
- if (provider = providers.find_and_load_provider(key))
618
+ if (provider = providers[key])
612
619
  provider.start
613
620
  return self
614
621
  end
615
622
 
616
623
  component = find_component(key)
617
624
 
618
- providers.start_provider_dependency(component)
625
+ providers[component.root_key]&.start
619
626
  return self if registered?(key)
620
627
 
621
628
  if component.loadable?
622
629
  load_local_component(component)
623
630
  elsif manifest_registrar.file_exists?(component)
624
631
  manifest_registrar.(component)
625
- elsif importer.namespace?(component.identifier.root_key)
626
- load_imported_component(component.identifier, namespace: component.identifier.root_key)
632
+ elsif importer.namespace?(component.root_key)
633
+ load_imported_component(component.identifier, namespace: component.root_key)
627
634
  elsif importer.namespace?(nil)
628
635
  load_imported_component(component.identifier, namespace: nil)
629
636
  end
@@ -659,6 +666,12 @@ module Dry
659
666
  end
660
667
  } || IndirectComponent.new(Identifier.new(key))
661
668
  end
669
+
670
+ def run_hooks(event)
671
+ hooks[:"before_#{event}"].each { instance_eval(&_1) }
672
+ yield
673
+ hooks[:"after_#{event}"].each { instance_eval(&_1) }
674
+ end
662
675
  end
663
676
 
664
677
  # Default hooks
@@ -125,7 +125,7 @@ module Dry
125
125
  end
126
126
  end
127
127
 
128
- super message.join("\n")
128
+ super(message.join("\n"))
129
129
  end
130
130
  end
131
131
  end
@@ -43,18 +43,17 @@ module Dry
43
43
  # @return [Object]
44
44
  #
45
45
  # @api public
46
- def call(component, *args)
46
+ def call(component, *args, **kwargs)
47
47
  require!(component)
48
48
 
49
49
  constant = self.constant(component)
50
50
 
51
51
  if singleton?(constant)
52
- constant.instance(*args)
52
+ constant.instance(*args, **kwargs)
53
53
  else
54
- constant.new(*args)
54
+ constant.new(*args, **kwargs)
55
55
  end
56
56
  end
57
- ruby2_keywords(:call) if respond_to?(:ruby2_keywords, true)
58
57
 
59
58
  # Returns the component's class constant
60
59
  #
@@ -67,7 +66,7 @@ module Dry
67
66
  inflector.constantize(const_name)
68
67
  rescue NameError => e
69
68
  # Ensure it's this component's constant, not any other NameError within the component
70
- if e.message =~ /#{const_name}( |\n)/
69
+ if e.message =~ /#{const_name}( |\n|$)/
71
70
  raise ComponentNotLoadableError.new(component, e)
72
71
  else
73
72
  raise e
@@ -3,8 +3,8 @@
3
3
  module Dry
4
4
  module System
5
5
  class MagicCommentsParser
6
- VALID_LINE_RE = /^(#.*)?$/.freeze
7
- COMMENT_RE = /^#\s+(?<name>[A-Za-z]{1}[A-Za-z0-9_]+):\s+(?<value>.+?)$/.freeze
6
+ VALID_LINE_RE = /^(#.*)?$/
7
+ COMMENT_RE = /^#\s+(?<name>[A-Za-z]{1}[A-Za-z0-9_]+):\s+(?<value>.+?)$/
8
8
 
9
9
  COERCIONS = {
10
10
  "true" => true,
@@ -26,19 +26,19 @@ module Dry
26
26
 
27
27
  # @api private
28
28
  def finalize!
29
- ::Dir[registrations_dir.join(RB_GLOB)].sort.each do |file|
29
+ ::Dir[registrations_dir.join(RB_GLOB)].each do |file|
30
30
  call(Identifier.new(File.basename(file, RB_EXT)))
31
31
  end
32
32
  end
33
33
 
34
34
  # @api private
35
35
  def call(component)
36
- require(root.join(config.registrations_dir, component.root_key.to_s))
36
+ load(root.join(config.registrations_dir, "#{component.root_key}#{RB_EXT}"))
37
37
  end
38
38
 
39
39
  # @api private
40
40
  def file_exists?(component)
41
- File.exist?(File.join(registrations_dir, "#{component.root_key}#{RB_EXT}"))
41
+ ::File.exist?(::File.join(registrations_dir, "#{component.root_key}#{RB_EXT}"))
42
42
  end
43
43
 
44
44
  private
@@ -6,10 +6,8 @@ module Dry
6
6
  module Bootsnap
7
7
  DEFAULT_OPTIONS = {
8
8
  load_path_cache: true,
9
- disable_trace: true,
10
9
  compile_cache_iseq: true,
11
- compile_cache_yaml: true,
12
- autoload_paths_cache: false
10
+ compile_cache_yaml: true
13
11
  }.freeze
14
12
 
15
13
  # @api private
@@ -32,12 +30,16 @@ module Dry
32
30
  def setup_bootsnap
33
31
  return unless bootsnap_available?
34
32
 
35
- ::Bootsnap.setup(config.bootsnap.merge(cache_dir: root.join("tmp/cache").to_s))
33
+ ::Bootsnap.setup(**config.bootsnap, cache_dir: root.join("tmp/cache").to_s)
36
34
  end
37
35
 
38
36
  # @api private
39
37
  def bootsnap_available?
40
- RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.3.0" && RUBY_VERSION < "3.1.0"
38
+ spec = Gem.loaded_specs["bootsnap"] or return false
39
+
40
+ RUBY_ENGINE == "ruby" &&
41
+ spec.match_platform(RUBY_PLATFORM) &&
42
+ spec.required_ruby_version.satisfied_by?(Gem::Version.new(RUBY_VERSION))
41
43
  end
42
44
  end
43
45
  end
@@ -20,7 +20,7 @@ module Dry
20
20
  target_class: klass
21
21
  )
22
22
 
23
- super(klass)
23
+ super
24
24
  end
25
25
  end
26
26
 
@@ -36,7 +36,7 @@ module Dry
36
36
  target_class: klass
37
37
  )
38
38
 
39
- super(klass)
39
+ super
40
40
  end
41
41
  end
42
42
 
@@ -51,7 +51,7 @@ module Dry
51
51
  target_class: klass
52
52
  )
53
53
 
54
- super(klass)
54
+ super
55
55
  end
56
56
  end
57
57
 
@@ -34,7 +34,7 @@ module Dry
34
34
  end
35
35
 
36
36
  # @api private
37
- def register(key, contents = nil, options = {}, &block)
37
+ def register(key, contents = nil, options = {}, &)
38
38
  super.tap do
39
39
  key = key.to_s
40
40
 
@@ -30,13 +30,13 @@ module Dry
30
30
  resolve(key).tap do |target|
31
31
  proxy = Proxy.for(target, **options, key: key)
32
32
 
33
- if block
33
+ if block_given?
34
34
  proxy.monitored_methods.each do |meth|
35
35
  notifications.subscribe(:monitoring, target: key, method: meth, &block)
36
36
  end
37
37
  end
38
38
 
39
- decorate(key, with: -> target { proxy.new(target, notifications) })
39
+ decorate(key, with: -> tgt { proxy.new(tgt, notifications) })
40
40
  end
41
41
  end
42
42
  end
@@ -11,8 +11,8 @@ module Dry
11
11
  # @return [Plugins]
12
12
  #
13
13
  # @api public
14
- def self.register(name, plugin, &block)
15
- registry[name] = Plugin.new(name, plugin, &block)
14
+ def self.register(name, plugin, &)
15
+ registry[name] = Plugin.new(name, plugin, &)
16
16
  end
17
17
 
18
18
  # @api private
@@ -37,11 +37,21 @@ module Dry
37
37
  # @see Dry::System::Provider::SourceDSL
38
38
  #
39
39
  # @api private
40
- def for(name:, group: nil, &block)
41
- Class.new(self) { |klass|
40
+ def for(name:, group: nil, superclass: nil, &block)
41
+ superclass ||= self
42
+
43
+ ::Class.new(superclass) { |klass|
42
44
  klass.source_name name
43
45
  klass.source_group group
44
- SourceDSL.evaluate(klass, &block) if block
46
+
47
+ name_with_group = group ? "#{group}->#{name}" : name
48
+ klass.instance_eval(<<~RUBY, __FILE__, __LINE__ + 1)
49
+ def name # def name
50
+ "#{superclass.name}[#{name_with_group}]" # "CustomSource[custom]"
51
+ end # end
52
+ RUBY
53
+
54
+ SourceDSL.evaluate(klass, &block) if block_given?
45
55
  }
46
56
  end
47
57
 
@@ -58,14 +68,6 @@ module Dry
58
68
  end
59
69
  end
60
70
 
61
- # @api private
62
- def name
63
- source_str = source_name
64
- source_str = "#{source_group}->#{source_str}" if source_group
65
-
66
- "Dry::System::Provider::Source[#{source_str}]"
67
- end
68
-
69
71
  # @api private
70
72
  def to_s
71
73
  "#<#{name}>"
@@ -117,15 +119,18 @@ module Dry
117
119
  #
118
120
  # @api public
119
121
  attr_reader :target_container
120
- alias_method :target, :target_container
122
+
123
+ # @see #target_container
124
+ # @api public
125
+ def target = target_container
121
126
 
122
127
  # @api private
123
- def initialize(provider_container:, target_container:, &block)
128
+ def initialize(provider_container:, target_container:, &)
124
129
  super()
125
130
  @callbacks = {before: CALLBACK_MAP.dup, after: CALLBACK_MAP.dup}
126
131
  @provider_container = provider_container
127
132
  @target_container = target_container
128
- instance_exec(&block) if block
133
+ instance_exec(&) if block_given?
129
134
  end
130
135
 
131
136
  # Returns a string containing a human-readable representation of the provider.
@@ -258,7 +263,7 @@ module Dry
258
263
  end
259
264
 
260
265
  # @api private
261
- def method_missing(name, *args, &block)
266
+ def method_missing(name, *args, &)
262
267
  if container.key?(name)
263
268
  container[name]
264
269
  else
@@ -10,8 +10,8 @@ module Dry
10
10
  #
11
11
  # @api private
12
12
  class SourceDSL
13
- def self.evaluate(source_class, &block)
14
- new(source_class).instance_eval(&block)
13
+ def self.evaluate(source_class, &)
14
+ new(source_class).instance_eval(&)
15
15
  end
16
16
 
17
17
  attr_reader :source_class
@@ -24,23 +24,23 @@ module Dry
24
24
  source_class.setting(...)
25
25
  end
26
26
 
27
- def prepare(&block)
28
- source_class.define_method(:prepare, &block)
27
+ def prepare(&)
28
+ source_class.define_method(:prepare, &)
29
29
  end
30
30
 
31
- def start(&block)
32
- source_class.define_method(:start, &block)
31
+ def start(&)
32
+ source_class.define_method(:start, &)
33
33
  end
34
34
 
35
- def stop(&block)
36
- source_class.define_method(:stop, &block)
35
+ def stop(&)
36
+ source_class.define_method(:stop, &)
37
37
  end
38
38
 
39
39
  private
40
40
 
41
- def method_missing(name, *args, &block)
41
+ def method_missing(name, ...)
42
42
  if source_class.respond_to?(name)
43
- source_class.public_send(name, *args, &block)
43
+ source_class.public_send(name, ...)
44
44
  else
45
45
  super
46
46
  end
@@ -127,7 +127,8 @@ module Dry
127
127
  attr_reader :source
128
128
 
129
129
  # @api private
130
- def initialize(name:, namespace: nil, target_container:, source_class:, &block) # rubocop:disable Style/KeywordParametersOrder
130
+ # rubocop:disable Style/KeywordParametersOrder
131
+ def initialize(name:, namespace: nil, target_container:, source_class:, source_options: {}, &)
131
132
  @name = name
132
133
  @namespace = namespace
133
134
  @target_container = target_container
@@ -137,11 +138,13 @@ module Dry
137
138
  @step_running = nil
138
139
 
139
140
  @source = source_class.new(
141
+ **source_options,
140
142
  provider_container: provider_container,
141
143
  target_container: target_container,
142
- &block
144
+ &
143
145
  )
144
146
  end
147
+ # rubocop:enable Style/KeywordParametersOrder
145
148
 
146
149
  # Runs the `prepare` lifecycle step.
147
150
  #
@@ -13,7 +13,8 @@ module Dry
13
13
  # provider registrar is responsible for loading provider files and exposing an API for
14
14
  # running the provider lifecycle steps.
15
15
  #
16
- # @api private
16
+ # @api public
17
+ # @since 1.1.0
17
18
  class ProviderRegistrar
18
19
  # @api private
19
20
  attr_reader :providers
@@ -21,6 +22,14 @@ module Dry
21
22
  # @api private
22
23
  attr_reader :container
23
24
 
25
+ # Returns the container exposed to providers as `target_container`.
26
+ #
27
+ # @return [Dry::System::Container]
28
+ #
29
+ # @api public
30
+ # @since 1.1.0
31
+ alias_method :target_container, :container
32
+
24
33
  # @api private
25
34
  def initialize(container)
26
35
  @providers = {}
@@ -37,14 +46,14 @@ module Dry
37
46
 
38
47
  # @see Container.register_provider
39
48
  # @api private
40
- def register_provider(name, namespace: nil, from: nil, source: nil, if: true, &block)
49
+ def register_provider(name, from: nil, source: nil, if: true, **provider_options, &)
41
50
  raise ProviderAlreadyRegisteredError, name if providers.key?(name)
42
51
 
43
52
  if from && source.is_a?(Class)
44
53
  raise ArgumentError, "You must supply a block when using a provider source"
45
54
  end
46
55
 
47
- if block && source.is_a?(Class)
56
+ if block_given? && source.is_a?(Class)
48
57
  raise ArgumentError, "You must supply only a `source:` option or a block, not both"
49
58
  end
50
59
 
@@ -54,13 +63,18 @@ module Dry
54
63
  if from
55
64
  build_provider_from_source(
56
65
  name,
57
- namespace: namespace,
58
66
  source: source || name,
59
67
  group: from,
60
- &block
68
+ options: provider_options,
69
+ &
61
70
  )
62
71
  else
63
- build_provider(name, namespace: namespace, source: source, &block)
72
+ build_provider(
73
+ name,
74
+ source: source,
75
+ options: provider_options,
76
+ &
77
+ )
64
78
  end
65
79
 
66
80
  providers[provider.name] = provider
@@ -70,43 +84,31 @@ module Dry
70
84
 
71
85
  # rubocop:enable Metrics/PerceivedComplexity
72
86
 
73
- # Returns a provider for the given name, if it has already been loaded
74
- #
75
- # @api public
76
- def [](provider_name)
77
- providers[provider_name]
78
- end
79
- alias_method :provider, :[]
80
-
81
- # @api private
82
- def key?(provider_name)
83
- providers.key?(provider_name)
84
- end
85
-
86
87
  # Returns a provider if it can be found or loaded, otherwise nil
87
88
  #
88
89
  # @return [Dry::System::Provider, nil]
89
90
  #
90
- # @api private
91
- def find_and_load_provider(name)
92
- name = name.to_sym
91
+ # @api public
92
+ def [](provider_name)
93
+ provider_name = provider_name.to_sym
93
94
 
94
- if (provider = providers[name])
95
+ if (provider = providers[provider_name])
95
96
  return provider
96
97
  end
97
98
 
98
99
  return if finalized?
99
100
 
100
- require_provider_file(name)
101
+ require_provider_file(provider_name)
101
102
 
102
- providers[name]
103
+ providers[provider_name]
103
104
  end
104
105
 
106
+ # @api public
107
+ alias_method :find_and_load_provider, :[]
108
+
105
109
  # @api private
106
- def start_provider_dependency(component)
107
- if (provider = find_and_load_provider(component.root_key))
108
- provider.start
109
- end
110
+ def key?(provider_name)
111
+ providers.key?(provider_name)
110
112
  end
111
113
 
112
114
  # Returns all provider files within the configured provider_paths.
@@ -124,10 +126,10 @@ module Dry
124
126
  # @api public
125
127
  def provider_files
126
128
  @provider_files ||= provider_paths.each_with_object([[], []]) { |path, (provider_files, loaded)| # rubocop:disable Layout/LineLength
127
- files = Dir["#{path}/#{RB_GLOB}"].sort
129
+ files = ::Dir["#{path}/#{RB_GLOB}"]
128
130
 
129
131
  files.each do |file|
130
- basename = File.basename(file)
132
+ basename = ::File.basename(file)
131
133
 
132
134
  unless loaded.include?(basename)
133
135
  provider_files << Pathname(file)
@@ -137,6 +139,21 @@ module Dry
137
139
  }.first
138
140
  end
139
141
 
142
+ # Extension point for subclasses to customize their
143
+ # provider source superclass. Expected to be a subclass
144
+ # of Dry::System::Provider::Source
145
+ #
146
+ # @api public
147
+ # @since 1.1.0
148
+ def provider_source_class = Dry::System::Provider::Source
149
+
150
+ # Extension point for subclasses to customize initialization
151
+ # params for provider_source_class
152
+ #
153
+ # @api public
154
+ # @since 1.1.0
155
+ def provider_source_options = {}
156
+
140
157
  # @api private
141
158
  def finalize!
142
159
  provider_files.each do |path|
@@ -196,26 +213,47 @@ module Dry
196
213
  }
197
214
  end
198
215
 
199
- def build_provider(name, namespace:, source: nil, &block)
200
- source_class = source || Provider::Source.for(name: name, &block)
216
+ def build_provider(name, options:, source: nil, &)
217
+ source_class = source || Provider::Source.for(
218
+ name: name,
219
+ superclass: provider_source_class,
220
+ &
221
+ )
222
+
223
+ source_options =
224
+ if source_class < provider_source_class
225
+ provider_source_options
226
+ else
227
+ {}
228
+ end
201
229
 
202
230
  Provider.new(
231
+ **options,
203
232
  name: name,
204
- namespace: namespace,
205
- target_container: container,
206
- source_class: source_class
233
+ target_container: target_container,
234
+ source_class: source_class,
235
+ source_options: source_options
207
236
  )
208
237
  end
209
238
 
210
- def build_provider_from_source(name, source:, group:, namespace:, &block)
211
- source_class = System.provider_sources.resolve(name: source, group: group)
239
+ def build_provider_from_source(name, source:, group:, options:, &)
240
+ provider_source = System.provider_sources.resolve(name: source, group: group)
241
+
242
+ source_options =
243
+ if provider_source.source <= provider_source_class
244
+ provider_source_options
245
+ else
246
+ {}
247
+ end
212
248
 
213
249
  Provider.new(
250
+ **provider_source.provider_options,
251
+ **options,
214
252
  name: name,
215
- namespace: namespace,
216
- target_container: container,
217
- source_class: source_class,
218
- &block
253
+ target_container: target_container,
254
+ source_class: provider_source.source,
255
+ source_options: source_options,
256
+ &
219
257
  )
220
258
  end
221
259
 
@@ -6,6 +6,17 @@ module Dry
6
6
  module System
7
7
  # @api private
8
8
  class ProviderSourceRegistry
9
+ # @api private
10
+ class Registration
11
+ attr_reader :source
12
+ attr_reader :provider_options
13
+
14
+ def initialize(source:, provider_options:)
15
+ @source = source
16
+ @provider_options = provider_options
17
+ end
18
+ end
19
+
9
20
  attr_reader :sources
10
21
 
11
22
  def initialize
@@ -13,24 +24,24 @@ module Dry
13
24
  end
14
25
 
15
26
  def load_sources(path)
16
- Dir[File.join(path, "**/#{RB_GLOB}")].sort.each do |file|
27
+ ::Dir[::File.join(path, "**/#{RB_GLOB}")].each do |file|
17
28
  require file
18
29
  end
19
30
  end
20
31
 
21
- def register(name:, group:, source:)
22
- sources[key(name, group)] = source
32
+ def register(name:, group:, source:, provider_options:)
33
+ sources[key(name, group)] = Registration.new(
34
+ source: source,
35
+ provider_options: provider_options
36
+ )
23
37
  end
24
38
 
25
- def register_from_block(name:, group:, &block)
39
+ def register_from_block(name:, group:, provider_options:, &)
26
40
  register(
27
41
  name: name,
28
42
  group: group,
29
- source: Provider::Source.for(
30
- name: name,
31
- group: group,
32
- &block
33
- )
43
+ source: Provider::Source.for(name: name, group: group, &),
44
+ provider_options: provider_options
34
45
  )
35
46
  end
36
47
 
@@ -55,9 +55,9 @@ module Dry
55
55
 
56
56
  private
57
57
 
58
- def method_missing(name, *args, &block)
58
+ def method_missing(name, ...)
59
59
  if config.respond_to?(name)
60
- config.public_send(name, *args, &block)
60
+ config.public_send(name, ...)
61
61
  else
62
62
  super
63
63
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "pathname"
3
4
  require "dry/system"
4
5
 
5
6
  Dry::System.register_provider_sources Pathname(__dir__).join("provider_sources").realpath
@@ -11,8 +11,8 @@ module Dry
11
11
  # of the container
12
12
  #
13
13
  # @api private
14
- def finalize!(**, &block)
15
- super(freeze: false, &block)
14
+ def finalize!(**, &)
15
+ super(freeze: false, &)
16
16
  end
17
17
  end
18
18
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module System
5
- VERSION = "1.0.1"
5
+ VERSION = "1.2.3"
6
6
  end
7
7
  end
data/lib/dry/system.rb CHANGED
@@ -30,15 +30,25 @@ module Dry
30
30
  # Registers a provider source, which can be used as the basis for other providers
31
31
  #
32
32
  # @api public
33
- def self.register_provider_source(name, group:, source: nil, &block)
34
- if source && block
33
+ def self.register_provider_source(name, group:, source: nil, provider_options: {}, &)
34
+ if source && block_given?
35
35
  raise ArgumentError, "You must supply only a `source:` option or a block, not both"
36
36
  end
37
37
 
38
38
  if source
39
- provider_sources.register(name: name, group: group, source: source)
39
+ provider_sources.register(
40
+ name: name,
41
+ group: group,
42
+ source: source,
43
+ provider_options: provider_options
44
+ )
40
45
  else
41
- provider_sources.register_from_block(name: name, group: group, &block)
46
+ provider_sources.register_from_block(
47
+ name: name,
48
+ group: group,
49
+ provider_options: provider_options,
50
+ &
51
+ )
42
52
  end
43
53
  end
44
54
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-system
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-18 00:00:00.000000000 Z
11
+ date: 2025-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-auto_inject
@@ -16,122 +16,56 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: '2'
19
+ version: '1.1'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - "~>"
28
25
  - !ruby/object:Gem::Version
29
- version: '1.0'
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: '2'
26
+ version: '1.1'
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: dry-configurable
35
29
  requirement: !ruby/object:Gem::Requirement
36
30
  requirements:
37
31
  - - "~>"
38
32
  - !ruby/object:Gem::Version
39
- version: '1.0'
40
- - - "<"
41
- - !ruby/object:Gem::Version
42
- version: '2'
33
+ version: '1.3'
43
34
  type: :runtime
44
35
  prerelease: false
45
36
  version_requirements: !ruby/object:Gem::Requirement
46
37
  requirements:
47
38
  - - "~>"
48
39
  - !ruby/object:Gem::Version
49
- version: '1.0'
50
- - - "<"
51
- - !ruby/object:Gem::Version
52
- version: '2'
40
+ version: '1.3'
53
41
  - !ruby/object:Gem::Dependency
54
42
  name: dry-core
55
43
  requirement: !ruby/object:Gem::Requirement
56
44
  requirements:
57
45
  - - "~>"
58
46
  - !ruby/object:Gem::Version
59
- version: '1.0'
60
- - - "<"
61
- - !ruby/object:Gem::Version
62
- version: '2'
47
+ version: '1.1'
63
48
  type: :runtime
64
49
  prerelease: false
65
50
  version_requirements: !ruby/object:Gem::Requirement
66
51
  requirements:
67
52
  - - "~>"
68
53
  - !ruby/object:Gem::Version
69
- version: '1.0'
70
- - - "<"
71
- - !ruby/object:Gem::Version
72
- version: '2'
54
+ version: '1.1'
73
55
  - !ruby/object:Gem::Dependency
74
56
  name: dry-inflector
75
57
  requirement: !ruby/object:Gem::Requirement
76
58
  requirements:
77
59
  - - "~>"
78
60
  - !ruby/object:Gem::Version
79
- version: '1.0'
80
- - - "<"
81
- - !ruby/object:Gem::Version
82
- version: '2'
61
+ version: '1.1'
83
62
  type: :runtime
84
63
  prerelease: false
85
64
  version_requirements: !ruby/object:Gem::Requirement
86
65
  requirements:
87
66
  - - "~>"
88
67
  - !ruby/object:Gem::Version
89
- version: '1.0'
90
- - - "<"
91
- - !ruby/object:Gem::Version
92
- version: '2'
93
- - !ruby/object:Gem::Dependency
94
- name: bundler
95
- requirement: !ruby/object:Gem::Requirement
96
- requirements:
97
- - - ">="
98
- - !ruby/object:Gem::Version
99
- version: '0'
100
- type: :development
101
- prerelease: false
102
- version_requirements: !ruby/object:Gem::Requirement
103
- requirements:
104
- - - ">="
105
- - !ruby/object:Gem::Version
106
- version: '0'
107
- - !ruby/object:Gem::Dependency
108
- name: rake
109
- requirement: !ruby/object:Gem::Requirement
110
- requirements:
111
- - - ">="
112
- - !ruby/object:Gem::Version
113
- version: '0'
114
- type: :development
115
- prerelease: false
116
- version_requirements: !ruby/object:Gem::Requirement
117
- requirements:
118
- - - ">="
119
- - !ruby/object:Gem::Version
120
- version: '0'
121
- - !ruby/object:Gem::Dependency
122
- name: rspec
123
- requirement: !ruby/object:Gem::Requirement
124
- requirements:
125
- - - ">="
126
- - !ruby/object:Gem::Version
127
- version: '0'
128
- type: :development
129
- prerelease: false
130
- version_requirements: !ruby/object:Gem::Requirement
131
- requirements:
132
- - - ">="
133
- - !ruby/object:Gem::Version
134
- version: '0'
68
+ version: '1.1'
135
69
  description: Organize your code into reusable components
136
70
  email:
137
71
  - piotr.solnica@gmail.com
@@ -193,7 +127,8 @@ metadata:
193
127
  changelog_uri: https://github.com/dry-rb/dry-system/blob/main/CHANGELOG.md
194
128
  source_code_uri: https://github.com/dry-rb/dry-system
195
129
  bug_tracker_uri: https://github.com/dry-rb/dry-system/issues
196
- post_install_message:
130
+ rubygems_mfa_required: 'true'
131
+ post_install_message:
197
132
  rdoc_options: []
198
133
  require_paths:
199
134
  - lib
@@ -201,15 +136,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
201
136
  requirements:
202
137
  - - ">="
203
138
  - !ruby/object:Gem::Version
204
- version: 2.7.0
139
+ version: '3.1'
205
140
  required_rubygems_version: !ruby/object:Gem::Requirement
206
141
  requirements:
207
142
  - - ">="
208
143
  - !ruby/object:Gem::Version
209
144
  version: '0'
210
145
  requirements: []
211
- rubygems_version: 3.1.6
212
- signing_key:
146
+ rubygems_version: 3.3.27
147
+ signing_key:
213
148
  specification_version: 4
214
149
  summary: Organize your code into reusable components
215
150
  test_files: []