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
@@ -1,7 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "dry/core/deprecations"
4
+
3
5
  module Dry
4
6
  module System
7
+ extend Dry::Core::Deprecations["dry-system"]
8
+
5
9
  # Error raised when a component dir is added to configuration more than once
6
10
  #
7
11
  # @api public
@@ -11,8 +15,19 @@ module Dry
11
15
  end
12
16
  end
13
17
 
18
+ # Error raised when a configured component directory could not be found
19
+ #
20
+ # @api public
21
+ ComponentDirNotFoundError = Class.new(StandardError) do
22
+ def initialize(dir)
23
+ super("Component dir '#{dir}' not found")
24
+ end
25
+ end
26
+
14
27
  # Error raised when a namespace for a component dir is added to configuration more
15
28
  # than once
29
+ #
30
+ # @api public
16
31
  NamespaceAlreadyAddedError = Class.new(StandardError) do
17
32
  def initialize(path)
18
33
  path_label = path ? "path #{path.inspect}" : "root path"
@@ -21,45 +36,40 @@ module Dry
21
36
  end
22
37
  end
23
38
 
24
- # Error raised when booter file do not match with register component
25
- #
26
- # @api public
27
- ComponentFileMismatchError = Class.new(StandardError) do
28
- def initialize(component)
29
- super(<<-STR)
30
- Bootable component '#{component.name}' not found
31
- STR
32
- end
33
- end
34
-
35
- # Error raised when resolved component couldn't be loaded
39
+ # Error raised when attempting to register provider using a name that has already been
40
+ # registered
36
41
  #
37
42
  # @api public
38
- InvalidComponentError = Class.new(ArgumentError) do
39
- def initialize(name, reason = nil)
40
- super(
41
- "Tried to create an invalid #{name.inspect} component - #{reason}"
42
- )
43
+ ProviderAlreadyRegisteredError = Class.new(ArgumentError) do
44
+ def initialize(provider_name)
45
+ super("Provider #{provider_name.inspect} has already been registered")
43
46
  end
44
47
  end
48
+ DuplicatedComponentKeyError = ProviderAlreadyRegisteredError
49
+ deprecate_constant :DuplicatedComponentKeyError
45
50
 
46
- # Error raised when component's name is not valid
51
+ # Error raised when a named provider could not be found
47
52
  #
48
53
  # @api public
49
- InvalidComponentNameError = Class.new(ArgumentError) do
54
+ ProviderNotFoundError = Class.new(ArgumentError) do
50
55
  def initialize(name)
51
- super(
52
- "component +#{name}+ is invalid or boot file is missing"
53
- )
56
+ super("Provider #{name.inspect} not found")
54
57
  end
55
58
  end
59
+ InvalidComponentError = ProviderNotFoundError
60
+ deprecate_constant :InvalidComponentError
56
61
 
57
- # Error raised when trying to stop a component that hasn't started yet
62
+ # Error raised when a named provider source could not be found
58
63
  #
59
64
  # @api public
60
- ComponentNotStartedError = Class.new(StandardError) do
61
- def initialize(component_name)
62
- super("component +#{component_name}+ has not been started")
65
+ ProviderSourceNotFoundError = Class.new(StandardError) do
66
+ def initialize(name:, group:, keys:)
67
+ msg = "Provider source not found: #{name.inspect}, group: #{group.inspect}"
68
+
69
+ key_list = keys.map { |key| "- #{key[:name].inspect}, group: #{key[:group].inspect}" }
70
+ msg += "Available provider sources:\n\n#{key_list}"
71
+
72
+ super(msg)
63
73
  end
64
74
  end
65
75
 
@@ -72,43 +82,53 @@ module Dry
72
82
  end
73
83
  end
74
84
 
75
- # Error raised when a configured component directory could not be found
85
+ # Exception raise when a plugin dependency failed to load
76
86
  #
77
87
  # @api public
