[rspec-users] syntax for custom messages

David Chelimsky
Mon, 05 Mar 2012 14:10:01 -0000

On Mon, Mar 5, 2012 at 2:18 AM, ruud144 <r.grosmann at gmail.com>
wrote:
> hi group,
>
> I read that expectations can print a custom message on failure using a
> syntax like
>
> cars.should be_empty, "Cars left"
>
> But when I try this syntax for this expectation:
>
> string.should == ''Cars left'', ''Yippee, no cars
anymore''
>
> I get a syntax error:
>
> syntax error, unexpected '','', expecting keyword_end
(SyntaxError)
>
> I want two things:
> - I want a syntax error free expectation for should =
Can''t have it because Ruby won''t parse it. The reason
`a.should == b`
works is because Ruby parses that as `a.should.==(b)`.

There is an `eq` matcher, which is the recommended approach these days
for this (and other similar) reason(s):

string.should eq(''Cars left''), ''Yippee, no cars
anymore''

> - I want to understand what the mechanism is. I am afraid that my ruby
> knowledge is not sufficient. Clearly, should is a function, but what
> are be_empty and == then? Parameters? Can I use parentheses?

Here are the bits of code relevant to your question:

https://github.com/rspec/rspec-expectations/blob/master/lib/rspec/expectations/extensions/kernel.rb#L11-13

https://github.com/rspec/rspec-expectations/blob/master/lib/rspec/expectations/handler.rb#L4-7

The `should` method delegates to `handle_matcher`, passing along the
matcher (which might be nil), optional message (also might be nil),
and optional block (again, might be nil).

When you use `a.should == b`, the matcher itself is nil, and the
`handle_matcher` method delegates to a `PositiveOperatorMatcher`
(there is also a `NegativeOperatorMatcher` for `should_not`),
otherwise it handles the matcher itself.

Parens won''t help you here because everything after `==` is bound to
`==`, not should - there''s no way (that I know of) to bind the message
to `should`. It''s feasible to pass an array to `==`:

  string.should == [''Cars left'', ''Yippee, no cars
anymore'']

... but then we''d be comparing `string` with the list, so that
wouldn''t work either (nor would it make any sense).

Your best bet is using the `eq` matcher, as described above.

HTH,
David

>
> Thanks for helping me!
>
> Ruud