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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +400 -0
- data/LICENSE +1 -1
- data/README.md +2 -2
- data/dry-system.gemspec +2 -2
- data/lib/dry/system/component.rb +2 -3
- data/lib/dry/system/component_dir.rb +8 -34
- data/lib/dry/system/components.rb +8 -4
- data/lib/dry/system/config/component_dir.rb +60 -16
- data/lib/dry/system/config/component_dirs.rb +23 -10
- data/lib/dry/system/config/namespace.rb +4 -6
- data/lib/dry/system/constants.rb +1 -1
- data/lib/dry/system/container.rb +264 -182
- data/lib/dry/system/errors.rb +73 -53
- data/lib/dry/system/identifier.rb +62 -20
- data/lib/dry/system/importer.rb +83 -12
- data/lib/dry/system/indirect_component.rb +1 -1
- data/lib/dry/system/loader.rb +6 -1
- data/lib/dry/system/{manual_registrar.rb → manifest_registrar.rb} +8 -5
- data/lib/dry/system/plugins/bootsnap.rb +2 -1
- data/lib/dry/system/plugins/dependency_graph/strategies.rb +37 -1
- data/lib/dry/system/plugins/dependency_graph.rb +26 -20
- data/lib/dry/system/plugins/env.rb +2 -1
- data/lib/dry/system/plugins/logging.rb +2 -2
- data/lib/dry/system/plugins/monitoring.rb +1 -1
- data/lib/dry/system/plugins/notifications.rb +1 -1
- data/lib/dry/system/plugins/zeitwerk/compat_inflector.rb +22 -0
- data/lib/dry/system/plugins/zeitwerk.rb +109 -0
- data/lib/dry/system/plugins.rb +7 -4
- data/lib/dry/system/provider/source.rb +324 -0
- data/lib/dry/system/provider/source_dsl.rb +94 -0
- data/lib/dry/system/provider.rb +262 -22
- data/lib/dry/system/provider_registrar.rb +276 -0
- data/lib/dry/system/provider_source_registry.rb +70 -0
- data/lib/dry/system/provider_sources/settings/config.rb +86 -0
- data/lib/dry/system/provider_sources/settings/loader.rb +53 -0
- data/lib/dry/system/provider_sources/settings.rb +40 -0
- data/lib/dry/system/provider_sources.rb +5 -0
- data/lib/dry/system/version.rb +1 -1
- data/lib/dry/system.rb +44 -12
- metadata +18 -18
- data/lib/dry/system/booter/component_registry.rb +0 -35
- data/lib/dry/system/booter.rb +0 -200
- data/lib/dry/system/components/bootable.rb +0 -280
- data/lib/dry/system/components/config.rb +0 -35
- data/lib/dry/system/lifecycle.rb +0 -135
- data/lib/dry/system/provider_registry.rb +0 -27
- data/lib/dry/system/settings/file_loader.rb +0 -30
- data/lib/dry/system/settings/file_parser.rb +0 -51
- data/lib/dry/system/settings.rb +0 -64
- data/lib/dry/system/system_components/settings.rb +0 -11
data/lib/dry/system/errors.rb
CHANGED
@@ -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
|
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
|
-
|
39
|
-
def initialize(
|
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
|
51
|
+
# Error raised when a named provider could not be found
|
47
52
|
#
|
48
53
|
# @api public
|
49
|
-
|
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
|
62
|
+
# Error raised when a named provider source could not be found
|
58
63
|
#
|
59
64
|
# @api public
|
60
|
-
|
61
|
-
def initialize(
|
62
|
-
|
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
|
-
#
|
85
|
+
# Exception raise when a plugin dependency failed to load
|
76
86
|
#
|
77
87
|
# @api public
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
-
|
85
|
-
|
86
|
-
|
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(
|
89
|
-
|
90
|
-
|
101
|
+
def initialize(component, error,
|
102
|
+
corrections: DidYouMean::ClassNameChecker.new(error).corrections)
|
103
|
+
full_class_name = [error.receiver, error.name].join("::")
|
91
104
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
105
|
+
message = [
|
106
|
+
"Component '#{component.key}' is not loadable.",
|
107
|
+
"Looking for #{full_class_name}."
|
108
|
+
]
|
96
109
|
|
97
|
-
|
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
|
-
|
100
|
-
attributes.map { |key, error| "#{key.name}: #{error}" }
|
101
|
-
end
|
102
|
-
end
|
120
|
+
You likely need to add:
|
103
121
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
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
|
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
|
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
|
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
|
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
|
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
|
70
|
-
|
71
|
-
|
72
|
-
|
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}#{
|
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(
|
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
|
167
|
+
self.class.new(new_key)
|
126
168
|
end
|
127
169
|
|
128
170
|
private
|
129
171
|
|
130
172
|
def segments
|
131
|
-
@segments ||= key.split(
|
173
|
+
@segments ||= key.split(KEY_SEPARATOR)
|
132
174
|
end
|
133
175
|
end
|
134
176
|
end
|
data/lib/dry/system/importer.rb
CHANGED
@@ -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
|
-
|
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 :
|
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
|
29
|
-
registry
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
47
|
-
|
59
|
+
def finalize!
|
60
|
+
registry.each_key { import(_1) }
|
61
|
+
self
|
48
62
|
end
|
49
63
|
|
50
64
|
# @api private
|
51
|
-
def
|
52
|
-
|
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
|
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.
|
data/lib/dry/system/loader.rb
CHANGED
@@ -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.
|
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
|
7
|
+
# Default manifest registration implementation
|
8
8
|
#
|
9
|
-
# This is
|
10
|
-
#
|
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
|
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.
|
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,
|
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
|
-
|
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.
|
14
|
+
system.instance_eval do
|
15
|
+
use(:notifications)
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
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
|
-
{
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|
@@ -8,7 +8,7 @@ module Dry
|
|
8
8
|
module Logging
|
9
9
|
# @api private
|
10
10
|
def self.extended(system)
|
11
|
-
system.
|
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 =
|
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)
|