78
- ComponentDirNotFoundError = Class.new(StandardError) do
79
- def initialize(dir)
80
- super("Component dir '#{dir}' not found")
88
+ PluginDependencyMissing = Class.new(StandardError) do
89
+ # @api private
90
+ def initialize(plugin, message, gem = nil)
91
+ details = gem ? "#{message} - add #{gem} to your Gemfile" : message
92
+ super("dry-system plugin #{plugin.inspect} failed to load its dependencies: #{details}")
81
93
  end
82
94
  end
83
95
 
84
- DuplicatedComponentKeyError = Class.new(ArgumentError)
85
-
86
- InvalidSettingsError = Class.new(ArgumentError) do
96
+ # Exception raised when auto-registerable component is not loadable
97
+ #
98
+ # @api public
99
+ ComponentNotLoadableError = Class.new(NameError) do
87
100
  # @api private
88
- def initialize(attributes)
89
- message = <<~STR
90
- Could not initialize settings. The following settings were invalid:
101
+ def initialize(component, error,
102
+ corrections: DidYouMean::ClassNameChecker.new(error).corrections)
103
+ full_class_name = [error.receiver, error.name].join("::")
91
104
 
92
- #{attributes_errors(attributes).join("\n")}
93
- STR
94
- super(message)
95
- end
105
+ message = [
106
+ "Component '#{component.key}' is not loadable.",
107
+ "Looking for #{full_class_name}."
108
+ ]
96
109
 
97
- private
110
+ if corrections.any?
111
+ case_correction = corrections.find { |correction| correction.casecmp?(full_class_name) }
112
+ if case_correction
113
+ acronyms_needed = case_correction.split("::").difference(full_class_name.split("::"))
114
+ stringified_acronyms_needed = acronyms_needed.map { |acronym|
115
+ "'#{acronym}'"
116
+ } .join(", ")
117
+ message <<
118
+ <<~ERROR_MESSAGE
98
119
 
99
- def attributes_errors(attributes)
100
- attributes.map { |key, error| "#{key.name}: #{error}" }
101
- end
102
- end
120
+ You likely need to add:
103
121
 
