dry-system 0.10.0 → 0.10.1

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: d2a8be3e6a065030a843d21c8940d4869cfda202c1959c7094b601f8d266c499
4
- data.tar.gz: 1938faa66a1913ca2297d51ad0abd9a4f1f787426c4fe512103a3b9e2ada5394
3
+ metadata.gz: 691aea0bf618106d932309794bcf87afa5d84a3c423871342c2ceb39b45a6ce6
4
+ data.tar.gz: 1ac5655641e9ffd965e3f0b37a199367e7157074a14250745a49925bab0ec517
5
5
  SHA512:
6
- metadata.gz: 5766837f8f85f7d3ece0107d3f65f0f81501ec00088cf860e1d47ad7e18284c24ff02c6109d80559aa64473cadce187fd6840e81b9a96648b75718d3d571fcbf
7
- data.tar.gz: e26fd6ffb2d50c7b536a7ba7307ef348efcf6860f13487565975b17b34528fc876788705f655f0a3919b572eb26fc73b91cd2745156fb1d3acd6a737d3b0813c
6
+ metadata.gz: 589e77b1739b554528f13633f93bf61c39f4945067318f08afcc5be5bf0afbc53db137f54d0e1b2202aa45a5f2a3df697564cfc7f208cb3fa043d28b0f174706
7
+ data.tar.gz: 8271fb82fde50c7bfed6e52da6a58ea90a447ee7097562402cfd38d94823edb29bee835b0e462bc893ddb59ddb76f1d0fe0c9dab99d4cf14062f74082ab0ccdc
@@ -1,3 +1,15 @@
1
+ # 0.10.1 - 2018-07-05
2
+
3
+ ### Added
4
+
5
+ * Support for stopping bootable components with `Container.stop(component_name)` (GustavoCaso)
6
+
7
+ ### Fixed
8
+
9
+ * When using a non-finalized container, you can now resolve multiple different container objects registered using the same root key as a bootable component (timriley)
10
+
11
+ [Compare v0.10.0...v0.10.1](https://github.com/dry-rb/dry-system/compare/v0.10.0...v0.10.1)
12
+
1
13
  # 0.10.0 - 2018-06-07
2
14
 
3
15
  ### Added
@@ -17,10 +29,10 @@
17
29
 
18
30
  * A helpful error will be raised if an invalid setting value is provided (GustavoCaso)
19
31
  * When using setting plugin, will use default values from types (GustavoCaso)
20
- * Minimal supported ruby version was bump to `2.3` (flash-gordon)
32
+ * Minimal supported ruby version was bumped to `2.3` (flash-gordon)
21
33
  * `dry-struct` was updated to `~> 0.5` (flash-gordon)
22
34
 
23
- [Compare v0.9.2...master](https://github.com/dry-rb/dry-system/compare/v0.9.2...master)
35
+ [Compare v0.9.2...v0.10.0](https://github.com/dry-rb/dry-system/compare/v0.9.2...v0.10.0)
24
36
 
25
37
  # 0.9.2 - 2018-02-08
26
38
 
@@ -96,6 +96,15 @@ module Dry
96
96
  end
97
97
  end
98
98
 
99
+ # @api private
100
+ def stop(name_or_component)
101
+ call(name_or_component) do |component|
102
+ raise ComponentNotStartedError.new(name_or_component) unless booted.include?(component)
103
+ component.stop
104
+ yield if block_given?
105
+ end
106
+ end
107
+
99
108
  # @api private
100
109
  def call(name_or_component)
101
110
  with_component(name_or_component) do |component|
@@ -0,0 +1,664 @@
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
@@ -341,6 +341,21 @@ module Dry
341
341
  self
342
342
  end
343
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
+
344
359
  # Sets load paths relative to the container's root dir
345
360
  #
346
361
  # @example
@@ -560,7 +575,9 @@ module Dry
560
575
  booter.start(bootable_dep)
561
576
  elsif importer.key?(root_key)
562
577
  load_imported_component(component.namespaced(root_key))
563
- else
578
+ end
579
+
580
+ if !key?(key)
564
581
  load_local_component(component)
565
582
  end
566
583
  end
@@ -58,5 +58,14 @@ module Dry
58
58
  super("component identifier #{name.inspect} must be a symbol")
59
59
  end
60
60
  end
61
+
62
+ # Error raised when trying to stop a component that hasn't started yet
63
+ #
64
+ # @api public
65
+ ComponentNotStartedError = Class.new(StandardError) do
66
+ def initialize(component_name)
67
+ super("component +#{component_name}+ has not been started")
68
+ end
69
+ end
61
70
  end
62
71
  end
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module System
3
- VERSION = '0.10.0'.freeze
3
+ VERSION = '0.10.1'.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.0
4
+ version: 0.10.1
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-06-07 00:00:00.000000000 Z
11
+ date: 2018-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -197,6 +197,7 @@ 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
200
201
  - lib/dry/system/container.rb
201
202
  - lib/dry/system/errors.rb
202
203
  - lib/dry/system/importer.rb
@@ -240,7 +241,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
240
241
  version: '0'
241
242
  requirements: []
242
243
  rubyforge_project:
243
- rubygems_version: 2.7.6
244
+ rubygems_version: 2.7.5
244
245
  signing_key:
245
246
  specification_version: 4
246
247
  summary: Organize your code into reusable components