phallguy/scorpion

View on GitHub
lib/scorpion/hunter.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
module Scorpion
  # A concrete implementation of a Scorpion used to hunt down food for a {Scorpion::Object}.
  # @see Scorpion
  class Hunter
    include Scorpion

    # ============================================================================
    # @!group Attributes
    #

    # @return [Scorpion::DependencyMap] map of {Dependency} and how to create instances.
      attr_reader :dependency_map
      protected :dependency_map

    # @return [Scorpion] parent scorpion to deferr hunting to on missing dependency.
      attr_reader :parent
      private :parent

    #
    # @!endgroup Attributes

    def initialize( parent = nil, &block )
      @parent         = parent
      @dependency_map = Scorpion::DependencyMap.new( self )

      prepare &block if block_given?
    end

    # Prepare the scorpion for hunting.
    # @see DependencyMap#chart
    def prepare( &block )
      dependency_map.chart &block
    end

    # Expose dependency injection definitions as top-level methods.
    [:hunt_for, :capture, :share].each do |delegate|
      define_method delegate do |*args, &block|
        prepare do |hunter|
          hunter.send delegate, *args, &block
        end
      end
    end

    # @see Scorpion#replicate
    def replicate
      replica = self.class.new self
      replica.dependency_map.replicate_from( dependency_map )
      replica
    end

    # @see Scorpion#execute
    def execute( hunt, explicit_only = false )
      dependency   = find_dependency( hunt )
      dependency ||= Dependency.define( hunt.contract ) unless explicit_only

      unsuccessful_hunt( hunt.contract ) unless dependency

      dependency.fetch hunt
    end

    # Find any explicitly defined dependencies that can satisfy the hunt.
    # @param [Hunt] hunt being resolved.
    # @return [Dependency] the matching dependency if found
    def find_dependency( hunt )
      dependency   = dependency_map.find( hunt.contract )
      dependency ||= parent.find_dependency( hunt ) if parent

      dependency
    end

    # @see Scorpion#reset
    def reset
      dependency_map.reset
    end

    # @return [String]
    def inspect
      dependencies = dependency_map.to_a
      result = "<#{ self.class.name } contracts=#{ dependencies.inspect }"
      result << " parent=#{ parent.inspect }" if parent
      result << ">"
      result
    end

  end
end