Created
December 11, 2012 11:09
-
-
Save anowell/4257823 to your computer and use it in GitHub Desktop.
AnalogClock class, program, and specs (RSpec tests - TDD)
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 AnalogClock | |
attr_reader :hour, :min, :meridiem | |
def initialize(time) | |
return nil unless time.instance_of?(String) | |
# split on space and colon | |
split_time = time.split(/:| /) | |
return nil unless split_time.length == 3 | |
@hour = split_time[0].to_i if split_time[0].length <= 2 | |
@min = split_time[1].to_i if split_time[1].length == 2 | |
@meridiem = split_time[2].downcase.to_sym if split_time[2].length == 2 | |
# extra validation to prevent "1:ab AM" | |
# might be cleaner to implement a good String::is_i? method | |
@min = nil if @min == 0 and split_time[1] != "00" | |
end | |
def valid? | |
(1..12).include?(hour) and | |
(0..59).include?(min) and | |
[:am, :pm].include?(meridiem) | |
end | |
def military_hour | |
return nil unless valid? | |
mh = hour % 12 | |
mh += 12 if meridiem == :pm | |
mh | |
end | |
def minutes_until(clock) | |
return nil unless valid? and clock.kind_of?(AnalogClock) and clock.valid? | |
dif = (clock.military_hour-military_hour)*60 + (clock.min-min) | |
dif += (24*60) if dif < 0 | |
dif | |
end | |
def self.to_degrees(minutes) | |
minutes * 6 if minutes | |
end | |
def self.to_rotations(minutes) | |
minutes / 60.0 if minutes | |
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_relative 'analog_clock' | |
describe AnalogClock do | |
context "Parser" do | |
it "parses 1:00 AM" do | |
clock = AnalogClock.new "1:00 AM" | |
clock.should be_valid | |
clock.hour.should == 1 | |
clock.min.should == 0 | |
clock.meridiem.should == :am | |
clock.military_hour.should == 1 | |
end | |
it "parses 11:30 PM" do | |
clock = AnalogClock.new "11:30 PM" | |
clock.should be_valid | |
clock.hour.should == 11 | |
clock.min.should == 30 | |
clock.meridiem.should == :pm | |
clock.military_hour.should == 23 | |
end | |
it "parses 12:00 AM" do | |
clock = AnalogClock.new "12:00 AM" | |
clock.should be_valid | |
clock.hour.should == 12 | |
clock.min.should == 0 | |
clock.meridiem.should == :am | |
clock.military_hour.should == 0 | |
end | |
it "parses 12:00 PM" do | |
clock = AnalogClock.new "12:00 PM" | |
clock.should be_valid | |
clock.hour.should == 12 | |
clock.min.should == 0 | |
clock.meridiem.should == :pm | |
clock.military_hour.should == 12 | |
end | |
it "won't parse invalid times" do | |
AnalogClock.new(nil).should_not be_valid | |
AnalogClock.new("").should_not be_valid | |
AnalogClock.new("13:00 PM").should_not be_valid | |
AnalogClock.new("13:00 AM").should_not be_valid | |
AnalogClock.new("1:60 PM").should_not be_valid | |
AnalogClock.new("0:30 PM").should_not be_valid | |
AnalogClock.new("0013:00 AM").should_not be_valid | |
AnalogClock.new("1:1 AM").should_not be_valid | |
AnalogClock.new("a:00 AM").should_not be_valid | |
AnalogClock.new("1:ab AM").should_not be_valid | |
end | |
end | |
context "Comparing clocks" do | |
it "won't compare invalid clocks" do | |
c1 = AnalogClock.new "12:00 AM" | |
c2 = AnalogClock.new "12:00 ZZ" | |
c1.minutes_until(nil).should be_nil | |
c1.minutes_until("not a clock").should be_nil | |
c1.minutes_until(c2).should be_nil | |
c2.minutes_until(c1).should be_nil | |
end | |
it "can compare identical clocks" do | |
clock = AnalogClock.new "12:00 AM" | |
clock.minutes_until(clock).should == 0 | |
end | |
it "compares ordered clocks of same meridiem" do | |
c1 = AnalogClock.new "12:15 AM" | |
c2 = AnalogClock.new "1:30 AM" | |
c1.minutes_until(c2).should == 75 | |
c2 = AnalogClock.new "1:00 AM" | |
c1.minutes_until(c2).should == 45 | |
end | |
it "compares out-of-order clocks of same meridiem" do | |
c1 = AnalogClock.new "2:30 AM" | |
c2 = AnalogClock.new "12:00 AM" | |
c1.minutes_until(c2).should == (21*60+30) # 21 hrs 30 min | |
c3 = AnalogClock.new "2:29 AM" | |
c1.minutes_until(c3).should == 23*60+59 # 23 hours 59 min | |
end | |
it "compares ordered clocks of different meridiems" do | |
c1 = AnalogClock.new "11:59 AM" | |
c2 = AnalogClock.new "12:00 PM" | |
c1.minutes_until(c2).should == 1 | |
end | |
it "compares out-of-order clocks of different meridiems" do | |
c1 = AnalogClock.new "12:45 PM" | |
c2 = AnalogClock.new "12:15 AM" | |
c1.minutes_until(c2).should == (11*60+30) # 11 hr 30 min | |
end | |
end | |
context "Minute converter" do | |
it "converts minutes to rotations" do | |
AnalogClock.to_rotations(nil).should == nil | |
AnalogClock.to_rotations(0).should == 0 | |
AnalogClock.to_rotations(60).should == 1 | |
AnalogClock.to_rotations(90).should == 1.5 | |
AnalogClock.to_rotations(23*60+59).should == (23+59/60.0) | |
end | |
it "converts minutes to degrees" do | |
AnalogClock.to_degrees(nil).should == nil | |
AnalogClock.to_degrees(0).should == 0 | |
AnalogClock.to_degrees(1).should == 6 | |
AnalogClock.to_degrees(90).should == 540 | |
AnalogClock.to_degrees(23*60+59).should == (24*360-6) | |
end | |
end | |
end | |
# $ rspec -c analog_clock_spec.rb | |
# .............. | |
# | |
# Finished in 0.00411 seconds | |
# 13 examples, 0 failures |
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_relative 'analog_clock' | |
def run | |
clock1 = clock2 = nil | |
until clock1 and clock1.valid? do | |
puts 'Enter first time using format "[H]H:MM AM":' | |
clock1 = AnalogClock.new gets.chomp | |
end | |
until clock2 and clock2.valid? do | |
puts 'Enter second time using format "[H]H:MM AM":' | |
clock2 = AnalogClock.new gets.chomp | |
end | |
minutes = clock1.minutes_until(clock2) | |
degrees = AnalogClock.to_degrees(minutes) | |
rotations = AnalogClock.to_rotations(minutes) | |
puts "Minute hand must travel #{degrees} degrees (#{rotations} rotations)." | |
end | |
run | |
# $ ruby analog_clock.rb | |
# Enter first time using format "[H]H:MM AM": | |
# 10:15 AM | |
# Enter second time using format "[H]H:MM AM": | |
# 12:45 PM | |
# Minute hand must travel 900 degrees (2.5 rotations). | |
# $ ruby analog_clock.rb | |
# Enter first time using format "[H]H:MM AM": | |
# 10:00 PM | |
# Enter second time using format "[H]H:MM AM": | |
# 9:00 PM | |
# Minute hand must travel 8280 degrees (23.0 rotations). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment