Sep 22 2009

Bowling Kata with Ruby and RSpec

Category: bdd,ruby,Uncategorizedgiordano scalzo @ 8:59 pm

Looking around in daily feeds reading, suddenly I realized I never practiced the first code kata: that Bowling Kata that started all.
I decided to implement it while exploring RSpec and configuring my Ruby environment for Windows:
I used to do my programming under friendly Ubuntu, but because my recent jobs duties in Delphi, mainly I use a Windows Xp system.

Installing Ruby is straightforward thanks to RubyInstaller, a wonderful project that let you configure a Ruby environment under Windows; to dive into a complete Bdd flow I configured autospec and Growl following this useful post: I advice every Bdd practitioner to give autospec a try, it can save a lot of windows and mental switch… but it can’t be told, try it and enjoy it.

While I’m very happy with Eclipse during Java coding, I never found a satisfactory editor for Ruby code.
So I decided to try to enter in guru world and use Vim, adding a bunch of useful plugin, as the wondeful snipMate that import the Textmate snippets under Vim.

Back to kata, these are my specs:

require File.join(File.dirname(__FILE__), "//spec_helper")

describe Bowling do

	before(:each) do
		@game = Bowling.new
	end

	def roll_many(num, pins)
		num.times do |hit|
			@game.hit(pins)
		end
	end

	it "should score 0 for gutter game" do
		roll_many(20, 0)
		@game.score.should == 0
	end

	it "should score 20 for a pin each frame" do
		roll_many(20, 1)
		@game.score.should == 20
	end

	def roll_spare()
		@game.hit(5)
		@game.hit(5)
	end

	it "should score 20 when make a spare and 3 and 4 after " do
		roll_spare
		@game.hit(3)
		@game.hit(4)
		roll_many(16, 0)
		@game.score.should == 20
	end

	def roll_strike()
		@game.hit(10)
	end

	it "should score 24 when make a strike and 3 and 4 after " do
		roll_strike
		@game.hit(3)
		@game.hit(4)
		roll_many(16, 0)
		@game.score.should == 24
	end
end

They are virtually identical to UncleBob’s ones.

And this is my code:

class Bowling
	private
	class Frame
		def initialize
			@rolls = []
			@rolls[0] = @rolls[1] = 0
			@index = 0
		end

		def sum
			@rolls[0]+@rolls[1]
		end

		def strike?
			@rolls[0] == 10
		end

		def spare?
			sum == 10 && !strike?
		end

		def bonus_for_strike
			sum
		end

		def bonus_for_spare
			@rolls[0]
		end

		def pins=(value)
			@rolls[@index] = value
			@index = @index + 1
		end

		def finished?
			@index > 1 || strike?
		end

	end

	def add_frame?
		@frames.empty? || @frames.last.finished?
	end

	public

	def initialize
		@frames = []
	end

	def hit(pins)
		@frames << Frame.new if add_frame?
		@frames.last.pins=pins
	end

	def score
		was_spare = false
		was_strike = false
		@frames.inject(0) do |score, current_frame|
			if(was_strike)
				score = score + current_frame.bonus_for_strike
			end
			if(was_spare)
				score = score + current_frame.bonus_for_spare
			end
			was_spare = current_frame.spare?
			was_strike = current_frame.strike?

			score + current_frame.sum

		end
	end
end

I'm quite satisfied for the result, I like the encapsulation of responsibility inside Frame, but I don't like at all the fact I saved a state during the score's calculation: I will focus on that in next practice.

At last, the environment created has been very friendly, I didn't miss Eclipse for normal developing, maybe I miss a bit a helper for extracting method, but with snippets and the Vim shortcuts, I gained a lot of productivity.

Technorati Tags: , , , , ,

Tags: , , , , ,


« Previous Page