mjacobus/nurse-rb

View on GitHub
lib/nurse/dependency_container.rb

Summary

Maintainability
A
0 mins
Test Coverage
module Nurse
  # The dependency container class
  class DependencyContainer
    class UndefinedDependency < RuntimeError; end
    class DependencyAlreadyDefined < RuntimeError; end

    def initialize
      @factories = {}
      @shared_factories = {}
      @instances = {}
    end

    def share(dependency, &block)
      ensure_undefined(dependency)
      shared_factories[to_key(dependency)] = block
      self
    end

    def set(dependency, &block)
      ensure_undefined(dependency)
      factories[to_key(dependency)] = block
      self
    end

    def defined?(dependency)
      key = to_key(dependency)
      shared_factories.key?(key) || factories.key?(key)
    end

    def get(dependency, &_block)
      key = to_key(dependency)

      if self.defined?(key)
        return from_shared_factories(key) || from_factories(key)
      end

      return yield if block_given?

      fail UndefinedDependency, "'#{dependency}' was not defined"
    end

    def add_factory(factory)
      factory.attach_to(self)
    end

    protected

    attr_reader :factories
    attr_reader :instances
    attr_reader :shared_factories

    def from_shared_factories(key)
      return unless shared_factories.key?(key)
      instances[key] ||= shared_factories[key].call(self)
    end

    def from_factories(key)
      factories[key].call(self) if factories.key?(key)
    end

    def ensure_undefined(dependency)
      return unless self.defined?(dependency)
      fail DependencyAlreadyDefined,
           "Dependency '#{dependency}' was already defined"
    end

    def to_key(object)
      object.to_s
    end
  end
end