[rspec-devel] slightly-less-simple-matcher [was: crazy semantic question]

David Chelimsky dchelimsky at gmail.com
Sun Jun 22 19:31:53 EDT 2008


The ??? of the expression "x should y" is positive.
The ??? of the expression "x should not y" is negative.

So we've got:

sense
outcome
consequence
mood
feeling
aura
timbre
(un)likeliness
(un)likelihood

Let me provide a bit more context. RSpec matchers don't know whether  
they're being called with should or should_not. I'm toying with adding  
that capability such that if the matcher will accept a 2nd argument to  
the matches? method it will be given a hash. Then you can do this:

def matches?(given, options, &block)
   if options[:should_ness] == :positive
     # handle the 'should' case
   else
     # handle the 'should_not' case
   end
end

Although, now that I'm looking at it, it could just be:

def matches?(given, options, &block)
   if options[:called_with] == :should
     # handle the 'should' case
   else
     # handle the 'should_not' case
   end
end

Maybe that solves the problem? Thoughts?

For those interested, this stems from some evolution of the  
simple_matcher method. Right now (in git) you can do this:

def report_to(manager)
   simple_matcher do |employee, matcher|
     matcher.failure_message = "expected #{employee} to report to  
#{manager}"
     employee.reports_to?(manager)
   end
end

Some have expressed a desire to make these more like expectation  
wrappers, where you can put a couple of logical expectations together.  
The example above uses a boolean expression. But what if you wanted to  
do this?

def report_to(manager)
   simple_matcher do |employee, matcher|
     matcher.failure_message = "expected #{employee} to report to  
#{manager} and #{manager} not to report to #{employee}"
     employee.reports_to?(manager).should be_true
     manager.reports_to?(employee).should be_false
   end
end

This actually works ... as long as you only call it with should. If  
you use should_not, you'll get the wrong response, whereas the  
original boolean expression would work fine.

To be able to support this, the matcher *could* be written like this:

def report_to(manager)
   simple_matcher do |employee, matcher|
     if matcher.called_with_should?
       matcher.failure_message = "expected #{employee} to report to  
#{manager}"
       employee.reports_to?(manager).should be_true
       manager.reports_to?(employee).should be_false
     else
       matcher.failure_message = "expected #{employee} to report to  
#{manager} and #{manager} not to report to #{employee}"
       employee.reports_to?(manager).should be_false
     end
   end
end

Now you have a custom matcher that can handle should and should_not  
cases with the appropriate expectations and semantics for each. A bit  
more complex than maybe a simple matcher should be :) And certainly  
not necessary for you to use this way - just available.

Any feedback on this is welcome.

Cheers,
David



More information about the rspec-devel mailing list