module Dry::Container::Mixin

Mixin to expose Inversion of Control (IoC) container behaviour

@example

class MyClass
  extend Dry::Container::Mixin
end

MyClass.register(:item, 'item')
MyClass.resolve(:item)
=> 'item'

class MyObject
  include Dry::Container::Mixin
end

container = MyObject.new
container.register(:item, 'item')
container.resolve(:item)
=> 'item'

@api public

Public Class Methods

extended(base) click to toggle source

@private

# File lib/dry/container/mixin.rb, line 37
def self.extended(base)
  hooks_mod = ::Module.new do
    def inherited(subclass)
      subclass.instance_variable_set(:@_container, @_container.dup)
      super
    end
  end

  base.class_eval do
    extend ::Dry::Configurable
    extend hooks_mod

    setting :registry, ::Dry::Container::Registry.new
    setting :resolver, ::Dry::Container::Resolver.new
    setting :namespace_separator, '.'

    @_container = ::Concurrent::Hash.new
  end
end
included(base) click to toggle source

@private

# File lib/dry/container/mixin.rb, line 66
def self.included(base)
  base.class_eval do
    extend ::Dry::Configurable
    prepend Initializer

    setting :registry, ::Dry::Container::Registry.new
    setting :resolver, ::Dry::Container::Resolver.new
    setting :namespace_separator, '.'

    def config
      self.class.config
    end
  end
end

Public Instance Methods

[](key) click to toggle source

Resolve an item from the container

@param [Mixed] key

The key for the item you wish to resolve

@return [Mixed]

@api public @see Dry::Container::Mixin#resolve

# File lib/dry/container/mixin.rb, line 133
def [](key)
  resolve(key)
end
_container() click to toggle source

@private no, really

# File lib/dry/container/mixin.rb, line 275
def _container
  @_container
end
clone() click to toggle source

@api public

Calls superclass method
# File lib/dry/container/mixin.rb, line 287
def clone
  copy = super
  unless copy.frozen?
    copy.instance_variable_set(:@_container, _container.dup)
  end
  copy
end
config() click to toggle source
# File lib/dry/container/mixin.rb, line 75
def config
  self.class.config
end
decorate(key, with: nil, &block) click to toggle source

Decorates an item from the container with specified decorator

@return [Dry::Container::Mixin] self

@api public

# File lib/dry/container/mixin.rb, line 214
def decorate(key, with: nil, &block)
  key = key.to_s
  original = _container.delete(key) do
    raise Error, "Nothing registered with the key #{key.inspect}"
  end

  if with.is_a?(Class)
    decorator = with.method(:new)
  elsif block.nil? && !with.respond_to?(:call)
    raise Error, "Decorator needs to be a Class, block, or respond to the `call` method"
  else
    decorator = with || block
  end

  _container[key] = original.map(decorator)
  self
end
dup() click to toggle source

@api public

Calls superclass method
# File lib/dry/container/mixin.rb, line 280
def dup
  copy = super
  copy.instance_variable_set(:@_container, _container.dup)
  copy
end
each(&block) click to toggle source

Calls block once for each key/value pair in the container, passing the key and the registered item parameters.

If no block is given, an enumerator is returned instead.

@return [Enumerator]

@api public

@note In discussions with other developers, it was felt that being able to iterate over not just

the registered keys, but to see what was registered would be very helpful. This is a step
toward doing that.
# File lib/dry/container/mixin.rb, line 205
def each(&block)
  config.resolver.each(_container, &block)
end
each_key(&block) click to toggle source

Calls block once for each key in container, passing the key as a parameter.

If no block is given, an enumerator is returned instead.

@return [Dry::Container::Mixin] self

@api public

# File lib/dry/container/mixin.rb, line 189
def each_key(&block)
  config.resolver.each_key(_container, &block)
  self
end
enable_stubs!() click to toggle source

Enable stubbing functionality into the current container

# File lib/dry/container/stub.rb, line 48
def enable_stubs!
  extend ::Dry::Container::Stub
end
freeze() click to toggle source

Freeze the container. Nothing can be registered after freezing

@api public

Calls superclass method
# File lib/dry/container/mixin.rb, line 268
def freeze
  super
  _container.freeze
  self
end
import(namespace) click to toggle source

Import a namespace

@param [Dry::Container::Namespace] namespace

The namespace to import

@return [Dry::Container::Mixin] self

@api public

# File lib/dry/container/mixin.rb, line 259
def import(namespace)
  namespace(namespace.name, &namespace.block)

  self
end
inherited(subclass) click to toggle source
Calls superclass method
# File lib/dry/container/mixin.rb, line 39
def inherited(subclass)
  subclass.instance_variable_set(:@_container, @_container.dup)
  super
end
key?(key) click to toggle source

Check whether an item is registered under the given key

@param [Mixed] key

The key you wish to check for registration with

@return [Bool]

@api public

# File lib/dry/container/mixin.rb, line 169
def key?(key)
  config.resolver.key?(_container, key)
end
keys() click to toggle source

An array of registered names for the container

@return [Array<String>]

@api public

# File lib/dry/container/mixin.rb, line 178
def keys
  config.resolver.keys(_container)
end
merge(other, namespace: nil) click to toggle source

Merge in the items of the other container

@param [Dry::Container] other

The other container to merge in

@param [Symbol, nil] namespace

Namespace to prefix other container items with, defaults to nil

@return [Dry::Container::Mixin] self

@api public

# File lib/dry/container/mixin.rb, line 147
def merge(other, namespace: nil)
  if namespace
    _container.merge!(
      other._container.each_with_object(::Concurrent::Hash.new) do |a, h|
        h[PREFIX_NAMESPACE.call(namespace, a.first, config)] = a.last
      end
    )
  else
    _container.merge!(other._container)
  end

  self
end
namespace(namespace, &block) click to toggle source

Evaluate block and register items in namespace

@param [Mixed] namespace

The namespace to register items in

@return [Dry::Container::Mixin] self

@api public

# File lib/dry/container/mixin.rb, line 240
def namespace(namespace, &block)
  ::Dry::Container::NamespaceDSL.new(
    self,
    namespace,
    config.namespace_separator,
    &block
  )

  self
end
register(key, contents = nil, options = EMPTY_HASH, &block) click to toggle source

Register an item with the container to be resolved later

@param [Mixed] key

The key to register the container item with (used to resolve)

@param [Mixed] contents

The item to register with the container (if no block given)

@param [Hash] options

Options to pass to the registry when registering the item

@yield

If a block is given, contents will be ignored and the block
will be registered instead

@return [Dry::Container::Mixin] self

@api public

# File lib/dry/container/mixin.rb, line 96
def register(key, contents = nil, options = EMPTY_HASH, &block)
  if block_given?
    item = block
    options = contents if contents.is_a?(::Hash)
  else
    item = contents
  end

  config.registry.call(_container, key, item, options)

  self
end
resolve(key, &block) click to toggle source

Resolve an item from the container

@param [Mixed] key

The key for the item you wish to resolve

@yield

Fallback block to call when a key is missing. Its result will be returned

@yieldparam [Mixed] key Missing key

@return [Mixed]

@api public

# File lib/dry/container/mixin.rb, line 120
def resolve(key, &block)
  config.resolver.call(_container, key, &block)
end