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 38
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, default: Dry::Container::Registry.new
    setting :resolver, default: Dry::Container::Resolver.new
    setting :namespace_separator, default: "."

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

@private

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

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

    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 134
def [](key)
  resolve(key)
end
_container() click to toggle source

@private no, really

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

@api public

Calls superclass method
# File lib/dry/container/mixin.rb, line 288
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 76
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 215
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 281
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 206
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 190
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 50
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 269
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 260
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 40
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 170
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 179
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 148
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 241
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 97
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 121
def resolve(key, &block)
  config.resolver.call(_container, key, &block)
end