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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 691aea0bf618106d932309794bcf87afa5d84a3c423871342c2ceb39b45a6ce6
4
- data.tar.gz: 1ac5655641e9ffd965e3f0b37a199367e7157074a14250745a49925bab0ec517
3
+ metadata.gz: 75ae2c71ec73569babb52c596854afc53947908e0d6e4043bd7af02395cd3f33
4
+ data.tar.gz: e60b2a914e0479ec74226a92aa9d6e257c37bc4383d980d838e8ecb18dfe8c3d
5
5
  SHA512:
6
- metadata.gz: 589e77b1739b554528f13633f93bf61c39f4945067318f08afcc5be5bf0afbc53db137f54d0e1b2202aa45a5f2a3df697564cfc7f208cb3fa043d28b0f174706
7
- data.tar.gz: 8271fb82fde50c7bfed6e52da6a58ea90a447ee7097562402cfd38d94823edb29bee835b0e462bc893ddb59ddb76f1d0fe0c9dab99d4cf14062f74082ab0ccdc
6
+ metadata.gz: 11cff300881fb7e00e2575fcc0c1fc3d3d9e9ae0046035287d2c8aa9df47afca1c5f05abce90224899eb503aaa43b47402fa0a25f6d2c1626246aef31c338489
7
+ data.tar.gz: 1f28987740aa6cfc5ab97a20039e62d11cc5394d100dcf1df9c94f663577dfd2fdd363bc8dcb9ff67d162f94fffbb413f304d530563044697b8a638de782a746
@@ -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
@@ -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
@@ -25,7 +25,7 @@ module Dry
25
25
  private
26
26
 
27
27
  def attributes_errors(attributes)
28
- attributes.map { |key, error| "#{key}: #{error}" }
28
+ attributes.map { |key, error| "#{key.name}: #{error}" }
29
29
  end
30
30
  end
31
31
 
@@ -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
- require component.path
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)
@@ -27,6 +27,7 @@ module Dry
27
27
  registry.each do |name, container|
28
28
  call(name, container.finalize!)
29
29
  end
30
+ self
30
31
  end
31
32
 
32
33
  # @api private
@@ -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, decorator: proxy.new(target, notifications))
38
+ decorate(key, with: proxy.new(target, notifications))
40
39
  end
41
40
  end
42
41
  end
@@ -42,11 +42,11 @@ module Dry
42
42
  attributes = {}
43
43
  errors = {}
44
44
 
45
- schema.each do |key, type|
46
- value = ENV.fetch(key.to_s.upcase) { env_data[key.to_s.upcase] }
47
- type_check = type.try(value || Undefined)
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
 
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module System
3
- VERSION = '0.10.1'.freeze
3
+ VERSION = '0.11.0'.freeze
4
4
  end
5
5
  end
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.10.1
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: 2018-07-04 00:00:00.000000000 Z
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.6'
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.6'
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: '0.5'
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: '0.5'
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.3.0
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
- rubyforge_project:
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