Created
May 27, 2011 21:27
-
-
Save jglass/996214 to your computer and use it in GitHub Desktop.
My Solution to Gilded Rose Kata-- SPOILER ALERT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
source 'http://rubygems.org' | |
gem 'rspec' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require './item.rb' | |
# This is a fantastical store. Items are updated and | |
# generally lose or gain quality with the passage of time. | |
class GildedRose | |
include ItemHandler | |
attr_accessor :items | |
def initialize | |
@items = [] | |
@items << GenericItem.new("+5 Dexterity Vest", 10, 20) | |
@items << CheeseItem.new("Aged Brie", 2, 0) | |
@items << GenericItem.new("Elixir of the Mongoose", 5, 7) | |
@items << LegendaryItem.new("Sulfuras, Hand of Ragnaros", 0, 80) | |
@items << TicketItem.new("Backstage passes to a TAFKAL80ETC concert", 15, 20) | |
@items << ConjuredItem.new("Conjured Mana Cake", 3, 6) | |
end | |
def update_quality | |
@items.each { |item| item.update_item } | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rubygems' | |
require './gilded_rose.rb' | |
require 'rspec' | |
describe GildedRose do | |
before(:each) do | |
@gilded_rose = GildedRose.new | |
end | |
def update_should_decrement_sell_in | |
expect { | |
@gilded_rose.update_quality | |
}.to change { @item.sell_in }.by(-1) | |
end | |
def update_should_change_quality_by(number) | |
expect { | |
@gilded_rose.update_quality | |
}.to change { @item.quality }.by(number) | |
end | |
def update_should_not_change_quality | |
expect { | |
@gilded_rose.update_quality | |
}.to_not change { @item.quality } | |
end | |
describe "generic item, when updated" do | |
before(:each) do | |
@item = @gilded_rose.items.find { |item| item.name =~ /elixir/i } | |
@item.sell_in = 1 | |
@item.quality = 10 | |
end | |
it "should reduce sell_in by 1" do | |
update_should_decrement_sell_in | |
end | |
it "should reduce quality by 1 before it expires" do | |
update_should_change_quality_by(-1) | |
end | |
it "should reduce quality by 2 after it expires" do | |
@item.sell_in = 0 | |
update_should_change_quality_by(-2) | |
end | |
it "should not reduce quality below 0" do | |
@item.quality = 0 | |
update_should_not_change_quality | |
@item.sell_in = 0 | |
update_should_not_change_quality | |
end | |
end | |
describe "cheese item, when updated" do | |
before(:each) do | |
@item = @gilded_rose.items.find { |item| item.name =~ /brie/i } | |
@item.sell_in = 50 | |
@item.quality = 10 | |
end | |
it "should reduce sell_in by 1" do | |
update_should_decrement_sell_in | |
end | |
it "should increase quality by 1 before expiration" do | |
update_should_change_quality_by(1) | |
end | |
it "should increase quality by 2 after expiration" do | |
@item.sell_in = 0 | |
update_should_change_quality_by(2) | |
end | |
it "should not increase quality above 50" do | |
@item.quality = 50 | |
update_should_not_change_quality | |
@item.sell_in = 0 | |
update_should_not_change_quality | |
end | |
end | |
describe "legendary item, when updated" do | |
before(:each) do | |
@item = @gilded_rose.items.find { |item| item.name =~ /hand/i } | |
@item.sell_in = 50 | |
@item.quality = 80 | |
end | |
it "should not decrease in sell_in" do | |
expect { | |
@gilded_rose.update_quality | |
}.to_not change { @item.sell_in } | |
end | |
it "should not change quality" do | |
update_should_not_change_quality | |
end | |
it "should not change quality if created in expired state" do | |
@item.sell_in = -1 | |
update_should_not_change_quality | |
end | |
end | |
describe "ticket item, when updated" do | |
before(:each) do | |
@item = @gilded_rose.items.find { |item| item.name =~ /backstage/i } | |
@item.quality = 10 | |
@item.sell_in = 11 | |
end | |
it "should reduce sell_in by 1" do | |
update_should_decrement_sell_in | |
end | |
it "should increase quality by 1 more than 10 days before concert" do | |
update_should_change_quality_by(1) | |
end | |
it "should increase quality by 2 6-10 days before concert" do | |
[6, 10].each do |num| | |
@item.sell_in = num | |
update_should_change_quality_by(2) | |
end | |
end | |
it "should increase quality by 3 1-5 days before concert" do | |
[1, 5].each do |num| | |
@item.sell_in = num | |
update_should_change_quality_by(3) | |
end | |
end | |
it "should drop to 0 after the concert" do | |
@item.sell_in = 0 | |
expect { | |
@gilded_rose.update_quality | |
}.to change { @item.quality }.to(0) | |
end | |
it "should not go above 50 in any case" do | |
[15, 10, 5].each do |num| | |
@item.quality = 50 | |
@item.sell_in = num | |
update_should_not_change_quality | |
end | |
end | |
end | |
describe "a conjured item, when updated" do | |
before(:each) do | |
@item = @gilded_rose.items.find { |item| item.name =~ /conjured/i } | |
@item.sell_in = 1 | |
@item.quality = 10 | |
end | |
it "should reduce sell_in by 1" do | |
update_should_decrement_sell_in | |
end | |
it "should reduce quality by 2 when not expired" do | |
update_should_change_quality_by(-2) | |
end | |
it "should reduce quality by 4 when expired" do | |
@item.sell_in = 0 | |
update_should_change_quality_by(-4) | |
end | |
it "should not reduce quality below 0" do | |
@item.quality = 0 | |
update_should_not_change_quality | |
@item.sell_in = 0 | |
update_should_not_change_quality | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Wrapper for item classes | |
module ItemHandler | |
# Item would be our generic item class if not | |
# for that pesky goblin. GenericItem adds the | |
# necessary functionality instead. | |
class Item | |
attr_accessor :name, :sell_in, :quality | |
def initialize (name, sell_in, quality) | |
@name = name | |
@sell_in = sell_in | |
@quality = quality | |
end | |
end | |
# All of the actual updating should be done in this class. | |
# @quality is changed by amount of QLTY_CHANGE, or that number | |
# multiplied by 2 if the @sell_in date is passed. Quality | |
# may not be less than QLTY_MIN or greater than QLTY_MAX. | |
class GenericItem < Item | |
QLTY_MIN = 0 | |
QLTY_MAX = 50 | |
QLTY_CHANGE = -1 | |
def update_item | |
@sell_in -= 1 | |
result = @quality + qlty_change | |
@quality = [QLTY_MIN, result, QLTY_MAX].sort[1] | |
end | |
def qlty_change | |
self.class::QLTY_CHANGE * (expired? ? 2 : 1) | |
end | |
def expired? | |
@sell_in < 0 | |
end | |
end | |
# Cheese items gain in value over time, so | |
# QLTY_CHANGE is positive. | |
class CheeseItem < GenericItem | |
QLTY_CHANGE = 1 | |
end | |
# Conjured items decrease in value 2x | |
# faster than generic items, so QLTY_CHANGE is -2. | |
class ConjuredItem < GenericItem | |
QLTY_CHANGE = -2 | |
end | |
# Legendary items never change, so the update_item | |
# method does nothing. They can have @quality > 50. | |
class LegendaryItem < GenericItem | |
def update_item | |
false | |
end | |
end | |
# Ticket items increase in value more quickly as | |
# the concert approaches, then drop to zero. | |
# * > 10 days to concert: +1 @quality | |
# * 6-10 days to concert: +2 @quality | |
# * 1-5 days to concert: +3 @quality | |
# * After concert: @quality is zero | |
class TicketItem < GenericItem | |
def qlty_change | |
return 3 if (0..4).include? @sell_in | |
return 2 if (5..9).include? @sell_in | |
expired? ? @quality * -1 : 1 | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment