Class: Dry::System::Container
- Inherits:
-
Object
- Object
- Dry::System::Container
- Extended by:
- Core::Container::Mixin, Plugins
- Defined in:
- lib/dry/system/container.rb,
lib/dry/system/stubs.rb
Overview
Abstract container class to inherit from
Container class is treated as a global registry with all system components. Container can also import dependencies from other containers, which is useful in complex systems that are split into sub-systems.
Container can be finalized, which triggers loading of all the defined components within a system, after finalization it becomes frozen. This typically happens in cases like booting a web application.
Before finalization, Container can lazy-load components on demand. A component can be a simple class defined in a single file, or a complex component which has init/start/stop lifecycle, and it’s defined in a boot file. Components which specify their dependencies using Import module can be safely required in complete isolation, and Container will resolve and load these dependencies automatically.
Furthermore, Container supports auto-registering components based on dir/file naming conventions. This reduces a lot of boilerplate code as all you have to do is to put your classes under configured directories and their instances will be automatically registered within a container.
Every container needs to be configured with following settings:
-
‘:name` - a unique container name
-
‘:root` - a system root directory (defaults to `pwd`)
Defined Under Namespace
Modules: Stubs
Class Method Summary collapse
-
._configurable_finalize! ⇒ Object
private
Finalizes the config for this container.
-
.add_to_load_path!(*dirs) ⇒ self
Adds the directories (relative to the container’s root) to the Ruby load path.
-
.after(event, &block) ⇒ self
Registers a callback hook to run after container lifecycle events.
- .auto_registrar ⇒ Object private
-
.before(event, &block) ⇒ self
Registers a callback hook to run before container lifecycle events.
- .component_dirs ⇒ Object private
-
.config ⇒ Dry::Configurable::Config
Returns the configuration for the container.
-
.configure(finalize_config: true) ⇒ self
Yields a configuration object for the container, which you can use to modify the configuration, then runs the after-‘configured` hooks and finalizes (freezes) the Container.config.
-
.configured!(finalize_config: true) ⇒ self
Marks the container as configured, runs the after-‘configured` hooks, then finalizes (freezes) the Container.config.
- .configured? ⇒ Boolean
-
.enable_stubs! ⇒ Object
Enables stubbing container’s components.
-
.finalize!(freeze: true) ⇒ self
Finalizes the container.
-
.finalized? ⇒ TrueClass, FalseClass
Return if a container was finalized.
- .hooks ⇒ Object private
-
.import(from:, as:, keys: nil) ⇒ Object
Registers another container for import.
- .importer ⇒ Object private
- .inherited(klass) ⇒ Object private
-
.injector(**options) ⇒ Object
Builds injector for this container.
-
.key?(key) ⇒ Boolean
Check if identifier is registered.
- .load_registrations!(name) ⇒ Object
- .manifest_registrar ⇒ Object private
-
.prepare(name) ⇒ self
Prepares a provider using its ‘prepare` lifecycle trigger.
- .providers ⇒ Object private
-
.register_provider(name, namespace: nil, from: nil, source: nil) ⇒ self
Registers a provider and its lifecycle hooks.
-
.registered?(key) ⇒ Boolean
Whether a
key
is registered (doesn’t trigger loading). -
.require_from_root(*paths) ⇒ Object
Requires one or more files relative to the container’s root.
- .resolve(key) ⇒ Object
-
.root ⇒ Pathname
Returns container’s root path.
- .shutdown! ⇒ Object
-
.start(name) ⇒ self
Starts a provider.
-
.stop(name) ⇒ self
Stop a specific component but calls only ‘stop` lifecycle trigger.
Methods included from Plugins
enabled_plugins, inherited, loaded_dependencies, register, registry, use
Class Method Details
._configurable_finalize! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Finalizes the config for this container
141 |
# File 'lib/dry/system/container.rb', line 141 alias_method :_configurable_finalize!, :finalize! |
.add_to_load_path!(*dirs) ⇒ self
Adds the directories (relative to the container’s root) to the Ruby load path
407 408 409 410 411 412 |
# File 'lib/dry/system/container.rb', line 407 def add_to_load_path!(*dirs) dirs.reverse.map(&root.method(:join)).each do |path| $LOAD_PATH.prepend(path.to_s) unless $LOAD_PATH.include?(path.to_s) end self end |
.after(event, &block) ⇒ self
Registers a callback hook to run after container lifecycle events.
The supported events are:
-
‘:configured`, called when you run configure or configured!, or when running finalize! and neither of the prior two methods have been called.
-
‘:finalized`, called when you run finalize!.
When the given block is called, ‘self` is the container class, and no block arguments are given.
580 581 582 583 |
# File 'lib/dry/system/container.rb', line 580 def after(event, &block) hooks[:"after_#{event}"] << block self end |
.auto_registrar ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
530 531 532 |
# File 'lib/dry/system/container.rb', line 530 def auto_registrar @auto_registrar ||= config.auto_registrar.new(self) end |
.before(event, &block) ⇒ self
Registers a callback hook to run before container lifecycle events.
Currently, the only supported event is ‘:finalized`. This hook is called when you run `finalize!`.
When the given block is called, ‘self` is the container class, and no block arguments are given.
558 559 560 561 |
# File 'lib/dry/system/container.rb', line 558 def before(event, &block) hooks[:"before_#{event}"] << block self end |
.component_dirs ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
520 521 522 |
# File 'lib/dry/system/container.rb', line 520 def component_dirs config.component_dirs.to_a.map { |dir| ComponentDir.new(config: dir, container: self) } end |
.config ⇒ Dry::Configurable::Config
Returns the configuration for the container
|
# File 'lib/dry/system/container.rb', line 74
|
.configure(finalize_config: true) ⇒ self
Yields a configuration object for the container, which you can use to modify the configuration, then runs the after-‘configured` hooks and finalizes (freezes) the config.
Does not finalize the config when given ‘finalize_config: false`
106 107 108 109 |
# File 'lib/dry/system/container.rb', line 106 def configure(finalize_config: true, &) super(&) configured!(finalize_config: finalize_config) end |
.configured!(finalize_config: true) ⇒ self
Marks the container as configured, runs the after-‘configured` hooks, then finalizes (freezes) the config.
This method is useful to call if you’re modifying the container’s config directly, rather than via the config object yielded when calling configure.
Does not finalize the config if given ‘finalize_config: false`.
126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/dry/system/container.rb', line 126 def configured!(finalize_config: true) return self if configured? hooks[:after_configure].each { |hook| instance_eval(&hook) } _configurable_finalize! if finalize_config @__configured__ = true self end |
.configured? ⇒ Boolean
143 144 145 |
# File 'lib/dry/system/container.rb', line 143 def configured? @__configured__.equal?(true) end |
.enable_stubs! ⇒ Object
Enables stubbing container’s components
32 33 34 35 36 |
# File 'lib/dry/system/stubs.rb', line 32 def self.enable_stubs! super extend ::Dry::System::Container::Stubs self end |
.finalize!(freeze: true) ⇒ self
Finalizes the container
This triggers importing components from other containers, booting registered components and auto-registering components. It should be called only in places where you want to finalize your system as a whole, ie when booting a web application
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
# File 'lib/dry/system/container.rb', line 317 def finalize!(freeze: true, &) return self if finalized? configured! run_hooks(:finalize) do yield(self) if block_given? [providers, auto_registrar, manifest_registrar, importer].each(&:finalize!) @__finalized__ = true self.freeze if freeze end self end |
.finalized? ⇒ TrueClass, FalseClass
Return if a container was finalized
284 285 286 |
# File 'lib/dry/system/container.rb', line 284 def finalized? @__finalized__.equal?(true) end |
.hooks ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
586 587 588 |
# File 'lib/dry/system/container.rb', line 586 def hooks @hooks ||= Hash.new { |h, k| h[k] = [] } end |
.import(from:, as:, keys: nil) ⇒ Object
Registers another container for import
178 179 180 181 182 183 184 |
# File 'lib/dry/system/container.rb', line 178 def import(from:, as:, keys: nil) raise Dry::System::ContainerAlreadyFinalizedError if finalized? importer.register(container: from, namespace: as, keys: keys) self end |
.importer ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
540 541 542 |
# File 'lib/dry/system/container.rb', line 540 def importer @importer ||= config.importer.new(self) end |
.inherited(klass) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
591 592 593 594 595 596 597 598 599 600 |
# File 'lib/dry/system/container.rb', line 591 def inherited(klass) hooks.each do |event, blocks| klass.hooks[event].concat blocks.dup end klass.instance_variable_set(:@__configured__, false) klass.instance_variable_set(:@__finalized__, false) super end |
.injector(**options) ⇒ Object
Builds injector for this container
An injector is a useful mixin which injects dependencies into automatically defined constructor.
445 446 447 |
# File 'lib/dry/system/container.rb', line 445 def injector(**) Dry::AutoInject(self, **) end |
.key?(key) ⇒ Boolean
Check if identifier is registered. If not, try to load the component
510 511 512 513 514 515 516 517 |
# File 'lib/dry/system/container.rb', line 510 def key?(key) if finalized? registered?(key) else registered?(key) || resolve(key) { return false } true end end |
.load_registrations!(name) ⇒ Object
415 416 417 418 |
# File 'lib/dry/system/container.rb', line 415 def load_registrations!(name) manifest_registrar.(name) self end |
.manifest_registrar ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
535 536 537 |
# File 'lib/dry/system/container.rb', line 535 def manifest_registrar @manifest_registrar ||= config.manifest_registrar.new(self) end |
.prepare(name) ⇒ self
Prepares a provider using its ‘prepare` lifecycle trigger
Preparing (as opposed to starting) a provider is useful in places where some aspects of a heavier dependency are needed, but its fully started environment
365 366 367 368 |
# File 'lib/dry/system/container.rb', line 365 def prepare(name) providers.prepare(name) self end |
.providers ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
525 526 527 |
# File 'lib/dry/system/container.rb', line 525 def providers @providers ||= config.provider_registrar.new(self) end |
.register_provider(name, namespace: nil, from: nil, source: nil) ⇒ self
273 274 275 |
# File 'lib/dry/system/container.rb', line 273 def register_provider(...) providers.register_provider(...) end |
.registered?(key) ⇒ Boolean
Whether a key
is registered (doesn’t trigger loading)
495 |
# File 'lib/dry/system/container.rb', line 495 alias_method :registered?, :key? |
.require_from_root(*paths) ⇒ Object
Requires one or more files relative to the container’s root
461 462 463 464 465 466 467 |
# File 'lib/dry/system/container.rb', line 461 def require_from_root(*paths) paths.flat_map { |path| path.to_s.include?("*") ? ::Dir[root.join(path)] : root.join(path) }.each { |path| Kernel.require path.to_s } end |
.resolve(key) ⇒ Object
488 489 490 491 492 |
# File 'lib/dry/system/container.rb', line 488 def resolve(key) load_component(key) unless finalized? super end |
.root ⇒ Pathname
Returns container’s root path
483 484 485 |
# File 'lib/dry/system/container.rb', line 483 def root config.root end |
.shutdown! ⇒ Object
386 387 388 389 |
# File 'lib/dry/system/container.rb', line 386 def shutdown! providers.shutdown self end |
.start(name) ⇒ self
Starts a provider
As a result, the provider’s ‘prepare` and `start` lifecycle triggers are called
347 348 349 350 |
# File 'lib/dry/system/container.rb', line 347 def start(name) providers.start(name) self end |
.stop(name) ⇒ self
Stop a specific component but calls only ‘stop` lifecycle trigger
380 381 382 383 |
# File 'lib/dry/system/container.rb', line 380 def stop(name) providers.stop(name) self end |