module RSpec::Matchers::DSL::Macros

def assign_attributes(attr_names)

def assign_attributes(attr_names)
  attr_reader(*attr_names)
  private(*attr_names)
  lambda do |*attr_values|
    attr_names.zip(attr_values) do |attr_name, attr_value|
      instance_variable_set(:"@#{attr_name}", attr_value)
    end
  end
end

def chain(method_name, *attr_names, &definition)

expect(minor).to have_errors_on(:age).with("Not old enough to participate")

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

be exposed via getters.
arguments in instance variables with those names, and the values will
attribute names instead of a block; the chained method will store its
value(s) for later use (e.g. in `match`), you can provide one or more
In the common case where you just want the chained method to store some

default description and failure message.
hash been enabled, the chained method name and args will be added to the
`include_chain_clauses_in_custom_matcher_descriptions` config option
for you. If the method is invoked and the
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_name, *attr_names, &definition)
  unless block_given? ^ attr_names.any?
    raise ArgumentError, "You must pass either a block or some attribute names (but not both) to `chain`."
  end
  definition = assign_attributes(attr_names) if attr_names.any?
  define_user_override(method_name, definition) do |*args, &block|
    super(*args, &block)
    @chained_method_clauses.push([method_name, args])
    self
  end
end

def define_user_override(method_name, user_def, &our_def)

can `super` to the user's definition.
(e.g. assigning `@actual`, rescueing errors, etc) and
an override that can provide the wrapped handling
(e.g. for an early guard statement), while allowing us to define
them to use normal method constructs like `return`
This compiles the user block into an actual method, allowing

as an arg, but only if their block's arity can handle it.
of needing to call the user's definition with `@actual`
- Provides a default `our_def` block for the common case
usign the provided `our_def` block.
- Defines an overridden definition for the same method
in the singleton class in which we eval the `define` block.
in @user_method_defs, which is included as an ancestor
- Defines the named method using a user-provided block

Does the following:
def define_user_override(method_name, user_def, &our_def)
  @user_method_defs.__send__(:define_method, method_name, &user_def)
  our_def ||= lambda { super(*actual_arg_for(user_def)) }
  define_method(method_name, &our_def)
end

def description(&definition)

Other tags:
    Yield: - actual the actual object (i.e. the value wrapped by `expect`)
def description(&definition)
  define_user_override(__method__, definition)
end

def diffable

message.
Tells the matcher to diff the actual and expected values in the failure
def diffable
  define_method(:diffable?) { true }
end

def failure_message(&definition)

Other tags:
    Yield: - actual the actual object (i.e. the value wrapped by `expect`)
def failure_message(&definition)
  define_user_override(__method__, definition)
end

def failure_message_when_negated(&definition)

Other tags:
    Yield: - actual the actual object (i.e. the value wrapped by `expect`)
def failure_message_when_negated(&definition)
  define_user_override(__method__, definition)
end

def match(options={}, &match_block)

Other tags:
    Yield: - actual the actual value (i.e. the value wrapped by `expect`)

Parameters:
  • options (Hash) -- for defining the behavior of the match block.
def match(options={}, &match_block)
  define_user_override(:matches?, match_block) do |actual|
    @actual = actual
    RSpec::Support.with_failure_notifier(RAISE_NOTIFIER) do
      begin
        super(*actual_arg_for(match_block))
      rescue RSpec::Expectations::ExpectationNotMetError
        raise if options[:notify_expectation_failures]
        false
      end
    end
  end
end

def match_unless_raises(expected_exception=Exception, &match_block)

Other tags:
    Yield: - actual the actual object (i.e. the value wrapped by `expect`)
def match_unless_raises(expected_exception=Exception, &match_block)
  define_user_override(:matches?, match_block) do |actual|
    @actual = actual
    begin
      super(*actual_arg_for(match_block))
    rescue expected_exception => @rescued_exception
      false
    else
      true
    end
  end
end

def match_when_negated(options={}, &match_block)

Other tags:
    Yield: - actual the actual value (i.e. the value wrapped by `expect`)

Parameters:
  • options (Hash) -- for defining the behavior of the match block.
def match_when_negated(options={}, &match_block)
  define_user_override(:does_not_match?, match_block) do |actual|
    begin
      @actual = actual
      RSpec::Support.with_failure_notifier(RAISE_NOTIFIER) do
        super(*actual_arg_for(match_block))
      end
    rescue RSpec::Expectations::ExpectationNotMetError
      raise if options[:notify_expectation_failures]
      false
    end
  end
end

def supports_block_expectations

(e.g. `expect { do_something }.to matcher`).
expectation without declaring this.
Users will not be able to use your matcher in a block
Declares that the matcher can be used in a block expectation.
def supports_block_expectations
  define_method(:supports_block_expectations?) { true }
end