dry-system 0.10.1 → 0.11.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 +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
|