Last active
December 27, 2015 11:59
-
-
Save zporter/7323059 to your computer and use it in GitHub Desktop.
Confident Ruby: Traffic Light Refactoring
This file contains 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
class TrafficLight | |
class Lamp | |
%w(name color).each do |attr| | |
define_singleton_method("#{attr}=") do |value| | |
define_method(attr) { value } | |
end | |
end | |
def to_s | |
name | |
end | |
def turn_on | |
puts "Turning on #{color} lamp" | |
end | |
end | |
class RedLamp < Lamp | |
self.name = 'stop' | |
self.color = 'red' | |
end | |
class GreenLamp < Lamp | |
self.name = 'proceed' | |
self.color = 'green' | |
end | |
class YellowLamp < Lamp | |
self.name = 'caution' | |
self.color = 'yellow' | |
def turn_on | |
super | |
puts 'Ring ring ring!' | |
end | |
end | |
class Lamps | |
COLLECTION = [ | |
RedLamp.new, | |
GreenLamp.new, | |
YellowLamp.new | |
] | |
class << self | |
@current = 0 | |
def select_by_name(name) | |
index = COLLECTION.index{ |l| l.name == name.to_s } | |
if index | |
@current = index | |
else | |
raise(ArgumentError, "Could not find Lamp with name: #{name}") | |
end | |
end | |
def signal | |
current_lamp.turn_on | |
end | |
def current_lamp | |
COLLECTION[@current] | |
end | |
def next | |
index = if (@current + 1) >= COLLECTION.length | |
0 | |
else | |
@current + 1 | |
end | |
COLLECTION[index] | |
end | |
end | |
end | |
def change_to(state) | |
Lamps.select_by_name(state) | |
end | |
def signal | |
Lamps.signal | |
end | |
def next_state | |
Lamps.next.to_s | |
end | |
end |
This file contains 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 'minitest/autorun' | |
require_relative 'traffic_light' | |
describe TrafficLight do | |
subject { TrafficLight.new } | |
describe "when current state is stop" do | |
before do | |
subject.change_to 'stop' | |
end | |
it "turns on red light" do | |
proc { subject.signal }.must_output "Turning on red lamp\n" | |
end | |
it "has next state of proceed" do | |
subject.next_state.must_equal 'proceed' | |
end | |
end | |
describe "when current state is caution" do | |
before do | |
subject.change_to :caution | |
end | |
it "turns on yellow light and rings warning bell" do | |
proc{ subject.signal }.must_output "Turning on yellow lamp\nRing ring ring!\n" | |
end | |
it "has next state of stop" do | |
subject.next_state.must_equal 'stop' | |
end | |
end | |
describe "when current state is proceed" do | |
before do | |
subject.change_to :proceed | |
end | |
it "turns on green light" do | |
proc{ subject.signal }.must_output "Turning on green lamp\n" | |
end | |
it "has next state of caution" do | |
subject.next_state.must_equal 'caution' | |
end | |
end | |
describe "when changing to an invalid state" do | |
it "raises an ArgumentError exception" do | |
proc { subject.change_to 'lolwut' }.must_raise ArgumentError | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment