Skip to content

Instantly share code, notes, and snippets.

@drKreso
Created February 23, 2012 09:41
Show Gist options
  • Save drKreso/1891958 to your computer and use it in GitHub Desktop.
Save drKreso/1891958 to your computer and use it in GitHub Desktop.
The Gilded Rose Code Kata
require 'guerrilla_patch'
SPECIAL_ITEMS = {
legendary: [ 'Sulfuras, Hand of Ragnaros' ],
one_time_event: [ 'Backstage passes to a TAFKAL80ETC concert'],
better_with_age: ['Aged Brie'],
conjured: ['Conjured Mana Cake']
}
QUALITY_AMOUNT_RULES = [
[ "self.standard?", "-1"],
[ "self.is? :conjured", "-2"],
[ "(self.is?(:one_time_event) && (self.sell_in >= 6 && self.sell_in < 11) )", "2"],
[ "(self.is?(:one_time_event) && (self.sell_in < 6 ))", "3"],
[ "true", "1"]
]
EXPIRED_QUALITY_AMOUNT_RULES = [
[ "self.is? :one_time_event", "-self.quality"],
[ "self.is? :better_with_age", "1"],
[ "self.is? :conjured", "-2"],
[ "self.standard?", "-1" ],
[ "true", "0"]
]
def update_quality(items)
items.reject do |item|
item.extend Gilded
item.is? :legendary
end.each(&:tick_time)
end
module Gilded
def tick_time
adjust_quality
adjust_age
end
def adjust_quality
self.quality += find_amount(expired? ? EXPIRED_QUALITY_AMOUNT_RULES : QUALITY_AMOUNT_RULES)
limit_quality
end
def limit_quality
self.quality = 0 if self.quality < 0
self.quality = 50 if self.quality > 50
end
def adjust_age
self.sell_in -= 1
adjust_quality if expired?
end
let(:expired?) { self.sell_in < 0 }
let(:standard?) { (SPECIAL_ITEMS.each_value.reduce([]){|result, array| result += array }).include?(self.name) == false }
let(:is?) {|name| SPECIAL_ITEMS[name].include?(self.name) }
let(:find_amount) { |rules| eval(rules.select {|item| eval(item[0]) }.flatten[1]) }
end
# DO NOT CHANGE THINGS BELOW -----------------------------------------
Item = Struct.new(:name, :sell_in, :quality)
@drKreso
Copy link
Author

drKreso commented Feb 23, 2012

I don't think that optimal solution for the problem is sub-classing since classes hardly carry their weight in this example. I liked the JEG2 refactoring with modules.

Still I think the underlying abstraction for this is that you have arbitrary rules for quality with two cases: before and after expiration. You also have one exception of legendary items not being dependent on time.

IMHO code above communicates this nicely and rules are easy to grasp and extend.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment