dry-system 0.22.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +400 -0
  3. data/LICENSE +1 -1
  4. data/README.md +2 -2
  5. data/dry-system.gemspec +2 -2
  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 +60 -16
  10. data/lib/dry/system/config/component_dirs.rb +23 -10
  11. data/lib/dry/system/config/namespace.rb +4 -6
  12. data/lib/dry/system/constants.rb +1 -1
  13. data/lib/dry/system/container.rb +264 -182
  14. data/lib/dry/system/errors.rb +73 -53
  15. data/lib/dry/system/identifier.rb +62 -20
  16. data/lib/dry/system/importer.rb +83 -12
  17. data/lib/dry/system/indirect_component.rb +1 -1
  18. data/lib/dry/system/loader.rb +6 -1
  19. data/lib/dry/system/{manual_registrar.rb → manifest_registrar.rb} +8 -5
  20. data/lib/dry/system/plugins/bootsnap.rb +2 -1
  21. data/lib/dry/system/plugins/dependency_graph/strategies.rb +37 -1
  22. data/lib/dry/system/plugins/dependency_graph.rb +26 -20
  23. data/lib/dry/system/plugins/env.rb +2 -1
  24. data/lib/dry/system/plugins/logging.rb +2 -2
  25. data/lib/dry/system/plugins/monitoring.rb +1 -1
  26. data/lib/dry/system/plugins/notifications.rb +1 -1
  27. data/lib/dry/system/plugins/zeitwerk/compat_inflector.rb +22 -0
  28. data/lib/dry/system/plugins/zeitwerk.rb +109 -0
  29. data/lib/dry/system/plugins.rb +7 -4
  30. data/lib/dry/system/provider/source.rb +324 -0
  31. data/lib/dry/system/provider/source_dsl.rb +94 -0
  32. data/lib/dry/system/provider.rb +262 -22
  33. data/lib/dry/system/provider_registrar.rb +276 -0
  34. data/lib/dry/system/provider_source_registry.rb +70 -0
  35. data/lib/dry/system/provider_sources/settings/config.rb +86 -0
  36. data/lib/dry/system/provider_sources/settings/loader.rb +53 -0
  37. data/lib/dry/system/provider_sources/settings.rb +40 -0
  38. data/lib/dry/system/provider_sources.rb +5 -0
  39. data/lib/dry/system/version.rb +1 -1
  40. data/lib/dry/system.rb +44 -12
  41. metadata +18 -18
  42. data/lib/dry/system/booter/component_registry.rb +0 -35
  43. data/lib/dry/system/booter.rb +0 -200
  44. data/lib/dry/system/components/bootable.rb +0 -280
  45. data/lib/dry/system/components/config.rb +0 -35
  46. data/lib/dry/system/lifecycle.rb +0 -135
  47. data/lib/dry/system/provider_registry.rb +0 -27
  48. data/lib/dry/system/settings/file_loader.rb +0 -30
  49. data/lib/dry/system/settings/file_parser.rb +0 -51
  50. data/lib/dry/system/settings.rb +0 -64
  51. 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
 
@@ -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)