class Dry::Component::Container

Public Class Methods

auto_register!(dir) { |constant| ... } click to toggle source
# File lib/dry/component/container.rb, line 72
def self.auto_register!(dir, &_block)
  dir_root = root.join(dir.to_s.split('/')[0])

  Dir["#{root}/#{dir}/**/*.rb"].each do |path|
    component_path = path.to_s.gsub("#{dir_root}/", '').gsub('.rb', '')
    loader.load(component_path).tap do |component|
      next if key?(component.identifier)

      Kernel.require component.path

      if block_given?
        register(component.identifier, yield(component.constant))
      else
        register(component.identifier) { component.instance }
      end
    end
  end

  self
end
boot(name) click to toggle source
# File lib/dry/component/container.rb, line 109
def self.boot(name)
  require "#{config.core_dir}/boot/#{name}"
end
boot!(name) click to toggle source
# File lib/dry/component/container.rb, line 93
def self.boot!(name)
  check_component_identifier!(name)

  return self unless booted?(name)

  boot(name)

  finalizers[name].tap do |finalizer|
    finalizer.() if finalizer
  end

  booted[name] = true

  self
end
booted() click to toggle source
# File lib/dry/component/container.rb, line 186
def self.booted
  @booted ||= {}
end
booted?(name) click to toggle source
# File lib/dry/component/container.rb, line 113
def self.booted?(name)
  !booted.key?(name)
end
configure(&block) click to toggle source
Calls superclass method
# File lib/dry/component/container.rb, line 25
def self.configure(&block)
  super(&block)

  load_paths!(config.core_dir)

  self
end
finalize(name, &block) click to toggle source
# File lib/dry/component/container.rb, line 44
def self.finalize(name, &block)
  finalizers[name] = proc { block.(self) }
end
finalize!() { |self| ... } click to toggle source
# File lib/dry/component/container.rb, line 48
def self.finalize!(&_block)
  yield(self) if block_given?

  imports.each do |ns, container|
    import_container(ns, container.finalize!)
  end

  Dir[root.join("#{config.core_dir}/boot/**/*.rb")].each do |path|
    boot!(File.basename(path, '.rb').to_sym)
  end

  auto_register.each(&method(:auto_register!)) if auto_register?

  freeze
end
finalizers() click to toggle source
# File lib/dry/component/container.rb, line 190
def self.finalizers
  @finalizers ||= {}
end
import(other) click to toggle source
Calls superclass method
# File lib/dry/component/container.rb, line 33
def self.import(other)
  case other
  when Dry::Container::Namespace then super
  when Hash then imports.update(other)
  else
    if other < Component::Container
      imports.update(other.config.name => other)
    end
  end
end
imports() click to toggle source
# File lib/dry/component/container.rb, line 194
def self.imports
  @imports ||= {}
end
injector(options = {}) click to toggle source
# File lib/dry/component/container.rb, line 68
def self.injector(options = {})
  Injector.new(self, options: options)
end
load_component(key) click to toggle source
# File lib/dry/component/container.rb, line 125
def self.load_component(key)
  return self if key?(key)

  component = loader.load(key)
  src_key = component.namespaces[0]

  if imports.key?(src_key)
    src_container = imports[src_key]

    src_container.load_component(
      (component.namespaces - [src_key]).map(&:to_s).join('.')
    )

    import_container(src_key, src_container)
  else
    begin
      require_component(component) { |klass| register(key) { klass.new } }
    rescue FileNotFoundError => e
      if config.default_namespace
        load_component("#{config.default_namespace}#{config.namespace_separator}#{component.identifier}")
      else
        raise e
      end
    end
  end

  self
end
load_paths() click to toggle source
# File lib/dry/component/container.rb, line 182
def self.load_paths
  @load_paths ||= []
end
load_paths!(*dirs) click to toggle source
# File lib/dry/component/container.rb, line 169
def self.load_paths!(*dirs)
  dirs.map(&:to_s).each do |dir|
    path = root.join(dir)

    next if load_paths.include?(path)

    load_paths << path
    $LOAD_PATH.unshift(path.to_s)
  end

  self
end
loader() click to toggle source
# File lib/dry/component/container.rb, line 64
def self.loader
  @loader ||= config.loader.new(config)
end
require(*paths) click to toggle source
# File lib/dry/component/container.rb, line 117
def self.require(*paths)
  paths.flat_map { |path|
    path.to_s.include?('*') ? Dir[root.join(path)] : root.join(path)
  }.each { |path|
    Kernel.require path.to_s
  }
end
require_component(component) { |constant| ... } click to toggle source
# File lib/dry/component/container.rb, line 154
def self.require_component(component, &block)
  path = load_paths.detect { |p| p.join(component.file).exist? }

  if path
    Kernel.require component.path
    yield(component.constant) if block
  else
    fail FileNotFoundError, "could not resolve require file for #{component.identifier}"
  end
end
root() click to toggle source
# File lib/dry/component/container.rb, line 165
def self.root
  config.root
end

Private Class Methods

auto_register() click to toggle source
# File lib/dry/component/container.rb, line 208
def self.auto_register
  Array(config.auto_register)
end
auto_register?() click to toggle source
# File lib/dry/component/container.rb, line 212
def self.auto_register?
  !auto_register.empty?
end
check_component_identifier!(name) click to toggle source
# File lib/dry/component/container.rb, line 216
def self.check_component_identifier!(name)
  fail(
    ArgumentError,
    'component identifier must be a symbol'
  ) unless name.is_a?(Symbol)

  fail(
    ArgumentError,
    "component identifier +#{name}+ is invalid or boot file is missing"
  ) unless root.join("#{config.core_dir}/boot/#{name}.rb").exist?
end
import_container(ns, container) click to toggle source
# File lib/dry/component/container.rb, line 200
def self.import_container(ns, container)
  items = container._container.each_with_object({}) { |(key, item), res|
    res[[ns, key].join(config.namespace_separator)] = item
  }

  _container.update(items)
end