ArticleS. DavidChelimsky.
BowlingWithRspec [add child]

Bowling with rSpec


Now THIS is fun. Here's the bowling game test driven in Ruby with the new rspec (v0.5).
 Spec using v0.5
NOTE - updated on 4/15/2006 - see "Spec using v0.4" for the original post

require 'spec'

context "A bowling score calculator" do

setup do
@game = Game.new
end

specify "should score 0 for an all gutter game" do
(1..20).each { @game.roll(0) }
@game.score.should.be 0
end

specify "should score 20 for an all ones game" do
(1..20).each { @game.roll(1) }
@game.score.should.be 20
end

specify "should score 150 for an all fives game" do
(1..21).each { @game.roll(5) }
@game.score.should.be 150
end

specify "should score 300 for a perfect game" do
(1..12).each { @game.roll(10) }
@game.score.should.be 300
end

end
 Spec using v0.4
 Solution
!commentForm
 Fri, 3 Mar 2006 16:27:14, Dave Astels, A recursive solution
When David showed me this, I immediately thought "A recursive solution would probably be cleaner and more understandable". So here it is.
require 'spec'

class GameSpec < Spec::Context

def setup
@game = Game.new
end

def gutter_game_score_should_be_zero
(1..20).each { @game.roll(0) }
@game.score.should.be 0
end

def all_ones_game_score_should_be_20
(1..20).each { @game.roll(1) }
@game.score.should.be 20
end

def all_fives_game_score_should_be_150
(1..21).each { @game.roll(5) }
@game.score.should.be 150
end

def perfect_game_score_should_be_300
(1..12).each { @game.roll(10) }
@game.score.should.be 300
end

end

class Game

def initialize
@rolls = []
end

def roll(pins)
@rolls.push pins
end

def score
compute_score(1, @rolls)
end

def compute_score(frame, rolls)
return 0 if frame > 10
return do_strike(frame, rolls) if strike?(rolls)
return do_spare(frame, rolls) if spare?(rolls)
return do_regular_frame(frame, rolls)
end

def strike?(rolls)
rolls[0] == 10
end

def spare?(rolls)
rolls[0] + rolls[1] == 10
end

def do_strike(frame, rolls)
10 + rolls[1] + rolls[2] + compute_score(frame + 1, rolls[1..-1])
end

def do_spare(frame, rolls)
10 + rolls[2] + compute_score(frame + 1, rolls[2..-1])
end

def do_regular_frame(frame, rolls)
rolls[0] + rolls[1] + compute_score(frame + 1, rolls[2..-1])
end

end
 Sat, 4 Mar 2006 18:02:18, Craig Demyanovich, Thanks and using require
First, thanks to the two of you for your work on this latest version of RSpec. Second, thanks for this example. I tried the bowling game in Ruby with Test::Unit some time ago. I'll compare what I did then with the examples here and see where it leads me.

Notice that David uses

require 'rubygems'
require_gem 'rspec'

while Dave uses

require 'spec'

In my previous experimentation with RSpec and another library available as a gem, I had to use require as David did, even though the example code showed the form that Dave uses. This is true with RSpec v. 0.4.0 for me. I installed it as a gem; I'm using Mac OS X 10.4.5 and Ruby 1.8.4 from DarwinPorts[?]. Any ideas why I can't just do

require 'spec'

instead of

require 'rubygems'
require_gem 'rspec'
 Sun, 5 Mar 2006 15:30:52, Dave Astels, require 'rubygems'
you can avoid having to explicitly require rubygems by putting this in your env var setup:

RUBYOPT=rubygems

It doesn't seem to be ideal, though... but it does work.

IMHO gems is a package & deployment approach... libraries shouldn't depend on it.

Dave
 Wed, 22 Mar 2006 18:25:59, Micah Martin, Man, that's small!
The amount of code I mean. Ruby rocks!
 Sat, 15 Apr 2006 10:10:54, Aslak Hellesoy, Update the example - the syntax has changed!
We've got a new syntax for specs now. Take a peek at the examples over at http://rspec.rubyforge.org/

Aslak