Custom matcher for predicates

I hope this isn’t a dumb question, but can a custom matcher be written
for a possibly non-existant predicate? I know that if the object
responds to some predicate? message, RSpec will breate a custom
matcher on the fly for it. Such as be_naughty or be_nice for
sarah.naughty? and jane.nice?

But what if you want to create your own where this is not the case.
Like sarah.should_not be_on_santas_list:

Spec::Matchers.define :be_on_santas_list do |expected|
matcher do |actual|
$santas_list.include? actual
end
end

Or in the situation where the object has a predicate that returns a
string and not true or false. As is the case with
REXML::Document#stand_alone?:

match do |actual|
actual.stand_alone? == ‘yes’
end

This works, but the value of expected is nil.

Is this Ok? How do others handle this? .

Thanks, and Happy Holidays.
Ed


Ed Howland

http://twitter.com/ed_howland

On Sat, Dec 26, 2009 at 5:53 PM, Ed Howland [email protected]
wrote:

I hope this isn’t a dumb question, but can a custom matcher be written
for a possibly non-existant predicate? I know that if the object
responds to some predicate? message, RSpec will breate a custom
matcher on the fly for it. Such as be_naughty or be_nice for
sarah.naughty? and jane.nice?

It’s not that RSpec looks at your code and creates predicates for it.
When
you say “jane.should be_nice”, RSpec looks to see if jane has a nice?()
method and uses that if it’s there. Subtle, but important difference.

But what if you want to create your own where this is not the case.
Like sarah.should_not be_on_santas_list:

Spec::Matchers.define :be_on_santas_list do |expected|
matcher do |actual|
$santas_list.include? actual
end
end

The block arguments should align with the arguments you pass to the
matcher.
So if you intend to write this in the example:

sarah.should_not be_on_santas_list

Then the definition should be like this:

Spec::Matchers.define :be_on_santas_list do
matcher do |actual|
$santas_list.include? actual
end
end

… with no block arguments.

Or in the situation where the object has a predicate that returns a
string and not true or false. As is the case with
REXML::Document#stand_alone?:

match do |actual|
actual.stand_alone? == ‘yes’
end

This works, but the value of expected is nil.

That’s because you didn’t pass anything to the matcher, as described
above.

The fact that expected is nil at that point should not matter, since
you’re
not evaluating against expected in the match block. As long as as
“actual.stand_alone? == ‘yes’” returns true or false (which it should
unless
you’ve gone and redefined ==) you should be ok.

Is this Ok?

Yes. Why do you ask? What are your concerns? What problems have you had?

How do others handle this? .

Thanks, and Happy Holidays.

And to you.

Cheers,
David

On Sat, Dec 26, 2009 at 6:55 PM, David C.
[email protected]wrote:

you say “jane.should be_nice”, RSpec looks to see if jane has a nice?()
method and uses that if it’s there. Subtle, but important difference.

I should add here, that if you’ve already defined a be_nice method, it
will
be called. RSpec only checks for a predicate when it gets
method_missing,
which it wouldn’t if you’ve defined a method already.

HTH,
David

On Sat, Dec 26, 2009 at 7:56 PM, David C. [email protected]
wrote:

It’s not that RSpec looks at your code and creates predicates for it. When
you say “jane.should be_nice”, RSpec looks to see if jane has a nice?()
method and uses that if it’s there. Subtle, but important difference.

I should add here, that if you’ve already defined a be_nice method, it will
be called. RSpec only checks for a predicate when it gets method_missing,
which it wouldn’t if you’ve defined a method already.
HTH,
David

Thanks, David.

That helps my understanding a lot.

Happy Boxing day, or what’s left of it

Ed


Ed Howland

http://twitter.com/ed_howland