dry-system 0.7.3 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/lib/dry/system.rb +24 -0
- data/lib/dry/system/booter.rb +75 -43
- data/lib/dry/system/booter/component_registry.rb +37 -0
- data/lib/dry/system/component.rb +9 -4
- data/lib/dry/system/components.rb +6 -0
- data/lib/dry/system/components/bootable.rb +307 -0
- data/lib/dry/system/components/config.rb +33 -0
- data/lib/dry/system/constants.rb +2 -0
- data/lib/dry/system/container.rb +69 -22
- data/lib/dry/system/errors.rb +2 -2
- data/lib/dry/system/lifecycle.rb +40 -7
- data/lib/dry/system/provider.rb +46 -0
- data/lib/dry/system/provider_registry.rb +25 -0
- data/lib/dry/system/settings.rb +59 -0
- data/lib/dry/system/settings/file_loader.rb +28 -0
- data/lib/dry/system/settings/file_parser.rb +49 -0
- data/lib/dry/system/system_components/settings.rb +9 -0
- data/lib/dry/system/version.rb +1 -1
- metadata +27 -144
- data/.gitignore +0 -39
- data/.rspec +0 -3
- data/.travis.yml +0 -22
- data/.yardopts +0 -5
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -9
- data/Rakefile +0 -12
- data/dry-system.gemspec +0 -31
- data/examples/custom_configuration_auto_register/Gemfile +0 -5
- data/examples/custom_configuration_auto_register/lib/entities/user.rb +0 -7
- data/examples/custom_configuration_auto_register/lib/user_repo.rb +0 -5
- data/examples/custom_configuration_auto_register/run.rb +0 -8
- data/examples/custom_configuration_auto_register/system/boot/persistence.rb +0 -13
- data/examples/custom_configuration_auto_register/system/container.rb +0 -16
- data/examples/custom_configuration_auto_register/system/import.rb +0 -3
- data/examples/standalone/Gemfile +0 -5
- data/examples/standalone/lib/user_repo.rb +0 -5
- data/examples/standalone/run.rb +0 -8
- data/examples/standalone/system/boot/persistence.rb +0 -13
- data/examples/standalone/system/container.rb +0 -9
- data/examples/standalone/system/import.rb +0 -3
- data/spec/fixtures/components/bar.rb +0 -5
- data/spec/fixtures/components/bar/baz.rb +0 -4
- data/spec/fixtures/components/foo.rb +0 -2
- data/spec/fixtures/components/no_register.rb +0 -4
- data/spec/fixtures/import_test/config/application.yml +0 -2
- data/spec/fixtures/import_test/lib/test/bar.rb +0 -4
- data/spec/fixtures/import_test/lib/test/foo.rb +0 -5
- data/spec/fixtures/import_test/system/boot/bar.rb +0 -11
- data/spec/fixtures/lazytest/config/application.yml +0 -2
- data/spec/fixtures/lazytest/lib/test/dep.rb +0 -4
- data/spec/fixtures/lazytest/lib/test/foo.rb +0 -5
- data/spec/fixtures/lazytest/lib/test/models.rb +0 -4
- data/spec/fixtures/lazytest/lib/test/models/book.rb +0 -6
- data/spec/fixtures/lazytest/lib/test/models/user.rb +0 -6
- data/spec/fixtures/lazytest/system/boot/bar.rb +0 -15
- data/spec/fixtures/magic_comments/comments.rb +0 -17
- data/spec/fixtures/manual_registration/container/foo.rb +0 -6
- data/spec/fixtures/manual_registration/lib/test/foo.rb +0 -9
- data/spec/fixtures/multiple_namespaced_components/multiple/level/baz.rb +0 -7
- data/spec/fixtures/multiple_namespaced_components/multiple/level/foz.rb +0 -6
- data/spec/fixtures/namespaced_components/namespaced/bar.rb +0 -5
- data/spec/fixtures/namespaced_components/namespaced/foo.rb +0 -4
- data/spec/fixtures/other/config/boot/bar.rb +0 -11
- data/spec/fixtures/other/config/boot/hell.rb +0 -3
- data/spec/fixtures/other/lib/test/dep.rb +0 -4
- data/spec/fixtures/other/lib/test/foo.rb +0 -5
- data/spec/fixtures/other/lib/test/models.rb +0 -4
- data/spec/fixtures/other/lib/test/models/book.rb +0 -6
- data/spec/fixtures/other/lib/test/models/user.rb +0 -6
- data/spec/fixtures/stubbing/lib/test/car.rb +0 -7
- data/spec/fixtures/stubbing/system/boot/db.rb +0 -8
- data/spec/fixtures/test/config/application.yml +0 -2
- data/spec/fixtures/test/config/subapp.yml +0 -2
- data/spec/fixtures/test/lib/test/dep.rb +0 -4
- data/spec/fixtures/test/lib/test/foo.rb +0 -5
- data/spec/fixtures/test/lib/test/models.rb +0 -4
- data/spec/fixtures/test/lib/test/models/book.rb +0 -6
- data/spec/fixtures/test/lib/test/models/user.rb +0 -6
- data/spec/fixtures/test/lib/test/singleton_dep.rb +0 -7
- data/spec/fixtures/test/log/.gitkeep +0 -0
- data/spec/fixtures/test/system/boot/bar.rb +0 -11
- data/spec/fixtures/test/system/boot/client.rb +0 -7
- data/spec/fixtures/test/system/boot/db.rb +0 -1
- data/spec/fixtures/test/system/boot/hell.rb +0 -3
- data/spec/fixtures/test/system/boot/logger.rb +0 -5
- data/spec/fixtures/umbrella/system/boot/db.rb +0 -10
- data/spec/integration/boot_spec.rb +0 -18
- data/spec/integration/container/lazy_loading/manual_registration_spec.rb +0 -18
- data/spec/integration/import_spec.rb +0 -81
- data/spec/spec_helper.rb +0 -48
- data/spec/unit/auto_registrar/configuration_spec.rb +0 -26
- data/spec/unit/component_spec.rb +0 -121
- data/spec/unit/container/auto_register_spec.rb +0 -113
- data/spec/unit/container/config_spec.rb +0 -38
- data/spec/unit/container/finalize_spec.rb +0 -97
- data/spec/unit/container/import_spec.rb +0 -53
- data/spec/unit/container/injector_spec.rb +0 -29
- data/spec/unit/container_spec.rb +0 -244
- data/spec/unit/loader_spec.rb +0 -64
- data/spec/unit/magic_comments_parser_spec.rb +0 -41
@@ -0,0 +1,33 @@
|
|
1
|
+
module Dry
|
2
|
+
module System
|
3
|
+
module Components
|
4
|
+
class Config
|
5
|
+
def self.new(&block)
|
6
|
+
config = super
|
7
|
+
yield(config) if block_given?
|
8
|
+
config
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@settings = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_hash
|
16
|
+
@settings
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def method_missing(meth, value = nil)
|
22
|
+
if meth.to_s.end_with?('=')
|
23
|
+
@settings[meth.to_s.gsub('=', '').to_sym] = value
|
24
|
+
elsif @settings.key?(meth)
|
25
|
+
@settings[meth]
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/dry/system/constants.rb
CHANGED
data/lib/dry/system/container.rb
CHANGED
@@ -6,6 +6,7 @@ require 'dry-container'
|
|
6
6
|
|
7
7
|
require 'dry/core/deprecations'
|
8
8
|
|
9
|
+
require 'dry/system'
|
9
10
|
require 'dry/system/errors'
|
10
11
|
require 'dry/system/loader'
|
11
12
|
require 'dry/system/booter'
|
@@ -77,6 +78,7 @@ module Dry
|
|
77
78
|
setting :auto_registrar, Dry::System::AutoRegistrar
|
78
79
|
setting :manual_registrar, Dry::System::ManualRegistrar
|
79
80
|
setting :importer, Dry::System::Importer
|
81
|
+
setting(:components, {}, reader: true) { |v| v.dup }
|
80
82
|
|
81
83
|
class << self
|
82
84
|
extend Dry::Core::Deprecations['Dry::System::Container']
|
@@ -154,7 +156,7 @@ module Dry
|
|
154
156
|
# # system/boot/db.rb
|
155
157
|
# #
|
156
158
|
# # Simple component registration
|
157
|
-
# MyApp.
|
159
|
+
# MyApp.boot(:db) do |container|
|
158
160
|
# require 'db'
|
159
161
|
#
|
160
162
|
# container.register(:db, DB.new)
|
@@ -163,7 +165,7 @@ module Dry
|
|
163
165
|
# # system/boot/db.rb
|
164
166
|
# #
|
165
167
|
# # Component registration with lifecycle triggers
|
166
|
-
# MyApp.
|
168
|
+
# MyApp.boot(:db) do |container|
|
167
169
|
# init do
|
168
170
|
# require 'db'
|
169
171
|
# DB.configure(ENV['DB_URL'])
|
@@ -182,7 +184,7 @@ module Dry
|
|
182
184
|
# # system/boot/db.rb
|
183
185
|
# #
|
184
186
|
# # Component registration which uses another bootable component
|
185
|
-
# MyApp.
|
187
|
+
# MyApp.boot(:db) do |container|
|
186
188
|
# use :logger
|
187
189
|
#
|
188
190
|
# start do
|
@@ -209,9 +211,41 @@ module Dry
|
|
209
211
|
# @return [self]
|
210
212
|
#
|
211
213
|
# @api public
|
212
|
-
def
|
213
|
-
|
214
|
+
def boot(name, opts = {}, &block)
|
215
|
+
if components.key?(name)
|
216
|
+
raise DuplicatedComponentKeyError, "Bootable component #{name.inspect} was already registered"
|
217
|
+
end
|
218
|
+
|
219
|
+
component =
|
220
|
+
if opts[:from]
|
221
|
+
boot_external(name, opts, &block)
|
222
|
+
else
|
223
|
+
boot_local(name, opts, &block)
|
224
|
+
end
|
214
225
|
self
|
226
|
+
|
227
|
+
components[name] = component
|
228
|
+
end
|
229
|
+
deprecate :finalize, :boot
|
230
|
+
|
231
|
+
# @api private
|
232
|
+
def boot_external(identifier, from:, key: nil, namespace: nil, &block)
|
233
|
+
component = System.providers[from].component(
|
234
|
+
key || identifier, key: identifier, namespace: namespace, finalize: block, container: self
|
235
|
+
)
|
236
|
+
|
237
|
+
booter.register_component(component)
|
238
|
+
|
239
|
+
component
|
240
|
+
end
|
241
|
+
|
242
|
+
# @api private
|
243
|
+
def boot_local(name, namespace: nil, &block)
|
244
|
+
component = Components::Bootable.new(name, container: self, namespace: namespace, &block)
|
245
|
+
|
246
|
+
booter.register_component(component)
|
247
|
+
|
248
|
+
component
|
215
249
|
end
|
216
250
|
|
217
251
|
# Return if a container was finalized
|
@@ -283,7 +317,6 @@ module Dry
|
|
283
317
|
booter.start(name)
|
284
318
|
self
|
285
319
|
end
|
286
|
-
deprecate :boot!, :start
|
287
320
|
|
288
321
|
# Boots a specific component but calls only `init` lifecycle trigger
|
289
322
|
#
|
@@ -302,7 +335,6 @@ module Dry
|
|
302
335
|
booter.init(name)
|
303
336
|
self
|
304
337
|
end
|
305
|
-
deprecate :boot, :init
|
306
338
|
|
307
339
|
# Sets load paths relative to the container's root dir
|
308
340
|
#
|
@@ -457,7 +489,12 @@ module Dry
|
|
457
489
|
|
458
490
|
# @api private
|
459
491
|
def booter
|
460
|
-
@booter ||= config.booter.new(
|
492
|
+
@booter ||= config.booter.new(boot_path)
|
493
|
+
end
|
494
|
+
|
495
|
+
# @api private
|
496
|
+
def boot_path
|
497
|
+
root.join("#{config.system_dir}/boot")
|
461
498
|
end
|
462
499
|
|
463
500
|
# @api private
|
@@ -476,14 +513,18 @@ module Dry
|
|
476
513
|
end
|
477
514
|
|
478
515
|
# @api private
|
479
|
-
def component(
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
516
|
+
def component(identifier, **options)
|
517
|
+
if (component = booter.components.detect { |c| c.identifier == identifier })
|
518
|
+
component
|
519
|
+
else
|
520
|
+
Component.new(
|
521
|
+
identifier,
|
522
|
+
loader: config.loader,
|
523
|
+
namespace: config.default_namespace,
|
524
|
+
separator: config.namespace_separator,
|
525
|
+
**options,
|
526
|
+
)
|
527
|
+
end
|
487
528
|
end
|
488
529
|
|
489
530
|
# @api private
|
@@ -504,12 +545,18 @@ module Dry
|
|
504
545
|
return self if key?(key)
|
505
546
|
|
506
547
|
component(key).tap do |component|
|
507
|
-
|
508
|
-
|
509
|
-
if importer.key?(root_key)
|
510
|
-
load_external_component(component.namespaced(root_key))
|
548
|
+
if component.boot?
|
549
|
+
booter.start(component)
|
511
550
|
else
|
512
|
-
|
551
|
+
root_key = component.root_key
|
552
|
+
|
553
|
+
if (bootable_dep = component(root_key)).boot?
|
554
|
+
booter.start(bootable_dep)
|
555
|
+
elsif importer.key?(root_key)
|
556
|
+
load_imported_component(component.namespaced(root_key))
|
557
|
+
else
|
558
|
+
load_local_component(component)
|
559
|
+
end
|
513
560
|
end
|
514
561
|
end
|
515
562
|
|
@@ -536,7 +583,7 @@ module Dry
|
|
536
583
|
end
|
537
584
|
|
538
585
|
# @api private
|
539
|
-
def
|
586
|
+
def load_imported_component(component)
|
540
587
|
container = importer[component.namespace]
|
541
588
|
container.load_component(component.identifier)
|
542
589
|
importer.(component.namespace, container)
|
data/lib/dry/system/errors.rb
CHANGED
@@ -14,8 +14,8 @@ module Dry
|
|
14
14
|
#
|
15
15
|
# @api public
|
16
16
|
ComponentFileMismatchError = Class.new(StandardError) do
|
17
|
-
def initialize(
|
18
|
-
super("
|
17
|
+
def initialize(component)
|
18
|
+
super("Boot file for component #{component.identifier.inspect} not found. Container boot files under #{component.boot_path}: #{component.container_boot_files.inspect}")
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
data/lib/dry/system/lifecycle.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'concurrent/map'
|
2
2
|
|
3
|
+
require 'dry/system/settings'
|
4
|
+
|
3
5
|
module Dry
|
4
6
|
module System
|
5
7
|
# Lifecycle booting DSL
|
@@ -23,9 +25,11 @@ module Dry
|
|
23
25
|
|
24
26
|
attr_reader :triggers
|
25
27
|
|
28
|
+
attr_reader :opts
|
29
|
+
|
26
30
|
# @api private
|
27
|
-
def self.new(container, &block)
|
28
|
-
cache.fetch_or_store([container, block].hash) do
|
31
|
+
def self.new(container, opts = {}, &block)
|
32
|
+
cache.fetch_or_store([container, opts, block].hash) do
|
29
33
|
super
|
30
34
|
end
|
31
35
|
end
|
@@ -36,11 +40,13 @@ module Dry
|
|
36
40
|
end
|
37
41
|
|
38
42
|
# @api private
|
39
|
-
def initialize(container, &block)
|
43
|
+
def initialize(container, opts, &block)
|
40
44
|
@container = container
|
45
|
+
@settings = nil
|
41
46
|
@statuses = []
|
42
47
|
@triggers = {}
|
43
|
-
|
48
|
+
@opts = opts
|
49
|
+
instance_exec(target, &block)
|
44
50
|
end
|
45
51
|
|
46
52
|
# @api private
|
@@ -53,6 +59,21 @@ module Dry
|
|
53
59
|
end
|
54
60
|
end
|
55
61
|
|
62
|
+
# @api private
|
63
|
+
def settings(&block)
|
64
|
+
component.settings(&block)
|
65
|
+
end
|
66
|
+
|
67
|
+
# @api private
|
68
|
+
def configure(&block)
|
69
|
+
component.configure(&block)
|
70
|
+
end
|
71
|
+
|
72
|
+
# @api private
|
73
|
+
def config
|
74
|
+
component.config
|
75
|
+
end
|
76
|
+
|
56
77
|
# @api private
|
57
78
|
def init(&block)
|
58
79
|
trigger!(:init, &block)
|
@@ -71,7 +92,7 @@ module Dry
|
|
71
92
|
# @api private
|
72
93
|
def use(*names)
|
73
94
|
names.each do |name|
|
74
|
-
|
95
|
+
target.start(name)
|
75
96
|
end
|
76
97
|
end
|
77
98
|
|
@@ -80,12 +101,22 @@ module Dry
|
|
80
101
|
container.register(*args, &block)
|
81
102
|
end
|
82
103
|
|
104
|
+
# @api private
|
105
|
+
def component
|
106
|
+
opts[:component]
|
107
|
+
end
|
108
|
+
|
109
|
+
# @api private
|
110
|
+
def target
|
111
|
+
component.container
|
112
|
+
end
|
113
|
+
|
83
114
|
private
|
84
115
|
|
85
116
|
# @api private
|
86
117
|
def trigger!(name, &block)
|
87
118
|
if triggers.key?(name)
|
88
|
-
triggers[name].()
|
119
|
+
triggers[name].(target)
|
89
120
|
elsif block
|
90
121
|
triggers[name] = block
|
91
122
|
end
|
@@ -93,7 +124,9 @@ module Dry
|
|
93
124
|
|
94
125
|
# @api private
|
95
126
|
def method_missing(meth, *args, &block)
|
96
|
-
if
|
127
|
+
if target.key?(meth)
|
128
|
+
target[meth]
|
129
|
+
elsif container.key?(meth)
|
97
130
|
container[meth]
|
98
131
|
elsif ::Kernel.respond_to?(meth)
|
99
132
|
::Kernel.public_send(meth, *args, &block)
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'concurrent/map'
|
2
|
+
require 'dry/system/components/bootable'
|
3
|
+
|
4
|
+
module Dry
|
5
|
+
module System
|
6
|
+
class Provider
|
7
|
+
attr_reader :identifier
|
8
|
+
|
9
|
+
attr_reader :options
|
10
|
+
|
11
|
+
attr_reader :components
|
12
|
+
|
13
|
+
def initialize(identifier, options)
|
14
|
+
@identifier = identifier
|
15
|
+
@options = options
|
16
|
+
@components = Concurrent::Map.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def boot_path
|
20
|
+
options.fetch(:boot_path)
|
21
|
+
end
|
22
|
+
|
23
|
+
def boot_files
|
24
|
+
Dir[boot_path.join('**/*.rb')]
|
25
|
+
end
|
26
|
+
|
27
|
+
def register_component(name, fn)
|
28
|
+
components[name] = Components::Bootable.new(name, &fn)
|
29
|
+
end
|
30
|
+
|
31
|
+
def boot_file(name)
|
32
|
+
boot_files.detect { |path| Pathname(path).basename('.rb').to_s == name.to_s }
|
33
|
+
end
|
34
|
+
|
35
|
+
def component(name, options = {})
|
36
|
+
components.fetch(name).with(options)
|
37
|
+
end
|
38
|
+
|
39
|
+
def load_components
|
40
|
+
boot_files.each { |f| require f }
|
41
|
+
freeze
|
42
|
+
self
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Dry
|
2
|
+
module System
|
3
|
+
class ProviderRegistry
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
attr_reader :items
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@items = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def each(&block)
|
13
|
+
items.each(&block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def register(identifier, options)
|
17
|
+
items << Provider.new(identifier, options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def [](identifier)
|
21
|
+
detect { |provider| provider.identifier == identifier }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "dry/core/class_builder"
|
2
|
+
require "dry/types"
|
3
|
+
require "dry/struct"
|
4
|
+
|
5
|
+
require "dry/system/settings/file_loader"
|
6
|
+
|
7
|
+
module Dry
|
8
|
+
module System
|
9
|
+
module Settings
|
10
|
+
class DSL < BasicObject
|
11
|
+
attr_reader :identifier
|
12
|
+
|
13
|
+
attr_reader :schema
|
14
|
+
|
15
|
+
def initialize(identifier, &block)
|
16
|
+
@identifier = identifier
|
17
|
+
@schema = {}
|
18
|
+
instance_eval(&block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def call
|
22
|
+
Core::ClassBuilder.new(name: 'Configuration', parent: Settings::Configuration).call do |klass|
|
23
|
+
schema.each do |key, type|
|
24
|
+
klass.setting(key, type)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def key(name, type)
|
30
|
+
schema[name] = type
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Configuration < Dry::Struct
|
35
|
+
constructor_type :strict_with_defaults
|
36
|
+
|
37
|
+
def self.setting(*args)
|
38
|
+
attribute(*args)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.load(root, env)
|
42
|
+
env_data = load_files(root, env)
|
43
|
+
|
44
|
+
attributes = schema.each_with_object({}) do |(key, type), h|
|
45
|
+
value = ENV.fetch(key.to_s.upcase) { env_data[key.to_s.upcase] }
|
46
|
+
h[key] = value
|
47
|
+
end
|
48
|
+
|
49
|
+
new(attributes)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.load_files(root, env)
|
53
|
+
FileLoader.new.(root, env)
|
54
|
+
end
|
55
|
+
private_class_method :load_files
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|