class RSpec::Matchers::DSL::Matcher

Provides the context in which the block passed to RSpec::Matchers.define will be evaluated.

Constants

PERSISTENT_INSTANCE_VARIABLES

Attributes

actual[R]
expected[R]
matcher_execution_context[RW]
rescued_exception[R]

Public Class Methods

new(name, &declarations) click to toggle source

@api private

# File lib/rspec/matchers/matcher.rb, line 17
def initialize(name, &declarations)
  @name         = name
  @declarations = declarations
  @actual       = nil
  @diffable     = false
  @expected_exception, @rescued_exception = nil, nil
  @match_for_should_not_block = nil
  @messages = {}
end

Public Instance Methods

chain(method, &block) click to toggle source

Convenience for defining methods on this matcher to create a fluent interface. The trick about fluent interfaces is that each method must return self in order to chain methods together. `chain` handles that for you.

@example

RSpec::Matchers.define :have_errors_on do |key|
  chain :with do |message|
    @message = message
  end

  match do |actual|
    actual.errors[key] == @message
  end
end

minor.should have_errors_on(:age).with("Not old enough to participate")
# File lib/rspec/matchers/matcher.rb, line 204
def chain(method, &block)
  define_method method do |*args|
    block.call(*args)
    self
  end
end
description(&block) click to toggle source

Customize the description to use for one-liners. Only use this when the description generated by default doesn't suit your needs.

@example

RSpec::Matchers.define :qualify_for do |expected|
  match { ... }

  description do
    "qualify for #{expected}"
  end
end
# File lib/rspec/matchers/matcher.rb, line 176
def description(&block)
  cache_or_call_cached(:description, &block)
end
diffable() click to toggle source

Tells the matcher to diff the actual and expected values in the failure message.

# File lib/rspec/matchers/matcher.rb, line 182
def diffable
  @diffable = true
end
diffable?() click to toggle source

@api private Used internally by objects returns by should and should_not.

# File lib/rspec/matchers/matcher.rb, line 213
def diffable?
  @diffable
end
does_not_match?(actual) click to toggle source

@api private Used internally by should_not

# File lib/rspec/matchers/matcher.rb, line 219
def does_not_match?(actual)
  @actual = actual
  @match_for_should_not_block ?
    instance_eval_with_args(actual, &@match_for_should_not_block) :
    !matches?(actual)
end
failure_message_for_should(&block) click to toggle source

Customize the failure messsage to use when this matcher is invoked with `should`. Only use this when the message generated by default doesn't suit your needs.

@example

RSpec::Matchers.define :have_strength do |expected|
  match { ... }

  failure_message_for_should do |actual|
    "Expected strength of #{expected}, but had #{actual.strength}"
  end
end

@yield [Object] actual the actual object

# File lib/rspec/matchers/matcher.rb, line 139
def failure_message_for_should(&block)
  cache_or_call_cached(:failure_message_for_should, &block)
end
failure_message_for_should_not(&block) click to toggle source

Customize the failure messsage to use when this matcher is invoked with `should_not`. Only use this when the message generated by default doesn't suit your needs.

@example

RSpec::Matchers.define :have_strength do |expected|
  match { ... }

  failure_message_for_should_not do |actual|
    "Expected not to have strength of #{expected}, but did"
  end
end

@yield [Object] actual the actual object @yield [Object] actual the actual object

# File lib/rspec/matchers/matcher.rb, line 159
def failure_message_for_should_not(&block)
  cache_or_call_cached(:failure_message_for_should_not, &block)
end
for_expected(*expected) click to toggle source

@api private

# File lib/rspec/matchers/matcher.rb, line 34
def for_expected(*expected)
  @expected = expected
  dup.instance_eval do
    instance_variables.map {|ivar| ivar.intern}.each do |ivar|
      instance_variable_set(ivar, nil) unless (PERSISTENT_INSTANCE_VARIABLES + [:@expected]).include?(ivar)
    end
    @messages = {}
    making_declared_methods_public do
      instance_eval_with_args(*@expected, &@declarations)
    end
    self
  end
end
match(&block) click to toggle source

Stores the block that is used to determine whether this matcher passes or fails. The block should return a boolean value. When the matcher is passed to `should` and the block returns `true`, then the expectation passes. Similarly, when the matcher is passed to `should_not` and the block returns `false`, then the expectation passes.

Use `match_for_should` when used in conjuntion with `match_for_should_not`.

@example

RSpec::Matchers.define :be_even do
  match do |actual|
    actual.even?
  end
end

4.should be_even     # passes
3.should_not be_even # passes
3.should be_even     # fails
4.should_not be_even # fails

@yield [Object] actual the actual value (or receiver of should)

# File lib/rspec/matchers/matcher.rb, line 91
def match(&block)
  @match_block = block
