dry-system 0.12.0 → 0.13.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 +101 -86
- data/README.md +2 -2
- data/lib/dry-system.rb +2 -0
- data/lib/dry/system.rb +3 -1
- data/lib/dry/system/auto_registrar.rb +12 -8
- data/lib/dry/system/auto_registrar/configuration.rb +2 -0
- data/lib/dry/system/booter.rb +10 -9
- data/lib/dry/system/booter/component_registry.rb +3 -5
- data/lib/dry/system/component.rb +5 -2
- data/lib/dry/system/components.rb +2 -0
- data/lib/dry/system/components/bootable.rb +13 -11
- data/lib/dry/system/components/config.rb +2 -0
- data/lib/dry/system/constants.rb +8 -7
- data/lib/dry/system/container.rb +64 -25
- data/lib/dry/system/errors.rb +9 -1
- data/lib/dry/system/importer.rb +2 -0
- data/lib/dry/system/lifecycle.rb +3 -1
- data/lib/dry/system/loader.rb +2 -0
- data/lib/dry/system/magic_comments_parser.rb +3 -3
- data/lib/dry/system/manual_registrar.rb +3 -1
- data/lib/dry/system/plugins.rb +9 -4
- data/lib/dry/system/plugins/bootsnap.rb +4 -1
- data/lib/dry/system/plugins/dependency_graph.rb +47 -0
- data/lib/dry/system/plugins/dependency_graph/strategies.rb +30 -0
- data/lib/dry/system/plugins/env.rb +2 -0
- data/lib/dry/system/plugins/logging.rb +8 -7
- data/lib/dry/system/plugins/monitoring.rb +3 -1
- data/lib/dry/system/plugins/monitoring/proxy.rb +2 -0
- data/lib/dry/system/plugins/notifications.rb +4 -1
- data/lib/dry/system/provider.rb +3 -1
- data/lib/dry/system/provider_registry.rb +2 -0
- data/lib/dry/system/settings.rb +9 -7
- data/lib/dry/system/settings/file_loader.rb +4 -2
- data/lib/dry/system/settings/file_parser.rb +5 -3
- data/lib/dry/system/stubs.rb +2 -0
- data/lib/dry/system/system_components/settings.rb +2 -0
- data/lib/dry/system/version.rb +3 -1
- metadata +25 -17
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dry
|
2
4
|
module System
|
3
5
|
class Booter
|
@@ -25,11 +27,7 @@ module Dry
|
|
25
27
|
def [](name)
|
26
28
|
component = components.detect { |component| component.identifier == name }
|
27
29
|
|
28
|
-
|
29
|
-
component
|
30
|
-
else
|
31
|
-
raise InvalidComponentIdentifierError, name
|
32
|
-
end
|
30
|
+
component || raise(InvalidComponentIdentifierError, name)
|
33
31
|
end
|
34
32
|
end
|
35
33
|
end
|
data/lib/dry/system/component.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'concurrent/map'
|
2
4
|
|
3
5
|
require 'dry-equalizer'
|
@@ -83,9 +85,10 @@ module Dry
|
|
83
85
|
|
84
86
|
# @api private
|
85
87
|
def initialize(identifier, path, options)
|
86
|
-
@identifier
|
88
|
+
@identifier = identifier
|
89
|
+
@path = path
|
87
90
|
@options = options
|
88
|
-
@file = "#{path}#{RB_EXT}"
|
91
|
+
@file = "#{path}#{RB_EXT}"
|
89
92
|
@loader = options.fetch(:loader)
|
90
93
|
freeze
|
91
94
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'dry/system/lifecycle'
|
2
4
|
require 'dry/system/settings'
|
3
5
|
require 'dry/system/components/config'
|
@@ -65,10 +67,12 @@ module Dry
|
|
65
67
|
# @return [Symbol,String] default namespace for the container keys
|
66
68
|
attr_reader :namespace
|
67
69
|
|
70
|
+
TRIGGER_MAP = Hash.new { |h, k| h[k] = [] }.freeze
|
71
|
+
|
68
72
|
# @api private
|
69
73
|
def initialize(identifier, options = {}, &block)
|
70
74
|
@identifier = identifier
|
71
|
-
@triggers = { before:
|
75
|
+
@triggers = { before: TRIGGER_MAP.dup, after: TRIGGER_MAP.dup }
|
72
76
|
@options = block ? options.merge(block: block) : options
|
73
77
|
@namespace = options[:namespace]
|
74
78
|
finalize = options[:finalize] || DEFAULT_FINALIZE
|
@@ -159,11 +163,7 @@ module Dry
|
|
159
163
|
#
|
160
164
|
# @api public
|
161
165
|
def config
|
162
|
-
|
163
|
-
@config
|
164
|
-
else
|
165
|
-
configure!
|
166
|
-
end
|
166
|
+
@config || configure!
|
167
167
|
end
|
168
168
|
|
169
169
|
# Return a list of lifecycle steps that were executed
|
@@ -191,7 +191,7 @@ module Dry
|
|
191
191
|
# @api private
|
192
192
|
def finalize
|
193
193
|
lifecycle.container.each do |key, item|
|
194
|
-
container.register(key, item) unless container.
|
194
|
+
container.register(key, item) unless container.registered?(key)
|
195
195
|
end
|
196
196
|
self
|
197
197
|
end
|
@@ -241,8 +241,8 @@ module Dry
|
|
241
241
|
#
|
242
242
|
# @api private
|
243
243
|
def boot_file
|
244
|
-
container_boot_files
|
245
|
-
detect { |path| Pathname(path).basename(RB_EXT).to_s == identifier.to_s }
|
244
|
+
container_boot_files
|
245
|
+
.detect { |path| Pathname(path).basename(RB_EXT).to_s == identifier.to_s }
|
246
246
|
end
|
247
247
|
|
248
248
|
# Return path to boot dir
|
@@ -260,7 +260,7 @@ module Dry
|
|
260
260
|
#
|
261
261
|
# @api private
|
262
262
|
def container_boot_files
|
263
|
-
Dir[container.boot_path.join("**/#{RB_GLOB}")]
|
263
|
+
::Dir[container.boot_path.join("**/#{RB_GLOB}")].sort
|
264
264
|
end
|
265
265
|
|
266
266
|
private
|
@@ -290,7 +290,9 @@ module Dry
|
|
290
290
|
when nil
|
291
291
|
container
|
292
292
|
else
|
293
|
-
raise
|
293
|
+
raise <<-STR
|
294
|
+
+namespace+ boot option must be true, string or symbol #{namespace.inspect} given.
|
295
|
+
STR
|
294
296
|
end
|
295
297
|
end
|
296
298
|
|
data/lib/dry/system/constants.rb
CHANGED
@@ -1,24 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'dry/core/constants'
|
2
4
|
|
3
5
|
module Dry
|
4
6
|
module System
|
5
7
|
include Dry::Core::Constants
|
6
8
|
|
7
|
-
RB_EXT = '.rb'
|
8
|
-
RB_GLOB = '*.rb'
|
9
|
-
PATH_SEPARATOR = '/'
|
10
|
-
DEFAULT_SEPARATOR = '.'
|
9
|
+
RB_EXT = '.rb'
|
10
|
+
RB_GLOB = '*.rb'
|
11
|
+
PATH_SEPARATOR = '/'
|
12
|
+
DEFAULT_SEPARATOR = '.'
|
11
13
|
WORD_REGEX = /\w+/.freeze
|
12
14
|
|
13
15
|
DuplicatedComponentKeyError = Class.new(ArgumentError)
|
14
16
|
InvalidSettingsError = Class.new(ArgumentError) do
|
15
17
|
# @api private
|
16
18
|
def initialize(attributes)
|
17
|
-
message = <<~
|
19
|
+
message = <<~STR
|
18
20
|
Could not initialize settings. The following settings were invalid:
|
19
21
|
|
20
22
|
#{attributes_errors(attributes).join("\n")}
|
21
|
-
|
23
|
+
STR
|
22
24
|
super(message)
|
23
25
|
end
|
24
26
|
|
@@ -38,6 +40,5 @@ module Dry
|
|
38
40
|
super("dry-system plugin #{plugin.inspect} failed to load its dependencies: #{message}")
|
39
41
|
end
|
40
42
|
end
|
41
|
-
|
42
43
|
end
|
43
44
|
end
|
data/lib/dry/system/container.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'pathname'
|
2
4
|
|
3
5
|
require 'dry-auto_inject'
|
@@ -73,8 +75,8 @@ module Dry
|
|
73
75
|
setting :name
|
74
76
|
setting :default_namespace
|
75
77
|
setting(:root, Pathname.pwd.freeze) { |path| Pathname(path) }
|
76
|
-
setting :system_dir, 'system'
|
77
|
-
setting :registrations_dir, 'container'
|
78
|
+
setting :system_dir, 'system'
|
79
|
+
setting :registrations_dir, 'container'
|
78
80
|
setting :auto_register, []
|
79
81
|
setting :inflector, Dry::Inflector.new
|
80
82
|
setting :loader, Dry::System::Loader
|
@@ -82,9 +84,17 @@ module Dry
|
|
82
84
|
setting :auto_registrar, Dry::System::AutoRegistrar
|
83
85
|
setting :manual_registrar, Dry::System::ManualRegistrar
|
84
86
|
setting :importer, Dry::System::Importer
|
85
|
-
setting(:components, {}, reader: true
|
87
|
+
setting(:components, {}, reader: true, &:dup)
|
86
88
|
|
87
89
|
class << self
|
90
|
+
def strategies(value = nil)
|
91
|
+
if value
|
92
|
+
@strategies = value
|
93
|
+
else
|
94
|
+
@strategies ||= Dry::AutoInject::Strategies
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
88
98
|
extend Dry::Core::Deprecations['Dry::System::Container']
|
89
99
|
|
90
100
|
# Configures the container
|
@@ -139,7 +149,9 @@ module Dry
|
|
139
149
|
when Hash then importer.register(other)
|
140
150
|
when Dry::Container::Namespace then super
|
141
151
|
else
|
142
|
-
raise ArgumentError,
|
152
|
+
raise ArgumentError, <<-STR
|
153
|
+
+other+ must be a hash of names and systems, or a Dry::Container namespace
|
154
|
+
STR
|
143
155
|
end
|
144
156
|
end
|
145
157
|
|
@@ -218,7 +230,9 @@ module Dry
|
|
218
230
|
# @api public
|
219
231
|
def boot(name, opts = {}, &block)
|
220
232
|
if components.key?(name)
|
221
|
-
raise DuplicatedComponentKeyError,
|
233
|
+
raise DuplicatedComponentKeyError, <<-STR
|
234
|
+
Bootable component #{name.inspect} was already registered
|
235
|
+
STR
|
222
236
|
end
|
223
237
|
|
224
238
|
component =
|
@@ -227,7 +241,6 @@ module Dry
|
|
227
241
|
else
|
228
242
|
boot_local(name, opts, &block)
|
229
243
|
end
|
230
|
-
self
|
231
244
|
|
232
245
|
components[name] = component
|
233
246
|
end
|
@@ -246,7 +259,9 @@ module Dry
|
|
246
259
|
|
247
260
|
# @api private
|
248
261
|
def boot_local(identifier, namespace: nil, &block)
|
249
|
-
component = Components::Bootable.new(
|
262
|
+
component = Components::Bootable.new(
|
263
|
+
identifier, container: self, namespace: namespace, &block
|
264
|
+
)
|
250
265
|
|
251
266
|
booter.register_component(component)
|
252
267
|
|
@@ -381,6 +396,7 @@ module Dry
|
|
381
396
|
def load_paths!(*dirs)
|
382
397
|
dirs.map(&root.method(:join)).each do |path|
|
383
398
|
next if load_paths.include?(path)
|
399
|
+
|
384
400
|
load_paths << path
|
385
401
|
$LOAD_PATH.unshift(path.to_s)
|
386
402
|
end
|
@@ -459,7 +475,7 @@ module Dry
|
|
459
475
|
# @param options [Hash] injector options
|
460
476
|
#
|
461
477
|
# @api public
|
462
|
-
def injector(options = {})
|
478
|
+
def injector(options = { strategies: strategies })
|
463
479
|
Dry::AutoInject(self, options)
|
464
480
|
end
|
465
481
|
|
@@ -477,7 +493,7 @@ module Dry
|
|
477
493
|
# @api public
|
478
494
|
def require_from_root(*paths)
|
479
495
|
paths.flat_map { |path|
|
480
|
-
path.to_s.include?('*') ? Dir[root.join(path)] : root.join(path)
|
496
|
+
path.to_s.include?('*') ? ::Dir[root.join(path)].sort : root.join(path)
|
481
497
|
}.each { |path|
|
482
498
|
require path.to_s
|
483
499
|
}
|
@@ -502,12 +518,37 @@ module Dry
|
|
502
518
|
end
|
503
519
|
|
504
520
|
# @api public
|
505
|
-
def resolve(key)
|
506
|
-
load_component(key) unless finalized?
|
521
|
+
def resolve(key, &block)
|
522
|
+
load_component(key, &block) unless finalized?
|
507
523
|
|
508
524
|
super
|
509
525
|
end
|
510
526
|
|
527
|
+
alias_method :registered?, :key?
|
528
|
+
#
|
529
|
+
# @!method registered?(key)
|
530
|
+
# Whether a +key+ is registered (doesn't trigger loading)
|
531
|
+
# @param [String,Symbol] key Identifier
|
532
|
+
# @return [Boolean]
|
533
|
+
# @api public
|
534
|
+
#
|
535
|
+
|
536
|
+
# Check if identifier is registered.
|
537
|
+
# If not, try to load the component
|
538
|
+
#
|
539
|
+
# @param [String,Symbol] key Identifier
|
540
|
+
# @return [Boolean]
|
541
|
+
#
|
542
|
+
# @api public
|
543
|
+
def key?(key)
|
544
|
+
if finalized?
|
545
|
+
registered?(key)
|
546
|
+
else
|
547
|
+
registered?(key) || resolve(key) { return false }
|
548
|
+
true
|
549
|
+
end
|
550
|
+
end
|
551
|
+
|
511
552
|
# @api private
|
512
553
|
def load_paths
|
513
554
|
@load_paths ||= []
|
@@ -549,18 +590,16 @@ module Dry
|
|
549
590
|
namespace: config.default_namespace,
|
550
591
|
separator: config.namespace_separator,
|
551
592
|
inflector: config.inflector,
|
552
|
-
**options
|
593
|
+
**options
|
553
594
|
)
|
554
595
|
end
|
555
596
|
end
|
556
597
|
|
557
598
|
# @api private
|
558
599
|
def require_component(component)
|
559
|
-
return if
|
600
|
+
return if registered?(component.identifier)
|
560
601
|
|
561
|
-
unless component.file_exists?(load_paths)
|
562
|
-
raise FileNotFoundError, component
|
563
|
-
end
|
602
|
+
raise FileNotFoundError, component unless component.file_exists?(load_paths)
|
564
603
|
|
565
604
|
require_path(component.path)
|
566
605
|
|
@@ -579,8 +618,8 @@ module Dry
|
|
579
618
|
end
|
580
619
|
|
581
620
|
# @api private
|
582
|
-
def load_component(key)
|
583
|
-
return self if
|
621
|
+
def load_component(key, &block)
|
622
|
+
return self if registered?(key)
|
584
623
|
|
585
624
|
component(key).tap do |component|
|
586
625
|
if component.boot?
|
@@ -594,9 +633,7 @@ module Dry
|
|
594
633
|
load_imported_component(component.namespaced(root_key))
|
595
634
|
end
|
596
635
|
|
597
|
-
|
598
|
-
load_local_component(component)
|
599
|
-
end
|
636
|
+
load_local_component(component, &block) unless registered?(key)
|
600
637
|
end
|
601
638
|
end
|
602
639
|
|
@@ -610,7 +647,7 @@ module Dry
|
|
610
647
|
|
611
648
|
# @api private
|
612
649
|
def hooks
|
613
|
-
@
|
650
|
+
@hooks ||= Hash.new { |h, k| h[k] = [] }
|
614
651
|
end
|
615
652
|
|
616
653
|
# @api private
|
@@ -622,14 +659,14 @@ module Dry
|
|
622
659
|
new_hooks[event].concat(klass.hooks[event])
|
623
660
|
end
|
624
661
|
|
625
|
-
klass.instance_variable_set(:@
|
662
|
+
klass.instance_variable_set(:@hooks, new_hooks)
|
626
663
|
super
|
627
664
|
end
|
628
665
|
|
629
666
|
private
|
630
667
|
|
631
668
|
# @api private
|
632
|
-
def load_local_component(component, default_namespace_fallback = false)
|
669
|
+
def load_local_component(component, default_namespace_fallback = false, &block)
|
633
670
|
if booter.bootable?(component) || component.file_exists?(load_paths)
|
634
671
|
booter.boot_dependency(component) unless finalized?
|
635
672
|
|
@@ -637,9 +674,11 @@ module Dry
|
|
637
674
|
register(component.identifier) { component.instance }
|
638
675
|
end
|
639
676
|
elsif !default_namespace_fallback
|
640
|
-
load_local_component(component.prepend(config.default_namespace), true)
|
677
|
+
load_local_component(component.prepend(config.default_namespace), true, &block)
|
641
678
|
elsif manual_registrar.file_exists?(component)
|
642
679
|
manual_registrar.(component)
|
680
|
+
elsif block_given?
|
681
|
+
yield
|
643
682
|
else
|
644
683
|
raise ComponentLoadError, component
|
645
684
|
end
|
data/lib/dry/system/errors.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dry
|
2
4
|
module System
|
3
5
|
# Error raised when the container tries to load a component with missing
|
@@ -15,7 +17,13 @@ module Dry
|
|
15
17
|
# @api public
|
16
18
|
ComponentFileMismatchError = Class.new(StandardError) do
|
17
19
|
def initialize(component)
|
18
|
-
|
20
|
+
path = component.boot_path
|
21
|
+
files = component.container_boot_files
|
22
|
+
|
23
|
+
super(<<-STR)
|
24
|
+
Boot file for component #{component.identifier.inspect} not found.
|
25
|
+
Container boot files under #{path}: #{files.inspect}")
|
26
|
+
STR
|
19
27
|
end
|
20
28
|
end
|
21
29
|
|
data/lib/dry/system/importer.rb
CHANGED
data/lib/dry/system/lifecycle.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'concurrent/map'
|
2
4
|
|
3
5
|
require 'dry/system/settings'
|
@@ -124,7 +126,7 @@ module Dry
|
|
124
126
|
|
125
127
|
# @api private
|
126
128
|
def method_missing(meth, *args, &block)
|
127
|
-
if target.
|
129
|
+
if target.registered?(meth)
|
128
130
|
target[meth]
|
129
131
|
elsif container.key?(meth)
|
130
132
|
container[meth]
|
data/lib/dry/system/loader.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dry
|
2
4
|
module System
|
3
5
|
class MagicCommentsParser
|
@@ -6,7 +8,7 @@ module Dry
|
|
6
8
|
|
7
9
|
COERCIONS = {
|
8
10
|
'true' => true,
|
9
|
-
'false' => false
|
11
|
+
'false' => false
|
10
12
|
}.freeze
|
11
13
|
|
12
14
|
def self.call(file_name)
|
@@ -21,8 +23,6 @@ module Dry
|
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
|
-
private
|
25
|
-
|
26
26
|
def self.coerce(value)
|
27
27
|
COERCIONS.fetch(value) { value }
|
28
28
|
end
|