104
- # Exception raise when a plugin dependency failed to load
105
- #
106
- # @api public
107
- PluginDependencyMissing = Class.new(StandardError) do
108
- # @api private
109
- def initialize(plugin, message, gem = nil)
110
- details = gem ? "#{message} - add #{gem} to your Gemfile" : message
111
- super("dry-system plugin #{plugin.inspect} failed to load its dependencies: #{details}")
122
+ acronym(#{stringified_acronyms_needed})
123
+
124
+ to your container's inflector, since we found a #{case_correction} class.
125
+ ERROR_MESSAGE
126
+ else
127
+ message << DidYouMean.formatter.message_for(corrections)
128
+ end
129
+ end
130
+
131
+ super message.join("\n")
112
132
  end
113
133
  end
114
134
  end
@@ -13,20 +13,15 @@ module Dry
13
13
  #
14
14
  # @api public
15
15
  class Identifier
16
- include Dry::Equalizer(:key, :separator)
16
+ include Dry::Equalizer(:key)
17
17
 
18
18
  # @return [String] the identifier's string key
19
19
  # @api public
20
20
  attr_reader :key
21
21
 
22
- # @return [String] the configured namespace separator
23
- # @api public
24
- attr_reader :separator
25
-
26
22
  # @api private
27
- def initialize(key, separator: DEFAULT_SEPARATOR)
23
+ def initialize(key)
28
24
  @key = key.to_s
29
- @separator = separator
30
25
  end
31
26
 
32
27
  # @!method to_s
@@ -49,11 +44,9 @@ module Dry
49
44
  segments.first.to_sym
50
45
  end
51
46
 
52
- # Returns true if the given leading namespaces are a leading part of the
53
- # identifier's key
47
+ # Returns true if the given leading segments string is a leading part of the {key}.
54
48
  #
55
- # Also returns true if nil is given (technically, from nothing everything is
56
- # wrought)
49
+ # Also returns true if nil or an empty string is given.
57
50
  #
58
51
  # @example
59
52
  # identifier.key # => "articles.operations.create"
@@ -63,13 +56,62 @@ module Dry
63
56
  # identifier.start_with?("article") # => false
64
57
  # identifier.start_with?(nil) # => true
65
58
  #
66
- # @param leading_namespaces [String] the one or more leading namespaces to check
59
+ # @param leading_segments [String] the one or more leading segments to check
60
+ # @return [Boolean]
61
+ # @api public
62
+ def start_with?(leading_segments)
63
+ leading_segments.to_s.empty? ||
64
+ key.start_with?("#{leading_segments}#{KEY_SEPARATOR}") ||
65
+ key.eql?(leading_segments)
66
+ end
67
+
68
+ # Returns true if the given trailing segments string is the end part of the {key}.
69
+ #
70
+ # Also returns true if nil or an empty string is given.
71
+ #
72
+ # @example
73
+ # identifier.key # => "articles.operations.create"
74
+ #
75
+ # identifier.end_with?("create") # => true
76
+ # identifier.end_with?("operations.create") # => true
77
+ # identifier.end_with?("ate") # => false, not a whole segment
78
+ # identifier.end_with?("nup") # => false, not in key at all
79
+ #
80
+ # @param trailing_segments [String] the one or more trailing key segments to check
81
+ # @return [Boolean]
82
+ # @api public
83
+ def end_with?(trailing_segments)
84
+ trailing_segments.to_s.empty? ||
85
+ key.end_with?("#{KEY_SEPARATOR}#{trailing_segments}") ||
86
+ key.eql?(trailing_segments)
87
+ end
88
+
89
+ # Returns true if the given segments string matches whole segments within the {key}.
90
+ #
91
+ # @example
92
+ # identifier.key # => "articles.operations.create"
93
+ #
94
+ # identifier.include?("operations") # => true
95
+ # identifier.include?("articles.operations") # => true
96
+ # identifier.include?("operations.create") # => true
97
+ #
98
+ # identifier.include?("article") # => false, not a whole segment
99
+ # identifier.include?("update") # => false, not in key at all
100
+ #
101
+ # @param segments [String] the one of more key segments to check
67
102
  # @return [Boolean]
68
103
  # @api public
69
- def start_with?(leading_namespaces)
70
- leading_namespaces.nil? ||
71
- key.start_with?("#{leading_namespaces}#{separator}") ||
72
- key.eql?(leading_namespaces)
104
+ def include?(segments)
105
+ return false if segments.to_s.empty?
106
+
107
+ sep_re = Regexp.escape(KEY_SEPARATOR)
108
+ key.match?(
109
+ /
110
+ (\A|#{sep_re})
111
+ #{Regexp.escape(segments)}
112
+ (\Z|#{sep_re})
113
+ /x
114
+ )
73
115
  end
74
116
 
75
117
  # Returns the key with its segments separated by the given separator
@@ -108,27 +150,27 @@ module Dry
108
150
  def namespaced(from:, to:)
109
151
  return self if from == to
110
152
 
111
- separated_to = "#{to}#{separator}" if to
153
+ separated_to = "#{to}#{KEY_SEPARATOR}" if to
112
154
 
113
155
  new_key =
114
156
  if from.nil?
115
157
  "#{separated_to}#{key}"
116
158
  else
117
159
  key.sub(
118
- /^#{Regexp.escape(from.to_s)}#{Regexp.escape(separator)}/,
160
+ /^#{Regexp.escape(from.to_s)}#{Regexp.escape(KEY_SEPARATOR)}/,
119
161
  separated_to || EMPTY_STRING
120
162
  )
121
163
  end
122
164
 
123
165
  return self if new_key == key
124
166
 
125
- self.class.new(new_key, separator: separator)
167
+ self.class.new(new_key)
126
168
  end
127
169
 
128
170
  private
129
171
 
130
172
  def segments
131
- @segments ||= key.split(separator)
173
+ @segments ||= key.split(KEY_SEPARATOR)
132
174
  end
133
175
  end
134
176
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "dry/container"
4
+ require_relative "constants"
5
+
3
6
  module Dry
4
7
  module System
5
8
  # Default importer implementation
@@ -11,25 +14,34 @@ module Dry
11
14
  #
12
15
  # @api private
13
16
  class Importer
14
- attr_reader :container
17
+ # @api private
18
+ class Item
19
+ attr_reader :namespace, :container, :import_keys
20
+
21
+ def initialize(namespace:, container:, import_keys:)
22
+ @namespace = namespace
23
+ @container = container
24
+ @import_keys = import_keys
25
+ end
26
+ end
15
27
 
16
- attr_reader :separator
28
+ attr_reader :container
17
29
 
18
30
  attr_reader :registry
19
31
 
20
32
  # @api private
21
33
  def initialize(container)
22
34
  @container = container
23
- @separator = container.config.namespace_separator
24
35
  @registry = {}
25
36
  end
26
37
 
27
38
  # @api private
28
- def finalize!
29
- registry.each do |name, container|
30
- call(name, container.finalize!)
31
- end
32
- self
39
+ def register(namespace:, container:, keys: nil)
40
+ registry[namespace] = Item.new(
41
+ namespace: namespace,
42
+ container: container,
43
+ import_keys: keys
44
+ )
33
45
  end
34
46
 
35
47
  # @api private
@@ -41,15 +53,74 @@ module Dry
41
53
  def key?(name)
42
54
  registry.key?(name)
43
55
  end
56
+ alias_method :namespace?, :key?
44
57
 
45
58
  # @api private
46
- def call(ns, other)
47
- container.merge(other, namespace: ns)
59
+ def finalize!
60
+ registry.each_key { import(_1) }
61
+ self
48
62
  end
49
63
 
50
64
  # @api private
51
- def register(other)
52
- registry.update(other)
65
+ def import(namespace, keys: Undefined)
66
+ item = self[namespace]
67
+ keys = Undefined.default(keys, item.import_keys)
68
+
69
+ if keys
70
+ import_keys(item.container, namespace, keys_to_import(keys, item))
71
+ else
72
+ import_all(item.container, namespace)
73
+ end
74
+
75
+ self
76
+ end
77
+
78
+ private
79
+
80
+ def keys_to_import(keys, item)
81
+ keys
82
+ .then { (arr = item.import_keys) ? _1 & arr : _1 }
83
+ .then { (arr = item.container.exports) ? _1 & arr : _1 }
84
+ end
85
+
86
+ def import_keys(other, namespace, keys)
87
+ container.merge(build_merge_container(other, keys), namespace: namespace)
88
+ end
89
+
90
+ def import_all(other, namespace)
91
+ merge_container =
92
+ if other.exports
93
+ build_merge_container(other, other.exports)
94
+ else
95
+ build_merge_container(other.finalize!, other.keys)
96
+ end
97
+
98
+ container.merge(merge_container, namespace: namespace)
99
+ end
100
+
101
+ def build_merge_container(other, keys)
102
+ keys.each_with_object(Dry::Container.new) { |key, ic|
103
+ next unless other.key?(key)
104
+
105
+ # Access the other container's items directly so that we can preserve all their
106
+ # options when we merge them with the target container (e.g. if a component in
107
+ # the provider container was registered with a block, we want block registration
108
+ # behavior to be exhibited when later resolving that component from the target
109
+ # container). TODO: Make this part of dry-system's public API.
110
+ item = other._container[key]
111
+
112
+ # By default, we "protect" components that were themselves imported into the
113
+ # other container from being implicitly exported; imported components are
114
+ # considered "private" and must be explicitly included in `exports` to be
115
+ # exported.
116
+ next if item.options[:imported] && !other.exports
117
+
118
+ if item.callable?
119
+ ic.register(key, **item.options, imported: true, &item.item)
120
+ else
121
+ ic.register(key, item.item, **item.options, imported: true)
122
+ end
123
+ }
53
124
  end
54
125
  end
55
126
  end
@@ -6,7 +6,7 @@ module Dry
6
6
  module System
7
7
  # An indirect component is a component that cannot be directly from a source file
8
8
  # directly managed by the container. It may be component that needs to be loaded
9
- # indirectly, either via a manual registration file or an imported container
9
+ # indirectly, either via a registration manifest file or an imported container
10
10
  #
11
11
  # Indirect components are an internal abstraction and, unlike ordinary components, are
12
12
  # not exposed to users via component dir configuration hooks.
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "dry/system/errors"
4
+
3
5
  module Dry
4
6
  module System
5
7
  # Default component loader implementation
@@ -61,7 +63,10 @@ module Dry
61
63
  # @api public
62
64
  def constant(component)
63
65
  inflector = component.inflector
64
- inflector.constantize(inflector.camelize(component.const_path))
66
+ const_name = inflector.camelize(component.const_path)
67
+ inflector.constantize(const_name)
68
+ rescue NameError => e
69
+ raise ComponentNotLoadableError.new(component, e)
65
70
  end
66
71
 
67
72
  private
@@ -4,19 +4,21 @@ require "dry/system/constants"
4
4
 
5
5
  module Dry
6
6
  module System
7
- # Default manual registration implementation
7
+ # Default manifest registration implementation
8
8
  #
9
- # This is currently configured by default for every System::Container.
10
- # Manual registrar objects are responsible for loading files from configured
11
- # manual registration paths, which should hold code to explicitly register
9
+ # This is configured by default for every System::Container. The manifest registrar is
10
+ # responsible for loading manifest files that contain code to manually register
12
11
  # certain objects with the container.
13
12
  #
14
13
  # @api private
15
- class ManualRegistrar
14
+ class ManifestRegistrar
15
+ # @api private
16
16
  attr_reader :container
17
17
 
18
+ # @api private
18
19
  attr_reader :config
19
20
 
21
+ # @api private
20
22
  def initialize(container)
21
23
  @container = container
22
24
  @config = container.config
@@ -34,6 +36,7 @@ module Dry
34
36
  require(root.join(config.registrations_dir, component.root_key.to_s))
35
37
  end
36
38
 
39
+ # @api private
37
40
  def file_exists?(component)
38
41
  File.exist?(File.join(registrations_dir, "#{component.root_key}#{RB_EXT}"))
39
42
  end
@@ -15,8 +15,9 @@ module Dry
15
15
  # @api private
16
16
  def self.extended(system)
17
17
  super
18
+
18
19
  system.use(:env)
19
- system.before(:configure) { setting :bootsnap, default: DEFAULT_OPTIONS }
20
+ system.setting :bootsnap, default: DEFAULT_OPTIONS
20
21
  system.after(:configure, &:setup_bootsnap)
21
22
  end
22
23
 
@@ -36,7 +37,7 @@ module Dry
36
37
 
37
38
  # @api private
38
39
  def bootsnap_available?
39
- RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.3.0" && RUBY_VERSION < "2.5.0"
40
+ RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.3.0" && RUBY_VERSION < "3.1.0"
40
41
  end
41
42
  end
42
43
  end
@@ -15,13 +15,49 @@ module Dry
15
15
  # @api private
16
16
  def define_initialize(klass)
17
17
  @container["notifications"].instrument(
18
- :resolved_dependency, dependency_map: dependency_map.to_h, target_class: klass
18
+ :resolved_dependency,
19
+ dependency_map: dependency_map.to_h,
20
+ target_class: klass
19
21
  )
22
+
23
+ super(klass)
24
+ end
25
+ end
26
+
27
+ # @api private
28
+ class Args < Dry::AutoInject::Strategies::Args
29
+ private
30
+
31
+ # @api private
32
+ def define_initialize(klass)
33
+ @container["notifications"].instrument(
34
+ :resolved_dependency,
35
+ dependency_map: dependency_map.to_h,
36
+ target_class: klass
37
+ )
38
+
39
+ super(klass)
40
+ end
41
+ end
42
+
43
+ class Hash < Dry::AutoInject::Strategies::Hash
44
+ private
45
+
46
+ # @api private
47
+ def define_initialize(klass)
48
+ @container["notifications"].instrument(
49
+ :resolved_dependency,
50
+ dependency_map: dependency_map.to_h,
51
+ target_class: klass
52
+ )
53
+
20
54
  super(klass)
21
55
  end
22
56
  end
23
57
 
24
58
  register :kwargs, Kwargs
59
+ register :args, Args
60
+ register :hash, Hash
25
61
  register :default, Kwargs
26
62
  end
27
63
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "dry/system/constants"
4
- require "dry/system/plugins/dependency_graph/strategies"
3
+ require_relative "dependency_graph/strategies"
5
4
 
6
5
  module Dry
7
6
  module System
@@ -12,36 +11,43 @@ module Dry
12
11
  def self.extended(system)
13
12
  super
14
13
 
15
- system.use(:notifications)
14
+ system.instance_eval do
15
+ use(:notifications)
16
16
 
17
- system.before(:configure) do
18
- setting :ignored_dependencies, default: []
19
- end
20
-
21
- system.after(:configure) do
22
- self[:notifications].register_event(:resolved_dependency)
23
- self[:notifications].register_event(:registered_dependency)
17
+ setting :dependency_graph do
18
+ setting :ignored_dependencies, default: []
19
+ end
24
20
 
25
- strategies(Strategies)
21
+ after(:configure) do
22
+ self[:notifications].register_event(:resolved_dependency)
23
+ self[:notifications].register_event(:registered_dependency)
24
+ end
26
25
  end
27
26
  end
28
27
 
29
28
  # @api private
30
29
  def self.dependencies
31
- {'dry-events': "dry/events/publisher"}
30
+ {"dry-events" => "dry/events/publisher"}
31
+ end
32
+
33
+ # @api private
34
+ def injector(**options)
35
+ super(**options, strategies: DependencyGraph::Strategies)
32
36
  end
33
37
 
34
38
  # @api private
35
39
  def register(key, contents = nil, options = {}, &block)
36
- super
37
- dependency_key = key.to_s
38
- unless config.ignored_dependencies.include?(dependency_key)
39
- self[:notifications].instrument(
40
- :registered_dependency, key: dependency_key, class: self[dependency_key].class
41
- )
40
+ super.tap do
41
+ key = key.to_s
42
+
43
+ unless config.dependency_graph.ignored_dependencies.include?(key)
44
+ self[:notifications].instrument(
45
+ :registered_dependency,
46
+ key: key,
47
+ class: self[key].class
48
+ )
49
+ end
42
50
  end
43
-
44
- self
45
51
  end
46
52
  end
47
53
  end
@@ -10,8 +10,9 @@ module Dry
10
10
  attr_reader :options
11
11
 
12
12
  # @api private
13
- def initialize(options)
13
+ def initialize(**options)
14
14
  @options = options
15
+ super()
15
16
  end
16
17
 
17
18
  def inferrer
@@ -8,7 +8,7 @@ module Dry
8
8
  module Logging
9
9
  # @api private
10
10
  def self.extended(system)
11
- system.before(:configure) do
11
+ system.instance_eval do
12
12
  setting :logger, reader: true
13
13
 
14
14
  setting :log_dir, default: "log"
@@ -40,7 +40,7 @@ module Dry
40
40
  elsif config.logger
41
41
  register(:logger, config.logger)
42
42
  else
43
- config.logger = logger = config.logger_class.new(log_file_path)
43
+ config.logger = config.logger_class.new(log_file_path)
44
44
  config.logger.level = log_level
45
45
 
46
46
  register(:logger, config.logger)