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
Public Class Methods
@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
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
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
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
@api private Used internally by objects returns by should
and should_not
.
# File lib/rspec/matchers/matcher.rb, line 213 def diffable? @diffable end
@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
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
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
@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
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
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
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
@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
# 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
# File lib/rspec/matchers/matcher.rb, line 268 def cache(key, &block) @messages[key] = block end
# File lib/rspec/matchers/matcher.rb, line 264 def cache_or_call_cached(key, &block) block ? cache(key, &block) : call_cached(key) end
# 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
# File lib/rspec/matchers/matcher.rb, line 280 def default_description "#{name_to_sentence}#{expected_to_sentence}" end
# 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
# 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
# File lib/rspec/matchers/matcher.rb, line 244 def define_method(name, &block) singleton_class.__send__(:define_method, name, &block) end
# File lib/rspec/matchers/matcher.rb, line 240 def include(*args) singleton_class.__send__(:include, *args) end
# 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
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
# File lib/rspec/matchers/matcher.rb, line 293 def singleton_class class << self; self; end end