dry-system 0.10.1 → 0.11.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 +9 -0
- data/lib/dry/system/auto_registrar.rb +1 -1
- data/lib/dry/system/auto_registrar/configuration.rb +3 -1
- data/lib/dry/system/booter.rb +12 -0
- data/lib/dry/system/constants.rb +1 -1
- data/lib/dry/system/container.rb +18 -1
- data/lib/dry/system/importer.rb +1 -0
- data/lib/dry/system/plugins.rb +0 -3
- data/lib/dry/system/plugins/monitoring.rb +1 -2
- data/lib/dry/system/settings.rb +4 -4
- data/lib/dry/system/version.rb +1 -1
- metadata +14 -17
- data/lib/dry/system/container.mod.rb +0 -664
- data/lib/dry/system/plugins/decorate.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75ae2c71ec73569babb52c596854afc53947908e0d6e4043bd7af02395cd3f33
|
4
|
+
data.tar.gz: e60b2a914e0479ec74226a92aa9d6e257c37bc4383d980d838e8ecb18dfe8c3d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11cff300881fb7e00e2575fcc0c1fc3d3d9e9ae0046035287d2c8aa9df47afca1c5f05abce90224899eb503aaa43b47402fa0a25f6d2c1626246aef31c338489
|
7
|
+
data.tar.gz: 1f28987740aa6cfc5ab97a20039e62d11cc5394d100dcf1df9c94f663577dfd2fdd363bc8dcb9ff67d162f94fffbb413f304d530563044697b8a638de782a746
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
# 0.11.0 - 2019-03-22
|
2
|
+
|
3
|
+
### Changed
|
4
|
+
|
5
|
+
* [BREAKING] `:decorate` plugin was moved from dry-system to dry-container (available in 0.7.0+). To upgrade remove `use :decorate` and change `decorate` calls from `decorate(key, decorator: something)` to `decorate(key, with: something)` (flash-gordon)
|
6
|
+
* [internal] Compatibility with dry-struct 0.7.0 and dry-types 0.15.0
|
7
|
+
|
8
|
+
[Compare v0.10.1...v0.11.0](https://github.com/dry-rb/dry-system/compare/v0.10.1...v0.11.0)
|
9
|
+
|
1
10
|
# 0.10.1 - 2018-07-05
|
2
11
|
|
3
12
|
### Added
|
@@ -35,7 +35,7 @@ module Dry
|
|
35
35
|
next if !component.auto_register? || registration_config.exclude.(component)
|
36
36
|
|
37
37
|
container.require_component(component) do
|
38
|
-
register(component.identifier) { registration_config.instance.(component) }
|
38
|
+
register(component.identifier, memoize: registration_config.memoize) { registration_config.instance.(component) }
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -16,7 +16,6 @@ module Dry
|
|
16
16
|
def self.setting(name)
|
17
17
|
define_method(name) do |&block|
|
18
18
|
ivar = "@#{name}"
|
19
|
-
|
20
19
|
if block
|
21
20
|
instance_variable_set(ivar, block)
|
22
21
|
else
|
@@ -28,10 +27,13 @@ module Dry
|
|
28
27
|
setting :exclude
|
29
28
|
setting :instance
|
30
29
|
|
30
|
+
attr_accessor :memoize
|
31
|
+
|
31
32
|
# @api private
|
32
33
|
def initialize
|
33
34
|
@instance = DEFAULT_INSTANCE
|
34
35
|
@exclude = FALSE_PROC
|
36
|
+
@memoize = false
|
35
37
|
end
|
36
38
|
end
|
37
39
|
end
|
data/lib/dry/system/booter.rb
CHANGED
@@ -69,6 +69,15 @@ module Dry
|
|
69
69
|
freeze
|
70
70
|
end
|
71
71
|
|
72
|
+
# @api private
|
73
|
+
def shutdown
|
74
|
+
components.each do |component|
|
75
|
+
next unless booted.include?(component)
|
76
|
+
|
77
|
+
stop(component)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
72
81
|
# @api private
|
73
82
|
def init(name_or_component)
|
74
83
|
with_component(name_or_component) do |component|
|
@@ -100,7 +109,10 @@ module Dry
|
|
100
109
|
def stop(name_or_component)
|
101
110
|
call(name_or_component) do |component|
|
102
111
|
raise ComponentNotStartedError.new(name_or_component) unless booted.include?(component)
|
112
|
+
|
103
113
|
component.stop
|
114
|
+
booted.delete(component)
|
115
|
+
|
104
116
|
yield if block_given?
|
105
117
|
end
|
106
118
|
end
|
data/lib/dry/system/constants.rb
CHANGED
data/lib/dry/system/container.rb
CHANGED
@@ -304,6 +304,7 @@ module Dry
|
|
304
304
|
@__finalized__ = true
|
305
305
|
|
306
306
|
self.freeze if freeze
|
307
|
+
self
|
307
308
|
end
|
308
309
|
|
309
310
|
# Boots a specific component
|
@@ -356,6 +357,11 @@ module Dry
|
|
356
357
|
self
|
357
358
|
end
|
358
359
|
|
360
|
+
def shutdown!
|
361
|
+
booter.shutdown
|
362
|
+
self
|
363
|
+
end
|
364
|
+
|
359
365
|
# Sets load paths relative to the container's root dir
|
360
366
|
#
|
361
367
|
# @example
|
@@ -556,11 +562,22 @@ module Dry
|
|
556
562
|
raise FileNotFoundError, component
|
557
563
|
end
|
558
564
|
|
559
|
-
|
565
|
+
require_path(component.path)
|
560
566
|
|
561
567
|
yield
|
562
568
|
end
|
563
569
|
|
570
|
+
# Allows subclasses to use a different strategy for required files.
|
571
|
+
#
|
572
|
+
# E.g. apps that use `ActiveSupport::Dependencies::Loadable#require_dependency`
|
573
|
+
# will override this method to allow container managed dependencies to be reloaded
|
574
|
+
# for non-finalized containers.
|
575
|
+
#
|
576
|
+
# @api private
|
577
|
+
def require_path(path)
|
578
|
+
require path
|
579
|
+
end
|
580
|
+
|
564
581
|
# @api private
|
565
582
|
def load_component(key)
|
566
583
|
return self if key?(key)
|
data/lib/dry/system/importer.rb
CHANGED
data/lib/dry/system/plugins.rb
CHANGED
@@ -111,9 +111,6 @@ module Dry
|
|
111
111
|
require 'dry/system/plugins/env'
|
112
112
|
register(:env, Plugins::Env)
|
113
113
|
|
114
|
-
require 'dry/system/plugins/decorate'
|
115
|
-
register(:decorate, Plugins::Decorate)
|
116
|
-
|
117
114
|
require 'dry/system/plugins/notifications'
|
118
115
|
register(:notifications, Plugins::Notifications)
|
119
116
|
|
@@ -10,7 +10,6 @@ module Dry
|
|
10
10
|
def self.extended(system)
|
11
11
|
super
|
12
12
|
|
13
|
-
system.use(:decorate)
|
14
13
|
system.use(:notifications)
|
15
14
|
|
16
15
|
system.after(:configure) do
|
@@ -36,7 +35,7 @@ module Dry
|
|
36
35
|
end
|
37
36
|
end
|
38
37
|
|
39
|
-
decorate(key,
|
38
|
+
decorate(key, with: proxy.new(target, notifications))
|
40
39
|
end
|
41
40
|
end
|
42
41
|
end
|
data/lib/dry/system/settings.rb
CHANGED
@@ -42,11 +42,11 @@ module Dry
|
|
42
42
|
attributes = {}
|
43
43
|
errors = {}
|
44
44
|
|
45
|
-
schema.each do |key
|
46
|
-
value = ENV.fetch(key.to_s.upcase) { env_data[key.to_s.upcase] }
|
47
|
-
type_check =
|
45
|
+
schema.each do |key|
|
46
|
+
value = ENV.fetch(key.name.to_s.upcase) { env_data[key.name.to_s.upcase] }
|
47
|
+
type_check = key.try(value || Undefined)
|
48
48
|
|
49
|
-
attributes[key] = value if value
|
49
|
+
attributes[key.name] = value if value
|
50
50
|
errors[key] = type_check if type_check.failure?
|
51
51
|
end
|
52
52
|
|
data/lib/dry/system/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-system
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -56,36 +56,36 @@ dependencies:
|
|
56
56
|
name: dry-configurable
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0.7'
|
62
59
|
- - ">="
|
63
60
|
- !ruby/object:Gem::Version
|
64
61
|
version: 0.7.0
|
62
|
+
- - "~>"
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0.7'
|
65
65
|
type: :runtime
|
66
66
|
prerelease: false
|
67
67
|
version_requirements: !ruby/object:Gem::Requirement
|
68
68
|
requirements:
|
69
|
-
- - "~>"
|
70
|
-
- !ruby/object:Gem::Version
|
71
|
-
version: '0.7'
|
72
69
|
- - ">="
|
73
70
|
- !ruby/object:Gem::Version
|
74
71
|
version: 0.7.0
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0.7'
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
name: dry-container
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
78
78
|
requirements:
|
79
79
|
- - "~>"
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version: '0.
|
81
|
+
version: '0.7'
|
82
82
|
type: :runtime
|
83
83
|
prerelease: false
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
86
|
- - "~>"
|
87
87
|
- !ruby/object:Gem::Version
|
88
|
-
version: '0.
|
88
|
+
version: '0.7'
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
90
|
name: dry-equalizer
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,14 +126,14 @@ dependencies:
|
|
126
126
|
requirements:
|
127
127
|
- - "~>"
|
128
128
|
- !ruby/object:Gem::Version
|
129
|
-
version:
|
129
|
+
version: 0.7.0
|
130
130
|
type: :runtime
|
131
131
|
prerelease: false
|
132
132
|
version_requirements: !ruby/object:Gem::Requirement
|
133
133
|
requirements:
|
134
134
|
- - "~>"
|
135
135
|
- !ruby/object:Gem::Version
|
136
|
-
version:
|
136
|
+
version: 0.7.0
|
137
137
|
- !ruby/object:Gem::Dependency
|
138
138
|
name: bundler
|
139
139
|
requirement: !ruby/object:Gem::Requirement
|
@@ -197,7 +197,6 @@ files:
|
|
197
197
|
- lib/dry/system/components/bootable.rb
|
198
198
|
- lib/dry/system/components/config.rb
|
199
199
|
- lib/dry/system/constants.rb
|
200
|
-
- lib/dry/system/container.mod.rb
|
201
200
|
- lib/dry/system/container.rb
|
202
201
|
- lib/dry/system/errors.rb
|
203
202
|
- lib/dry/system/importer.rb
|
@@ -207,7 +206,6 @@ files:
|
|
207
206
|
- lib/dry/system/manual_registrar.rb
|
208
207
|
- lib/dry/system/plugins.rb
|
209
208
|
- lib/dry/system/plugins/bootsnap.rb
|
210
|
-
- lib/dry/system/plugins/decorate.rb
|
211
209
|
- lib/dry/system/plugins/env.rb
|
212
210
|
- lib/dry/system/plugins/logging.rb
|
213
211
|
- lib/dry/system/plugins/monitoring.rb
|
@@ -233,15 +231,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
233
231
|
requirements:
|
234
232
|
- - ">="
|
235
233
|
- !ruby/object:Gem::Version
|
236
|
-
version: 2.
|
234
|
+
version: 2.4.0
|
237
235
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
238
236
|
requirements:
|
239
237
|
- - ">="
|
240
238
|
- !ruby/object:Gem::Version
|
241
239
|
version: '0'
|
242
240
|
requirements: []
|
243
|
-
|
244
|
-
rubygems_version: 2.7.5
|
241
|
+
rubygems_version: 3.0.1
|
245
242
|
signing_key:
|
246
243
|
specification_version: 4
|
247
244
|
summary: Organize your code into reusable components
|
@@ -1,664 +0,0 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
|
3
|
-
require 'dry-auto_inject'
|
4
|
-
require 'dry-configurable'
|
5
|
-
require 'dry-container'
|
6
|
-
require 'dry/inflector'
|
7
|
-
|
8
|
-
require 'dry/core/deprecations'
|
9
|
-
|
10
|
-
require 'dry/system'
|
11
|
-
require 'dry/system/errors'
|
12
|
-
require 'dry/system/loader'
|
13
|
-
require 'dry/system/booter'
|
14
|
-
require 'dry/system/auto_registrar'
|
15
|
-
require 'dry/system/manual_registrar'
|
16
|
-
require 'dry/system/importer'
|
17
|
-
require 'dry/system/component'
|
18
|
-
require 'dry/system/constants'
|
19
|
-
require 'dry/system/plugins'
|
20
|
-
|
21
|
-
module Dry
|
22
|
-
module System
|
23
|
-
# Abstract container class to inherit from
|
24
|
-
#
|
25
|
-
# Container class is treated as a global registry with all system components.
|
26
|
-
# Container can also import dependencies from other containers, which is
|
27
|
-
# useful in complex systems that are split into sub-systems.
|
28
|
-
#
|
29
|
-
# Container can be finalized, which triggers loading of all the defined
|
30
|
-
# components within a system, after finalization it becomes frozen. This
|
31
|
-
# typically happens in cases like booting a web application.
|
32
|
-
#
|
33
|
-
# Before finalization, Container can lazy-load components on demand. A
|
34
|
-
# component can be a simple class defined in a single file, or a complex
|
35
|
-
# component which has init/start/stop lifecycle, and it's defined in a boot
|
36
|
-
# file. Components which specify their dependencies using Import module can
|
37
|
-
# be safely required in complete isolation, and Container will resolve and
|
38
|
-
# load these dependencies automatically.
|
39
|
-
#
|
40
|
-
# Furthermore, Container supports auto-registering components based on
|
41
|
-
# dir/file naming conventions. This reduces a lot of boilerplate code as all
|
42
|
-
# you have to do is to put your classes under configured directories and
|
43
|
-
# their instances will be automatically registered within a container.
|
44
|
-
#
|
45
|
-
# Every container needs to be configured with following settings:
|
46
|
-
#
|
47
|
-
# * `:name` - a unique container identifier
|
48
|
-
# * `:root` - a system root directory (defaults to `pwd`)
|
49
|
-
# * `:system_dir` - directory name relative to root, where bootable components
|
50
|
-
# can be defined in `boot` dir this defaults to `system`
|
51
|
-
#
|
52
|
-
# @example
|
53
|
-
# class MyApp < Dry::System::Container
|
54
|
-
# configure do |config|
|
55
|
-
# config.name = :my_app
|
56
|
-
#
|
57
|
-
# # this will auto-register classes from 'lib/components'. ie if you add
|
58
|
-
# # `lib/components/repo.rb` which defines `Repo` class, then it's
|
59
|
-
# # instance will be automatically available as `MyApp['repo']`
|
60
|
-
# config.auto_register = %w(lib/components)
|
61
|
-
# end
|
62
|
-
#
|
63
|
-
# # this will configure $LOAD_PATH to include your `lib` dir
|
64
|
-
# load_paths!('lib')
|
65
|
-
# end
|
66
|
-
#
|
67
|
-
# @api public
|
68
|
-
class Container
|
69
|
-
extend Dry::Configurable
|
70
|
-
extend Dry::Container::Mixin
|
71
|
-
extend Dry::System::Plugins
|
72
|
-
|
73
|
-
setting :name
|
74
|
-
setting :default_namespace
|
75
|
-
setting(:root, Pathname.pwd.freeze) { |path| Pathname(path) }
|
76
|
-
setting :system_dir, 'system'.freeze
|
77
|
-
setting :registrations_dir, 'container'.freeze
|
78
|
-
setting :auto_register, []
|
79
|
-
setting :inflector, Dry::Inflector.new
|
80
|
-
setting :loader, Dry::System::Loader
|
81
|
-
setting :booter, Dry::System::Booter
|
82
|
-
setting :auto_registrar, Dry::System::AutoRegistrar
|
83
|
-
setting :manual_registrar, Dry::System::ManualRegistrar
|
84
|
-
setting :importer, Dry::System::Importer
|
85
|
-
setting(:components, {}, reader: true) { |v| v.dup }
|
86
|
-
|
87
|
-
class << self
|
88
|
-
extend Dry::Core::Deprecations['Dry::System::Container']
|
89
|
-
|
90
|
-
# Configures the container
|
91
|
-
#
|
92
|
-
# @example
|
93
|
-
# class MyApp < Dry::System::Container
|
94
|
-
# configure do |config|
|
95
|
-
# config.root = Pathname("/path/to/app")
|
96
|
-
# config.name = :my_app
|
97
|
-
# config.auto_register = %w(lib/apis lib/core)
|
98
|
-
# end
|
99
|
-
# end
|
100
|
-
#
|
101
|
-
# @return [self]
|
102
|
-
#
|
103
|
-
# @api public
|
104
|
-
def configure(&block)
|
105
|
-
super(&block)
|
106
|
-
load_paths!(config.system_dir)
|
107
|
-
hooks[:configure].each { |hook| instance_eval(&hook) }
|
108
|
-
self
|
109
|
-
end
|
110
|
-
|
111
|
-
# Registers another container for import
|
112
|
-
#
|
113
|
-
# @example
|
114
|
-
# # system/container.rb
|
115
|
-
# class Core < Dry::System::Container
|
116
|
-
# configure do |config|
|
117
|
-
# config.root = Pathname("/path/to/app")
|
118
|
-
# config.auto_register = %w(lib/apis lib/core)
|
119
|
-
# end
|
120
|
-
# end
|
121
|
-
#
|
122
|
-
# # apps/my_app/system/container.rb
|
123
|
-
# require 'system/container'
|
124
|
-
#
|
125
|
-
# class MyApp < Dry::System::Container
|
126
|
-
# configure do |config|
|
127
|
-
# config.root = Pathname("/path/to/app")
|
128
|
-
# config.auto_register = %w(lib/apis lib/core)
|
129
|
-
# end
|
130
|
-
#
|
131
|
-
# import core: Core
|
132
|
-
# end
|
133
|
-
#
|
134
|
-
# @param other [Hash, Dry::Container::Namespace]
|
135
|
-
#
|
136
|
-
# @api public
|
137
|
-
def import(other)
|
138
|
-
case other
|
139
|
-
when Hash then importer.register(other)
|
140
|
-
when Dry::Container::Namespace then super
|
141
|
-
else
|
142
|
-
raise ArgumentError, "+other+ must be a hash of names and systems, or a Dry::Container namespace"
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
# Registers finalization function for a bootable component
|
147
|
-
#
|
148
|
-
# By convention, boot files for components should be placed in
|
149
|
-
# `%{system_dir}/boot` and they will be loaded on demand when components
|
150
|
-
# are loaded in isolation, or during finalization process.
|
151
|
-
#
|
152
|
-
# @example
|
153
|
-
# # system/container.rb
|
154
|
-
# class MyApp < Dry::System::Container
|
155
|
-
# configure do |config|
|
156
|
-
# config.root = Pathname("/path/to/app")
|
157
|
-
# config.name = :core
|
158
|
-
# config.auto_register = %w(lib/apis lib/core)
|
159
|
-
# end
|
160
|
-
#
|
161
|
-
# # system/boot/db.rb
|
162
|
-
# #
|
163
|
-
# # Simple component registration
|
164
|
-
# MyApp.boot(:db) do |container|
|
165
|
-
# require 'db'
|
166
|
-
#
|
167
|
-
# container.register(:db, DB.new)
|
168
|
-
# end
|
169
|
-
#
|
170
|
-
# # system/boot/db.rb
|
171
|
-
# #
|
172
|
-
# # Component registration with lifecycle triggers
|
173
|
-
# MyApp.boot(:db) do |container|
|
174
|
-
# init do
|
175
|
-
# require 'db'
|
176
|
-
# DB.configure(ENV['DB_URL'])
|
177
|
-
# container.register(:db, DB.new)
|
178
|
-
# end
|
179
|
-
#
|
180
|
-
# start do
|
181
|
-
# db.establish_connection
|
182
|
-
# end
|
183
|
-
#
|
184
|
-
# stop do
|
185
|
-
# db.close_connection
|
186
|
-
# end
|
187
|
-
# end
|
188
|
-
#
|
189
|
-
# # system/boot/db.rb
|
190
|
-
# #
|
191
|
-
# # Component registration which uses another bootable component
|
192
|
-
# MyApp.boot(:db) do |container|
|
193
|
-
# use :logger
|
194
|
-
#
|
195
|
-
# start do
|
196
|
-
# require 'db'
|
197
|
-
# DB.configure(ENV['DB_URL'], logger: logger)
|
198
|
-
# container.register(:db, DB.new)
|
199
|
-
# end
|
200
|
-
# end
|
201
|
-
#
|
202
|
-
# # system/boot/db.rb
|
203
|
-
# #
|
204
|
-
# # Component registration under a namespace. This will register the
|
205
|
-
# # db object under `persistence.db` key
|
206
|
-
# MyApp.namespace(:persistence) do |persistence|
|
207
|
-
# require 'db'
|
208
|
-
# DB.configure(ENV['DB_URL'], logger: logger)
|
209
|
-
# persistence.register(:db, DB.new)
|
210
|
-
# end
|
211
|
-
#
|
212
|
-
# @param name [Symbol] a unique identifier for a bootable component
|
213
|
-
#
|
214
|
-
# @see Lifecycle
|
215
|
-
#
|
216
|
-
# @return [self]
|
217
|
-
#
|
218
|
-
# @api public
|
219
|
-
def boot(name, opts = {}, &block)
|
220
|
-
if components.key?(name)
|
221
|
-
raise DuplicatedComponentKeyError, "Bootable component #{name.inspect} was already registered"
|
222
|
-
end
|
223
|
-
|
224
|
-
component =
|
225
|
-
if opts[:from]
|
226
|
-
boot_external(name, opts, &block)
|
227
|
-
else
|
228
|
-
boot_local(name, opts, &block)
|
229
|
-
end
|
230
|
-
self
|
231
|
-
|
232
|
-
components[name] = component
|
233
|
-
end
|
234
|
-
deprecate :finalize, :boot
|
235
|
-
|
236
|
-
# @api private
|
237
|
-
def boot_external(identifier, from:, key: nil, namespace: nil, &block)
|
238
|
-
component = System.providers[from].component(
|
239
|
-
identifier, key: key, namespace: namespace, finalize: block, container: self
|
240
|
-
)
|
241
|
-
|
242
|
-
booter.register_component(component)
|
243
|
-
|
244
|
-
component
|
245
|
-
end
|
246
|
-
|
247
|
-
# @api private
|
248
|
-
def boot_local(identifier, namespace: nil, &block)
|
249
|
-
component = Components::Bootable.new(identifier, container: self, namespace: namespace, &block)
|
250
|
-
|
251
|
-
booter.register_component(component)
|
252
|
-
|
253
|
-
component
|
254
|
-
end
|
255
|
-
|
256
|
-
# Return if a container was finalized
|
257
|
-
#
|
258
|
-
# @return [TrueClass, FalseClass]
|
259
|
-
#
|
260
|
-
# @api public
|
261
|
-
def finalized?
|
262
|
-
@__finalized__.equal?(true)
|
263
|
-
end
|
264
|
-
|
265
|
-
# Finalizes the container
|
266
|
-
#
|
267
|
-
# This triggers importing components from other containers, booting
|
268
|
-
# registered components and auto-registering components. It should be
|
269
|
-
# called only in places where you want to finalize your system as a
|
270
|
-
# whole, ie when booting a web application
|
271
|
-
#
|
272
|
-
# @example
|
273
|
-
# # system/container.rb
|
274
|
-
# class MyApp < Dry::System::Container
|
275
|
-
# configure do |config|
|
276
|
-
# config.root = Pathname("/path/to/app")
|
277
|
-
# config.name = :my_app
|
278
|
-
# config.auto_register = %w(lib/apis lib/core)
|
279
|
-
# end
|
280
|
-
# end
|
281
|
-
#
|
282
|
-
# # You can put finalization file anywhere you want, ie system/boot.rb
|
283
|
-
# MyApp.finalize!
|
284
|
-
#
|
285
|
-
# # If you need last-moment adjustments just before the finalization
|
286
|
-
# # you can pass a block and do it there
|
287
|
-
# MyApp.finalize! do |container|
|
288
|
-
# # stuff that only needs to happen for finalization
|
289
|
-
# end
|
290
|
-
#
|
291
|
-
# @return [self] frozen container
|
292
|
-
#
|
293
|
-
# @api public
|
294
|
-
def finalize!(freeze: true, &block)
|
295
|
-
return self if finalized?
|
296
|
-
|
297
|
-
yield(self) if block
|
298
|
-
|
299
|
-
importer.finalize!
|
300
|
-
booter.finalize!
|
301
|
-
manual_registrar.finalize!
|
302
|
-
auto_registrar.finalize!
|
303
|
-
|
304
|
-
@__finalized__ = true
|
305
|
-
|
306
|
-
self.freeze if freeze
|
307
|
-
end
|
308
|
-
|
309
|
-
# Boots a specific component
|
310
|
-
#
|
311
|
-
# As a result, `init` and `start` lifecycle triggers are called
|
312
|
-
#
|
313
|
-
# @example
|
314
|
-
# MyApp.start(:persistence)
|
315
|
-
#
|
316
|
-
# @param name [Symbol] the name of a registered bootable component
|
317
|
-
#
|
318
|
-
# @return [self]
|
319
|
-
#
|
320
|
-
# @api public
|
321
|
-
def start(name)
|
322
|
-
booter.start(name)
|
323
|
-
self
|
324
|
-
end
|
325
|
-
|
326
|
-
# Boots a specific component but calls only `init` lifecycle trigger
|
327
|
-
#
|
328
|
-
# This way of booting is useful in places where a heavy dependency is
|
329
|
-
# needed but its started environment is not required
|
330
|
-
#
|
331
|
-
# @example
|
332
|
-
# MyApp.init(:persistence)
|
333
|
-
#
|
334
|
-
# @param [Symbol] name The name of a registered bootable component
|
335
|
-
#
|
336
|
-
# @return [self]
|
337
|
-
#
|
338
|
-
# @api public
|
339
|
-
def init(name)
|
340
|
-
booter.init(name)
|
341
|
-
self
|
342
|
-
end
|
343
|
-
|
344
|
-
# Stop a specific component but calls only `stop` lifecycle trigger
|
345
|
-
#
|
346
|
-
# @example
|
347
|
-
# MyApp.stop(:persistence)
|
348
|
-
#
|
349
|
-
# @param [Symbol] name The name of a registered bootable component
|
350
|
-
#
|
351
|
-
# @return [self]
|
352
|
-
#
|
353
|
-
# @api public
|
354
|
-
def stop(name)
|
355
|
-
booter.stop(name)
|
356
|
-
self
|
357
|
-
end
|
358
|
-
|
359
|
-
# Sets load paths relative to the container's root dir
|
360
|
-
#
|
361
|
-
# @example
|
362
|
-
# class MyApp < Dry::System::Container
|
363
|
-
# configure do |config|
|
364
|
-
# # ...
|
365
|
-
# end
|
366
|
-
#
|
367
|
-
# load_paths!('lib')
|
368
|
-
# end
|
369
|
-
#
|
370
|
-
# @param [Array<String>] dirs
|
371
|
-
#
|
372
|
-
# @return [self]
|
373
|
-
#
|
374
|
-
# @api public
|
375
|
-
def load_paths!(*dirs)
|
376
|
-
dirs.map(&root.method(:join)).each do |path|
|
377
|
-
next if load_paths.include?(path)
|
378
|
-
load_paths << path
|
379
|
-
$LOAD_PATH.unshift(path.to_s)
|
380
|
-
end
|
381
|
-
self
|
382
|
-
end
|
383
|
-
|
384
|
-
# @api public
|
385
|
-
def load_registrations!(name)
|
386
|
-
manual_registrar.(name)
|
387
|
-
self
|
388
|
-
end
|
389
|
-
|
390
|
-
# Auto-registers components from the provided directory
|
391
|
-
#
|
392
|
-
# Typically you want to configure auto_register directories, and it will
|
393
|
-
# work automatically. Use this method in cases where you want to have an
|
394
|
-
# explicit way where some components are auto-registered, or if you want
|
395
|
-
# to exclude some components from being auto-registered
|
396
|
-
#
|
397
|
-
# @example
|
398
|
-
# class MyApp < Dry::System::Container
|
399
|
-
# configure do |config|
|
400
|
-
# # ...
|
401
|
-
# end
|
402
|
-
#
|
403
|
-
# # with a dir
|
404
|
-
# auto_register!('lib/core')
|
405
|
-
#
|
406
|
-
# # with a dir and a custom registration block
|
407
|
-
# auto_register!('lib/core') do |config|
|
408
|
-
# config.instance do |component|
|
409
|
-
# # custom way of initializing a component
|
410
|
-
# end
|
411
|
-
#
|
412
|
-
# config.exclude do |component|
|
413
|
-
# # return true to exclude component from auto-registration
|
414
|
-
# end
|
415
|
-
# end
|
416
|
-
# end
|
417
|
-
#
|
418
|
-
# @param [String] dir The dir name relative to the root dir
|
419
|
-
#
|
420
|
-
# @yield AutoRegistrar::Configuration
|
421
|
-
# @see AutoRegistrar::Configuration
|
422
|
-
#
|
423
|
-
# @return [self]
|
424
|
-
#
|
425
|
-
# @api public
|
426
|
-
def auto_register!(dir, &block)
|
427
|
-
auto_registrar.(dir, &block)
|
428
|
-
self
|
429
|
-
end
|
430
|
-
|
431
|
-
# Builds injector for this container
|
432
|
-
#
|
433
|
-
# An injector is a useful mixin which injects dependencies into
|
434
|
-
# automatically defined constructor.
|
435
|
-
#
|
436
|
-
# @example
|
437
|
-
# # Define an injection mixin
|
438
|
-
# #
|
439
|
-
# # system/import.rb
|
440
|
-
# Import = MyApp.injector
|
441
|
-
#
|
442
|
-
# # Use it in your auto-registered classes
|
443
|
-
# #
|
444
|
-
# # lib/user_repo.rb
|
445
|
-
# require 'import'
|
446
|
-
#
|
447
|
-
# class UserRepo
|
448
|
-
# include Import['persistence.db']
|
449
|
-
# end
|
450
|
-
#
|
451
|
-
# MyApp['user_repo].db # instance under 'persistence.db' key
|
452
|
-
#
|
453
|
-
# @param options [Hash] injector options
|
454
|
-
#
|
455
|
-
# @api public
|
456
|
-
def injector(options = {})
|
457
|
-
Dry::AutoInject(self, options)
|
458
|
-
end
|
459
|
-
|
460
|
-
# Requires one or more files relative to the container's root
|
461
|
-
#
|
462
|
-
# @example
|
463
|
-
# # single file
|
464
|
-
# MyApp.require_from_root('lib/core')
|
465
|
-
#
|
466
|
-
# # glob
|
467
|
-
# MyApp.require_from_root('lib/**/*')
|
468
|
-
#
|
469
|
-
# @param paths [Array<String>] one or more paths, supports globs too
|
470
|
-
#
|
471
|
-
# @api public
|
472
|
-
def require_from_root(*paths)
|
473
|
-
paths.flat_map { |path|
|
474
|
-
path.to_s.include?('*') ? Dir[root.join(path)] : root.join(path)
|
475
|
-
}.each { |path|
|
476
|
-
require path.to_s
|
477
|
-
}
|
478
|
-
end
|
479
|
-
|
480
|
-
# Returns container's root path
|
481
|
-
#
|
482
|
-
# @example
|
483
|
-
# class MyApp < Dry::System::Container
|
484
|
-
# configure do |config|
|
485
|
-
# config.root = Pathname('/my/app')
|
486
|
-
# end
|
487
|
-
# end
|
488
|
-
#
|
489
|
-
# MyApp.root # returns '/my/app' pathname
|
490
|
-
#
|
491
|
-
# @return [Pathname]
|
492
|
-
#
|
493
|
-
# @api public
|
494
|
-
def root
|
495
|
-
config.root
|
496
|
-
end
|
497
|
-
|
498
|
-
# @api public
|
499
|
-
def resolve(key)
|
500
|
-
load_component(key) unless finalized?
|
501
|
-
|
502
|
-
super
|
503
|
-
end
|
504
|
-
|
505
|
-
# @api private
|
506
|
-
def load_paths
|
507
|
-
@load_paths ||= []
|
508
|
-
end
|
509
|
-
|
510
|
-
# @api private
|
511
|
-
def booter
|
512
|
-
@booter ||= config.booter.new(boot_path)
|
513
|
-
end
|
514
|
-
|
515
|
-
# @api private
|
516
|
-
def boot_path
|
517
|
-
root.join("#{config.system_dir}/boot")
|
518
|
-
end
|
519
|
-
|
520
|
-
# @api private
|
521
|
-
def auto_registrar
|
522
|
-
@auto_registrar ||= config.auto_registrar.new(self)
|
523
|
-
end
|
524
|
-
|
525
|
-
# @api private
|
526
|
-
def manual_registrar
|
527
|
-
@manual_registrar ||= config.manual_registrar.new(self)
|
528
|
-
end
|
529
|
-
|
530
|
-
# @api private
|
531
|
-
def importer
|
532
|
-
@importer ||= config.importer.new(self)
|
533
|
-
end
|
534
|
-
|
535
|
-
# @api private
|
536
|
-
def component(identifier, **options)
|
537
|
-
if (component = booter.components.detect { |c| c.identifier == identifier })
|
538
|
-
component
|
539
|
-
else
|
540
|
-
Component.new(
|
541
|
-
identifier,
|
542
|
-
loader: config.loader,
|
543
|
-
namespace: config.default_namespace,
|
544
|
-
separator: config.namespace_separator,
|
545
|
-
inflector: config.inflector,
|
546
|
-
**options,
|
547
|
-
)
|
548
|
-
end
|
549
|
-
end
|
550
|
-
|
551
|
-
# @api private
|
552
|
-
def require_component(component)
|
553
|
-
return if key?(component.identifier)
|
554
|
-
|
555
|
-
unless component.file_exists?(load_paths)
|
556
|
-
raise FileNotFoundError, component
|
557
|
-
end
|
558
|
-
|
559
|
-
require component.path
|
560
|
-
|
561
|
-
yield
|
562
|
-
end
|
563
|
-
|
564
|
-
# @api private
|
565
|
-
def load_component(key)
|
566
|
-
puts "load_component #{key}"
|
567
|
-
return self if key?(key)
|
568
|
-
|
569
|
-
component(key).tap do |component|
|
570
|
-
if component.boot?
|
571
|
-
booter.start(component)
|
572
|
-
else
|
573
|
-
root_key = component.root_key
|
574
|
-
|
575
|
-
puts "root key:"
|
576
|
-
p root_key
|
577
|
-
|
578
|
-
# byebug
|
579
|
-
|
580
|
-
|
581
|
-
# if (bootable_dep = component(root_key)).boot?
|
582
|
-
# booter.start(bootable_dep)
|
583
|
-
|
584
|
-
if importer.key?(root_key)
|
585
|
-
load_imported_component(component.namespaced(root_key))
|
586
|
-
else
|
587
|
-
# Feels like we don't even need this if load_local_component gets involved with booting?
|
588
|
-
booter.start(root_key) if booter.bootable?(root_key)
|
589
|
-
|
590
|
-
|
591
|
-
load_local_component(component)
|
592
|
-
end
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
# if booter.bootable?(root_key)
|
597
|
-
# booter.start(root_key)
|
598
|
-
# elsif importer.key?(root_key)
|
599
|
-
# load_imported_component(component.namespaced(root_key))
|
600
|
-
# else
|
601
|
-
# load_local_component(component)
|
602
|
-
# end
|
603
|
-
end
|
604
|
-
end
|
605
|
-
|
606
|
-
self
|
607
|
-
end
|
608
|
-
|
609
|
-
# @api private
|
610
|
-
def after(event, &block)
|
611
|
-
hooks[event] << block
|
612
|
-
end
|
613
|
-
|
614
|
-
# @api private
|
615
|
-
def hooks
|
616
|
-
@__hooks__ ||= Hash.new { |h, k| h[k] = [] }
|
617
|
-
end
|
618
|
-
|
619
|
-
# @api private
|
620
|
-
def inherited(klass)
|
621
|
-
new_hooks = Container.hooks.dup
|
622
|
-
|
623
|
-
hooks.each do |event, blocks|
|
624
|
-
new_hooks[event].concat(blocks)
|
625
|
-
new_hooks[event].concat(klass.hooks[event])
|
626
|
-
end
|
627
|
-
|
628
|
-
klass.instance_variable_set(:@__hooks__, new_hooks)
|
629
|
-
super
|
630
|
-
end
|
631
|
-
|
632
|
-
private
|
633
|
-
|
634
|
-
# @api private
|
635
|
-
def load_local_component(component, default_namespace_fallback = false)
|
636
|
-
# byebug
|
637
|
-
|
638
|
-
# if booter.bootable?(component)
|
639
|
-
# booter.boot_dependency(component) unless finalized?
|
640
|
-
# end
|
641
|
-
|
642
|
-
if component.file_exists?(load_paths)
|
643
|
-
require_component(component) do
|
644
|
-
register(component.identifier) { component.instance }
|
645
|
-
end
|
646
|
-
elsif !default_namespace_fallback
|
647
|
-
load_local_component(component.prepend(config.default_namespace), true)
|
648
|
-
elsif manual_registrar.file_exists?(component)
|
649
|
-
manual_registrar.(component)
|
650
|
-
else
|
651
|
-
raise ComponentLoadError, component
|
652
|
-
end
|
653
|
-
end
|
654
|
-
|
655
|
-
# @api private
|
656
|
-
def load_imported_component(component)
|
657
|
-
container = importer[component.namespace]
|
658
|
-
container.load_component(component.identifier)
|
659
|
-
importer.(component.namespace, container)
|
660
|
-
end
|
661
|
-
end
|
662
|
-
end
|
663
|
-
end
|
664
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module Dry
|
2
|
-
module System
|
3
|
-
module Plugins
|
4
|
-
# @api public
|
5
|
-
module Decorate
|
6
|
-
# @api public
|
7
|
-
def decorate(key, decorator:)
|
8
|
-
original = _container.delete(key.to_s)
|
9
|
-
|
10
|
-
if original.is_a?(Dry::Container::Item) && original.options[:call] && decorator.is_a?(Class)
|
11
|
-
register(key) do
|
12
|
-
decorator.new(original.call)
|
13
|
-
end
|
14
|
-
else
|
15
|
-
decorated = decorator.is_a?(Class) ? decorator.new(original) : decorator
|
16
|
-
register(key, decorated)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|