Created
August 21, 2010 09:46
-
-
Save ashmoran/542080 to your computer and use it in GitHub Desktop.
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
| 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 |
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 '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