#--
# Copyright (c) 2009 Sjoerd Andringa
#++

# The MultiMatcher is an abstract Matcher class which supports
# matching of multiple expectations in once.
#
# == Usage
#
# Extend this class with your own Matcher. Use the +expectations+ class method
# to set your expectations and optionally override +failure_message+ and +negative_failure_message+.
#
#   class RequireLogin < MultiMatcher
#     expectations do
#       response.should redirect_to(login_path)
#       flash[:warning].should include('Please log in')
#     end
#     
#     def failure_message
#       "Expected action to require log in. (#{@failure})"
#     end
#   end
#
# +@failure+ is the failure message thrown by your own failing expectations.
# 
# Pass in the spec's context at instantiation:
#
#   def require_login
#     RequireLogin.new(self)
#   end
#
# How to use in you specs:
#
#   lambda do
#     delete :destroy, :id => 1
#   end.should require_login
#
# It always expects a block as its target.
#
class MultiMatcher
  
  def initialize(spec)
    @spec = spec
  end
    
  def matches?(target)
    raise "Provide a block for #{self.class}" unless target.is_a?(Proc)

    begin
      target.call
      @spec.instance_eval(&expectations) if respond_to?(:expectations)
    rescue Spec::Expectations::ExpectationNotMetError => f
      @failure = f.to_s
      return false
    else
      return true
    end
  end
  
  def self.expectations(&block)
    define_method :expectations do
      block
    end
  end
  
  def failure_message
    @failure
  end
  
end
