Flowdock
simple_matcher(description=nil, &match_block) public

simple_matcher makes it easy for you to create your own custom matchers in just a few lines of code when you don’t need all the power of a completely custom matcher object.

The description argument will appear as part of any failure message, and is also the source for auto-generated descriptions.

The match_block can have an arity of 1 or 2. The first block argument will be the given value. The second, if the block accepts it will be the matcher itself, giving you access to set custom failure messages in favor of the defaults.

The match_block should return a boolean: true indicates a match, which will pass if you use should and fail if you use should_not. false (or nil) indicates no match, which will do the reverse: fail if you use should and pass if you use should_not.

An error in the match_block will bubble up, resulting in a failure.

Example with default messages

  def be_even
    simple_matcher("an even number") { |given| given % 2 == 0 }
  end

  describe 2 do
    it "should be even" do
      2.should be_even
    end
  end

Given an odd number, this example would produce an error message stating: expected "an even number", got 3.

Unfortunately, if you’re a fan of auto-generated descriptions, this will produce "should an even number." Not the most desirable result. You can control that using custom messages:

Example with custom messages

  def rhyme_with(expected)
    simple_matcher("rhyme with #{expected.inspect}") do |given, matcher|
      matcher.failure_message = "expected #{given.inspect} to rhyme with #{expected.inspect}"
      matcher.negative_failure_message = "expected #{given.inspect} not to rhyme with #{expected.inspect}"
      given.rhymes_with? expected
    end
  end

  # OR

  def rhyme_with(expected)
    simple_matcher do |given, matcher|
      matcher.description = "rhyme with #{expected.inspect}"
      matcher.failure_message = "expected #{given.inspect} to rhyme with #{expected.inspect}"
      matcher.negative_failure_message = "expected #{given.inspect} not to rhyme with #{expected.inspect}"
      given.rhymes_with? expected
    end
  end

  describe "pecan" do
    it "should rhyme with 'be gone'" do
      nut = "pecan"
      nut.extend Rhymer
      nut.should rhyme_with("be gone")
    end
  end

The resulting messages would be:

  description:              rhyme with "be gone"
  failure_message:          expected "pecan" to rhyme with "be gone"
  negative failure_message: expected "pecan" not to rhyme with "be gone"

Wrapped Expectations

Because errors will bubble up, it is possible to wrap other expectations in a SimpleMatcher.

  def be_even
    simple_matcher("an even number") { |given| (given % 2).should == 0 }
  end

BE VERY CAREFUL when you do this. Only use wrapped expectations for matchers that will always be used in only the positive (should) or negative (should_not), but not both. The reason is that is you wrap a should and call the wrapper with should_not, the correct result (the should failing), will fail when you want it to pass.

Show source
Register or log in to add new notes.
September 27, 2008
3 thanks

Example using simple_matcher

This is extracted from: http://blog.davidchelimsky.net/2008/6/7/thoughts-on-the-dance-off

Here’s an example:

def be_sorted
  simple_matcher("a sorted list") {|actual| actual.sort == actual}
end
[1,2,3].should be_sorted

The block is handed the actual value. If the block returns true, the expectation passes. If it returns false, it fails with the following message:

expected “a sorted list” but got [1, 3, 2]

If you say [1,2,3].should_not be_sorted you’d get this message instead=:

expected not to get “a sorted list”, but got [1, 2, 3]

As of now, you don’t get any control over the failure message other than the string you pass to the simple_matcher method