Skip to content

Instantly share code, notes, and snippets.

@jglass
Created May 27, 2011 21:27
Show Gist options
  • Save jglass/996214 to your computer and use it in GitHub Desktop.
Save jglass/996214 to your computer and use it in GitHub Desktop.
My Solution to Gilded Rose Kata-- SPOILER ALERT
source 'http://rubygems.org'
gem 'rspec'
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
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
# 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