rspec.should use_a_little_less_magic
January 10th, 2007
Updated on 21 Jan
One of the great things about Ruby is that it allows common folk like you and me to perform all sorts of magic that would dazzle and amaze the more statically typed of our neighbors.
One of the terrible things about Ruby is that, as the secret gets out, the various magic potions we mix begin to conflict with each other, creating the foul stench of bugs that don’t reveal themselves until someone ELSE does some of their own magic.
The most visible conflict has been between RSpec and Ruby on Rails, both of which usurp method_missing to support some devilishly sexy run-time method creation. The problem comes when RoR follows good guidelines like late-binding, and adds its version of method_missing later in the stack than RSpec does, rendering RSpec’s use of method_missing a bit futile, forcing RSpec to monkey patch Rails in order to work.
Well, this conflict may soon see its end.
We’ve just added support for a new way of setting expectations in RSpec that should support all of the existing expectations AND make it very easy to add custom expectations with no method_missing magic or monkey patching. Thanks to Dan North for this )&)(&ing brilliant idea.
Here’s how it looks:
result.should equal(3)
light.should be_red
newspaper.should be_read
rspec.should use_a_little_less_magic
And here’s how simple it is to add a custom expectation:
module HotelExpecations
class BeBookedSolidOn
def initialize(date)
@date = date
end
def matches?(hotel)
hotel.booked_solid_on?(@date)
end
def failure_message
"expected hotel to be booked solid on #{@date}"
end
def negative_failure_message
"expected hotel to not be booked solid on #{@date}"
end
end
def be_booked_solid_on(date)
BeBookedSolidOn.new(date)
end
end
context "Hotel behaviour" do
include HotelExpectations
specify "should be considered booked solid with 100 reservations" do
#given
@hotel = Hotel.new
#when
(1..100).each { @hotel.reserve_room_for(2).on("12/31/2007")
#then
@hotel.should be_booked_solid_on("12/31/2007")
end
specify "should NOT be considered booked solid with 99 reservations" do
#given
@hotel = Hotel.new
#when
(1..99).each { @hotel.reserve_room_for(2).on("12/31/2007")
#then
@hotel.should_not be_booked_solid_on("12/31/2007")
end
end
How easy is that??!
As of this writing, this is only available in the trunk, however it will be quietly released in 0.7.6, and perhaps with a bit more fanfare in 0.8. Those of you who make a habit of using the latest and greatest can do this RIGHT NOW, though beware that until the fanfare is sounded, the details may change a bit.
6 Responses to “rspec.should use_a_little_less_magic”
Sorry, comments are closed for this article.


July 13th, 2008 at 06:06 AM
I’m really pleased to see rspec adopting this convention, but I can’t claim to have originated the idea.
I was first introduced to it by Joe Walnes a couple of years ago and I’ve been using it ever since.
I found it led to much more readable assertions. It’s baked into JBehave as
ensureThat(). Long live convergence!July 13th, 2008 at 06:06 AM
great !—does this mean that the Rails integration with Rspec 0.8 will be much smoother ?
July 13th, 2008 at 06:06 AM
Yes, it should, although the plugin still has a few problems that are going to be a challenge to solve, and they won’t all be solved w/ the 0.8 release.
That said, this will be the last major syntax change for rspec before 1.0, and it will come w/ a translator for people who already use rspec pre-0.8.
July 13th, 2008 at 06:06 AM
I like the idea of modding the syntax to reduce/eliminate usage of method_missing, so that RSpec doesn’t step on other frameworks.
Just a devil’s advocate question here: is there a reason the library isn’t going with dot-notation instead?
the_result.should.equal 5
wouldn’t require all those ((()))s, and we wouldn’t be stuck with that brace vs. do/end priority puzzle.
July 13th, 2008 at 06:06 AM
Devil indeed.
Way back when there was a big dot vs underscore debate and consensus was that underscores were more desirable. What you propose could work, but at this point we’re fairly well committed to the current path (all of the new code is already implemented).
Personally, I prefer it the way it is over all the dots. Here are some examples:
vs
To my eyes, the space w/ parens is easier to read than the dots without parens.
If you feel strongly about it though, now is the time to voice your opinion because once we do this release there is no going back. Do so on the mailing lists though.
Cheers, David
July 13th, 2008 at 06:06 AM
Hi, David.
Thanks for the explanation. I’ll just post a quick response here, ‘cause I don’t think the scope of my answer is substantial enough for the mailing list.
I agree that, in general, underscores are more readable than dots. The question becomes much fuzzier when it’s underscores with parentheses vs. dots without. I actually liked your second example slightly better, but I don’t think my mild preference should be enough to undo all that hard work that’s gone into trunk.