module RSpec module Matchers module BuiltIn # @api private # # Used _internally_ as a base class for matchers that ship with # rspec-expectations and rspec-rails. # # ### Warning: # # This class is for internal use, and subject to change without notice. We # strongly recommend that you do not base your custom matchers on this # class. If/when this changes, we will announce it and remove this warning. class BaseMatcher include RSpec::Matchers::Pretty include RSpec::Matchers::Composable # @api private # Used to detect when no arg is passed to `initialize`. # `nil` cannot be used because it's a valid value to pass. UNDEFINED = Object.new.freeze # @private attr_reader :actual, :expected, :rescued_exception def initialize(expected=UNDEFINED) @expected = expected unless UNDEFINED.equal?(expected) end # @api private # Indicates if the match is successful. Delegates to `match`, which # should be defined on a subclass. Takes care of consistently # initializing the `actual` attribute. def matches?(actual) @actual = actual match(expected, actual) end # @api private # Used to wrap a block of code that will indicate failure by # raising one of the named exceptions. # # This is used by rspec-rails for some of its matchers that # wrap rails' assertions. def match_unless_raises(*exceptions) exceptions.unshift Exception if exceptions.empty? begin yield true rescue *exceptions => @rescued_exception false end end # @api private # Generates a "pretty" description using the logic in {Pretty}. # @return [String] def description return name_to_sentence unless defined?(@expected) "#{name_to_sentence}#{to_sentence @expected}" end # @api private # Matchers are not diffable by default. Override this to make your # subclass diffable. def diffable? false end # @api private # Most matchers are value matchers (i.e. meant to work with `expect(value)`) # rather than block matchers (i.e. meant to work with `expect { }`), so # this defaults to false. Block matchers must override this to return true. def supports_block_expectations? false end # @api private def expects_call_stack_jump? false end private def assert_ivars(*expected_ivars) return unless (expected_ivars - present_ivars).any? raise "#{self.class.name} needs to supply#{to_sentence expected_ivars}" end if RUBY_VERSION.to_f < 1.9 def present_ivars instance_variables.map { |v| v.to_sym } end else alias present_ivars instance_variables end # @api private # Provides default implementations of failure messages, based on the `description`. module DefaultFailureMessages # @api private # Provides a good generic failure message. Based on `description`. # When subclassing, if you are not satisfied with this failure message # you often only need to override `description`. # @return [String] def failure_message "expected #{actual.inspect} to #{description}" end # @api private # Provides a good generic negative failure message. Based on `description`. # When subclassing, if you are not satisfied with this failure message # you often only need to override `description`. # @return [String] def failure_message_when_negated "expected #{actual.inspect} not to #{description}" end # @private def self.has_default_failure_messages?(matcher) matcher.method(:failure_message).owner == self && matcher.method(:failure_message_when_negated).owner == self rescue NameError false end end include DefaultFailureMessages end end end end