class RSpec::Matchers::DSL::Matcher
will be evaluated.
Provides the context in which the block passed to RSpec::Matchers.define
def add_deprecation_warning_to(method_name, msg, replacement, extra_call_site_msg, condition)
def add_deprecation_warning_to(method_name, msg, replacement, extra_call_site_msg, condition) return if @deprecated_methods.include?(method_name) @deprecated_methods << method_name aliased_name = aliased_name_for(method_name) singleton_class.__send__(:alias_method, aliased_name, method_name) singleton_class.class_eval(<<-EOS, __FILE__, __LINE__ + 1) def #{method_name}(*a, &b) ::RSpec.deprecate(#{msg.inspect}, :replacement => #{replacement.inspect}, :call_site => CallerFilter.first_non_rspec_line + " and #{extra_call_site_msg} at #{CallerFilter.first_non_rspec_line}" ) #{condition} @define_block_executed __send__(#{aliased_name.inspect}, *a, &b) end EOS end
def aliased_name_for(method_name)
def aliased_name_for(method_name) target, punctuation = method_name.to_s.sub(/([?!=])$/, ''), $1 "#{target}_without_rspec_deprecation_warning#{punctuation}" end
def cache(key, &block)
def cache(key, &block) @messages[key] = block end
def cache_or_call_cached(key, &block)
def cache_or_call_cached(key, &block) block ? cache(key, &block) : call_cached(key) end
def call_cached(key)
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
def chain(method, &block)
end
end
actual.errors[key] == @message
match do |actual|
end
@message = message
chain :with do |message|
RSpec::Matchers.define :have_errors_on do |key|
@example
for you.
return self in order to chain methods together. `chain` handles that
interface. The trick about fluent interfaces is that each method must
Convenience for defining methods on this matcher to create a fluent
def chain(method, &block) define_method method do |*args| block.call(*args) self end end
def default_description
def default_description "#{name_to_sentence}#{to_sentence expected_as_array}" end
def default_failure_message_for_should
def default_failure_message_for_should "expected #{actual.inspect} to #{name_to_sentence}#{to_sentence expected_as_array}" end
def default_failure_message_for_should_not
def default_failure_message_for_should_not "expected #{actual.inspect} not to #{name_to_sentence}#{to_sentence expected_as_array}" end
def define_method(name, &block)
def define_method(name, &block) singleton_class.__send__(:define_method, name, &block) end
def description(&block)
end
"qualify for #{expected}"
description do
match { ... }
RSpec::Matchers.define :qualify_for do |expected|
@example
the description generated by default doesn't suit your needs.
Customize the description to use for one-liners. Only use this when
def description(&block) cache_or_call_cached(:description, &block) end
def diffable
Tells the matcher to diff the actual and expected values in the failure
def diffable @diffable = true end
def diffable?
- Api: - private
def diffable? @diffable end
def does_not_match?(actual)
- Api: - private
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
def expected
def expected if @expected.size == 1 RSpec.warn_deprecation( "Custom matchers in 3.x will set expected to be a single value "+ "(when provided as such) rather than an array. This may change "+ "the behaviour of your matcher.\n"+ "To continue to access this as an array use `expected_as_array`\n"+ "Called from: #{ RSpec::CallerFilter.first_non_rspec_line }\n\n" ) end @expected end
def expected_as_array
def expected_as_array @expected end
def extend(*modules)
def extend(*modules) return_value = super modules.each do |mod| mod.instance_methods.each do |name| add_deprecation_warning_to(name, "Calling a helper method (`#{name}`) from a module extended onto a custom matcher", "`include #{mod.name || "TheModule"}`", "extended onto the custom matcher", :if ) end end unless @define_block_executed return_value end
def failure_message_for_should(&block)
- Yield: - actual the actual object
def failure_message_for_should(&block) cache_or_call_cached(:failure_message_for_should, &block) end
def failure_message_for_should_not(&block)
- Yield: - actual the actual object
Yield: - actual the actual object
def failure_message_for_should_not(&block) cache_or_call_cached(:failure_message_for_should_not, &block) end
def for_expected(*expected)
- Api: - private
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 = {} @deprecated_methods = Set.new @block_method_differentiator = DifferentiateBlockMethodTypes.new(*@expected, &@declarations) making_declared_methods_public do instance_eval_with_args(*@expected, &@declarations) end @define_block_executed = true self end end
def include(*modules)
def include(*modules) return_value = singleton_class.__send__(:include, *modules) modules.each do |mod| mod.instance_methods.each do |name| add_deprecation_warning_to(name, "Calling a helper method (`#{name}`) from a module included in a custom matcher as a macro", "`extend #{mod.name || "TheModule"}`", "included in the custom matcher", :unless ) end end return_value end
def initialize(name, &declarations)
- Api: - private
def initialize(name, &declarations) @name = name @declarations = declarations @actual = nil @diffable = false @supports_block_expectations = false @expected_exception, @rescued_exception = nil, nil @match_for_should_not_block = nil @messages = {} @define_block_executed = false @block_method_differentiator = nil @deprecated_methods = Set.new @matcher_execution_context = nil end
def making_declared_methods_public
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
def match(&block)
- Yield: - actual the actual value (or receiver of should)
def match(&block) @match_block = block end
def match_for_should_not(&block)
- Yield: - actual the actual value (or receiver of should)
def match_for_should_not(&block) @match_for_should_not_block = block end
def match_unless_raises(exception=Exception, &block)
end
end
validator.validate(candidate_address)
match_unless_raises ValidationException do |validator|
RSpec::Matchers.define :accept_as_valid do |candidate_address|
@example
rather than returning false to indicate a failure.
Use this instead of `match` when the block will raise an exception
def match_unless_raises(exception=Exception, &block) @expected_exception = exception match(&block) end
def matcher_execution_context
def matcher_execution_context RSpec.deprecate("`matcher_execution_context` on custom matchers") @matcher_execution_context end
def matcher_execution_context=(value)
def matcher_execution_context=(value) RSpec.deprecate("`matcher_execution_context=` on custom matchers") @matcher_execution_context = value end
def matches?(actual)
- Api: - private
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
def method_missing(method, *args, &block)
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
def respond_to?(method, include_private=false)
def respond_to?(method, include_private=false) super || @matcher_execution_context.respond_to?(method, include_private) end
def singleton_class
def singleton_class class << self; self; end end
def singleton_method_added(name)
def singleton_method_added(name) return unless @block_method_differentiator if @block_method_differentiator.instance_methods.include?(name) add_deprecation_warning_to(name, "Calling a helper method (`#{name}`) defined as an instance method (using `def #{name}`) as a macro from a custom matcher `define` block", "`def self.#{name}` (to define it as a singleton method)", "defined in the custom matcher definition block", :unless ) elsif @block_method_differentiator.singleton_methods.include?(name) add_deprecation_warning_to(name, "Calling a helper method (`#{name}`) defined as a singleton method (using `def self.#{name}`) on a custom matcher", "`def #{name}` (to define it as an instance method)", "defined in the custom matcher definition block", :if ) end end
def supports_block_expectations
def supports_block_expectations @supports_block_expectations = true end
def supports_block_expectations?
- Api: - private
def supports_block_expectations? @supports_block_expectations end