end
Also aliased as: match_for_should
match_for_should(&block)
Alias for: match
match_for_should_not(&block) click to toggle source

Use this to define the block for a negative expectation (`should_not`) when the positive and negative forms require different handling. This is rarely necessary, but can be helpful, for example, when specifying asynchronous processes that require different timeouts.

@yield [Object] actual the actual value (or receiver of should)

# File lib/rspec/matchers/matcher.rb, line 103
def match_for_should_not(&block)
  @match_for_should_not_block = block
end
match_unless_raises(exception=Exception, &block) click to toggle source

Use this instead of `match` when the block will raise an exception rather than returning false to indicate a failure.

@example

RSpec::Matchers.define :accept_as_valid do |candidate_address|
  match_unless_raises ValidationException do |validator|
    validator.validate(candidate_address)
  end
end

email_validator.should accept_as_valid("person@company.com")
# File lib/rspec/matchers/matcher.rb, line 119
def match_unless_raises(exception=Exception, &block)
  @expected_exception = exception
  match(&block)
end
matches?(actual) click to toggle source

@api private Used internally by should and should_not.

# File lib/rspec/matchers/matcher.rb, line 50
def matches?(actual)
  @actual = actual
  if @expected_exception
    begin
      instance_eval_with_args(actual, &@match_block)
      true
    rescue @expected_exception => @rescued_exception
      false
    end
  else
    begin
      instance_eval_with_args(actual, &@match_block)
    rescue RSpec::Expectations::ExpectationNotMetError
      false
    end
  end
end
respond_to?(method, include_private=false) click to toggle source
Calls superclass method
# File lib/rspec/matchers/matcher.rb, line 226
def respond_to?(method, include_private=false)
  super || matcher_execution_context.respond_to?(method, include_private)
end

Private Instance Methods

cache(key, &block) click to toggle source
# File lib/rspec/matchers/matcher.rb, line 268
def cache(key, &block)
  @messages[key] = block
end
cache_or_call_cached(key, &block) click to toggle source
# File lib/rspec/matchers/matcher.rb, line 264
def cache_or_call_cached(key, &block)
  block ? cache(key, &block) : call_cached(key)
end
call_cached(key) click to toggle source
# File lib/rspec/matchers/matcher.rb, line 272
def call_cached(key)
  if @messages.has_key?(key)
    @messages[key].arity == 1 ? @messages[key].call(@actual) : @messages[key].call
  else
    __send__("default_#{key}")
  end
end
default_description() click to toggle source
# File lib/rspec/matchers/matcher.rb, line 280
def default_description
  "#{name_to_sentence}#{expected_to_sentence}"
end
default_failure_message_for_should() click to toggle source
# File lib/rspec/matchers/matcher.rb, line 284
def default_failure_message_for_should
  "expected #{actual.inspect} to #{name_to_sentence}#{expected_to_sentence}"
end
default_failure_message_for_should_not() click to toggle source
# File lib/rspec/matchers/matcher.rb, line 288
def default_failure_message_for_should_not
  "expected #{actual.inspect} not to #{name_to_sentence}#{expected_to_sentence}"
end
define_method(name, &block) click to toggle source
# File lib/rspec/matchers/matcher.rb, line 244
def define_method(name, &block)
  singleton_class.__send__(:define_method, name, &block)
end
include(*args) click to toggle source
# File lib/rspec/matchers/matcher.rb, line 240
def include(*args)
  singleton_class.__send__(:include, *args)
end
making_declared_methods_public() { || ... } click to toggle source
# File lib/rspec/matchers/matcher.rb, line 248
def making_declared_methods_public
  # Our home-grown instance_exec in ruby 1.8.6 results in any methods
  # declared in the block eval'd by instance_exec in the block to which we
  # are yielding here are scoped private. This is NOT the case for Ruby
  # 1.8.7 or 1.9.
  #
  # Also, due some crazy scoping that I don't understand, these methods
  # are actually available in the specs (something about the matcher being
  # defined in the scope of RSpec::Matchers or within an example), so not
  # doing the following will not cause specs to fail, but they *will*
  # cause features to fail and that will make users unhappy. So don't.
  orig_private_methods = private_methods
  yield
  (private_methods - orig_private_methods).each {|m| singleton_class.__send__ :public, m}
end
method_missing(method, *args, &block) click to toggle source
Calls superclass method RSpec::Matchers#method_missing
# File lib/rspec/matchers/matcher.rb, line 232
def method_missing(method, *args, &block)
  if matcher_execution_context.respond_to?(method)
    matcher_execution_context.__send__ method, *args, &block
  else
    super(method, *args, &block)
  end
end
singleton_class() click to toggle source
# File lib/rspec/matchers/matcher.rb, line 293
def singleton_class
  class << self; self; end
end