Skip to content

Instantly share code, notes, and snippets.

@zporter
Last active December 27, 2015 11:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zporter/7323059 to your computer and use it in GitHub Desktop.
Save zporter/7323059 to your computer and use it in GitHub Desktop.
Confident Ruby: Traffic Light Refactoring
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
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