Skip to content

Instantly share code, notes, and snippets.

@ashmoran
Created August 21, 2010 09:46
Show Gist options
  • Select an option

  • Save ashmoran/542080 to your computer and use it in GitHub Desktop.

Select an option

Save ashmoran/542080 to your computer and use it in GitHub Desktop.
module Chapter08
module ReplaceTypeCodeWithStateOrStrategy
class RigidMountainBike
def initialize(params)
@tyre_width = params[:tyre_width]
end
def off_road_ability
@tyre_width * MountainBike::TYRE_WIDTH_FACTOR
end
end
class FrontSuspensionMountainBike
def initialize(params)
@tyre_width = params[:tyre_width]
@front_fork_travel = params[:front_fork_travel]
end
def off_road_ability
@tyre_width * MountainBike::TYRE_WIDTH_FACTOR +
@front_fork_travel * MountainBike::FRONT_SUSPENSION_FACTOR
end
end
class FullSuspensionMountainBike
end
class MountainBike
TYRE_WIDTH_FACTOR = 2
FRONT_SUSPENSION_FACTOR = 3
REAR_SUSPENSION_FACTOR = 4
def initialize(params)
set_state_from_hash(params)
end
def add_front_suspension(params)
# NOTE: This line must come last, unless you want to have to
# pass `type_code: :front_suspension` in with the params (which
# would defeat the point of the method)
self.type_code = :front_suspension
set_state_from_hash(params)
end
def add_rear_suspension(params)
unless type_code == :front_suspension
raise "You can't have rear suspension unless you have front suspension"
end
self.type_code = :full_suspension
set_state_from_hash(params)
end
def off_road_ability
return @bike_type.off_road_ability if type_code == :rigid
return @bike_type.off_road_ability if type_code == :front_suspension
result = @tyre_width * TYRE_WIDTH_FACTOR
if type_code == :front_suspension || type_code == :full_suspension
result += @front_fork_travel * FRONT_SUSPENSION_FACTOR
end
if type_code == :full_suspension
result += @rear_fork_travel * REAR_SUSPENSION_FACTOR
end
result
end
def price
case type_code
when :rigid
(1 + @commission) * @base_price
when :front_suspension
(1 + @commission) * @base_price + @front_suspension_price
when :full_suspension
(1 + @commission) * @base_price + @front_suspension_price + @rear_suspension_price
end
end
private
attr_reader :type_code
def type_code=(value)
@type_code = value
@bike_type =
case type_code
when :rigid
RigidMountainBike.new(tyre_width: @tyre_width)
when :front_suspension
FrontSuspensionMountainBike.new(tyre_width: @tyre_width, front_fork_travel: @front_fork_travel)
when :full_suspension
FullSuspensionMountainBike.new
end
end
def set_state_from_hash(hash)
@base_price = hash[:base_price] if hash.has_key?(:base_price)
if hash.has_key?(:front_suspension_price)
@front_suspension_price = hash[:front_suspension_price]
end
if hash.has_key?(:rear_suspension_price)
@rear_suspension_price = hash[:rear_suspension_price]
end
if hash.has_key?(:commission)
@commission = hash[:commission]
end
if hash.has_key?(:tyre_width)
@tyre_width = hash[:tyre_width]
end
if hash.has_key?(:front_fork_travel)
@front_fork_travel = hash[:front_fork_travel]
end
if hash.has_key?(:rear_fork_travel)
@rear_fork_travel = hash[:rear_fork_travel]
end
self.type_code = hash[:type_code] if hash.has_key?(:type_code)
end
end
end
end
require 'spec_helper'
module Chapter08
module ReplaceTypeCodeWithStateOrStrategy
shared_examples_for "a Front-Suspension bike" do
it "has an off-road ability" do
bike.off_road_ability.should eq 20
end
it "has a price" do
bike.price.should eq 170
end
end
shared_examples_for "a Full-Suspension bike" do
it "has an off-road ability" do
bike.off_road_ability.should eq 32
end
it "has a price" do
bike.price.should eq 240
end
end
describe MountainBike do
context "Rigid type" do
let(:bike) {
MountainBike.new(
type_code: :rigid,
tyre_width: 2.5,
base_price: 100,
commission: 0.20
)
}
it "has an off-road ability" do
bike.off_road_ability.should eq 5
end
it "has a price" do
bike.price.should eq 120
end
context "after adding front suspension" do
before(:each) do
bike.add_front_suspension(
front_fork_travel: 5,
front_suspension_price: 50,
rear_fork_travel: 3,
rear_suspension_price: 70,
tyre_width: 2.5,
base_price: 100,
commission: 0.20
)
end
it_should_behave_like "a Front-Suspension bike"
end
it "won't let you add full suspension" do
expect {
bike.add_rear_suspension({})
}.to raise_error { |error|
error.message.should eq "You can't have rear suspension unless you have front suspension"
}
end
end
context "Front-Suspension type" do
let(:bike) {
MountainBike.new(
type_code: :front_suspension,
front_fork_travel: 5,
front_suspension_price: 50,
tyre_width: 2.5,
base_price: 100,
commission: 0.20
)
}
it_should_behave_like "a Front-Suspension bike"
context "after adding real suspension" do
before(:each) do
bike.add_rear_suspension(
front_fork_travel: 5,
front_suspension_price: 50,
rear_fork_travel: 3,
rear_suspension_price: 70,
tyre_width: 2.5,
base_price: 100,
commission: 0.20
)
end
it_should_behave_like "a Full-Suspension bike"
end
end
context "Full-Suspension type" do
let(:bike) {
MountainBike.new(
type_code: :full_suspension,
front_fork_travel: 5,
front_suspension_price: 50,
rear_fork_travel: 3,
rear_suspension_price: 70,
tyre_width: 2.5,
base_price: 100,
commission: 0.20
)
}
it_should_behave_like "a Full-Suspension bike"
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment