Please Forward: Ruby Quiz Submission

From: "Roland Swingler" <roland.swingler@gmail.com>
Date: August 28, 2006 3:07:36 PM CDT
To: submission@rubyquiz.com
Subject: Please Forward: Ruby Quiz Submission

Hi,

Here is my solution. I have added start accessor methods so one can
set the day the week starts - a lot of uses for this might want a more
weekend focused week, i.e. Thu-Mon. I had just been reading the first
couple of pages of "Programming Pearls" by Jon Bentley, and that gave
me the idea of using a "bit array" approach to the problem of sorting
the days. One stylistic approach I wanted to play with was using ||
and && in assignment - they might be used slightly too heavily

dayrange.rb:

require 'parsedate'

class DayRange
WEEK = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]

def initialize(*days)
   @start = 0
   @days = Array.new(7, nil)
   days.each do |day|
     i = int_for day
     @days[i] = WEEK[i]
   end
end

def to_s
   # Convert any middle days to "-"
   output = [@days[0]] + (1..6).map do |i|
     (@days[i] &&
      (WEEK.include?(@days[i-1]) || @days[i-1] == "-") &&
      WEEK.include?(@days[i+1]) &&
      "-") || @days[i]
   end
   # remove nils, duplicate dashes and any commas surounding them
   output.compact.join(", ").gsub(/(, )?-, /, '-').squeeze
end

def start=(day)
   i = int_for(day) - @start
   if i != 0
     @start += i
     # shift days from the front or back of the array to the other
end
     # so as to get the start day to index 0
     index, shift_len = (i > 0) ? [0, i] : [i, -i]
     mv_days = @days.slice!(index, shift_len)
     @days = (i > 0) ? @days + mv_days : mv_days + @days
   end
end

def start
   WEEK[@start]
end

private

def int_for(day)
   # Get the day as an integer regardless of input
   i = ((day.is_a?(String) && ParseDate.parsedate(day)[7]) || day) - 1
   # ParseDate thinks that Sunday is the 0th day of the week
   i = 6 if -1 == i
   raise ArgumentError unless (0..6).include?(i)
   i
end
end

And my test case - tc_dayrange.rb:

require 'dayrange'
require 'test/unit'

class TestDays < Test::Unit::TestCase
def test_all
   d = DayRange.new(1,2,3,4,5,6,7)
   assert_equal("Mon-Sun", d.to_s)
end

def test_end
   d = DayRange.new(1,2,3,4,5,6)
   assert_equal("Mon-Sat", d.to_s)
end

def test_start
   d = DayRange.new(2,3,4,5,6,7)
   assert_equal("Tue-Sun", d.to_s)
end

def test_alternate
   d = DayRange.new(1,3,4,6,7)
   assert_equal("Mon, Wed, Thu, Sat, Sun", d.to_s)
end

def test_no_wrap
   d = DayRange.new(1,2,3,6,7)
   assert_equal("Mon-Wed, Sat, Sun", d.to_s)
end

def test_order_unimportant
   d = DayRange.new(4,1,5,6,3)
   assert_equal("Mon, Wed-Sat", d.to_s)
end

def test_single
   d = DayRange.new(7)
   assert_equal("Sun", d.to_s)
end

def test_two
   d = DayRange.new(7,1)
   assert_equal("Mon, Sun", d.to_s)
end

def test_two_names
   d = DayRange.new("Monday", "Sun")
   assert_equal("Mon, Sun", d.to_s)
end

def test_error_raised
   assert_raise(ArgumentError){
     d = DayRange.new(1, 8)
   }
end

def test_week_start_friday
   d = DayRange.new(5,6,7,1)
   d.start = "Fri"
   assert_equal("Fri-Mon", d.to_s)
end

def test_week_start_can_be_changed
   d = DayRange.new(5,6,7,1)
   assert_equal "Mon", d.start
   d.start = 5
   assert_equal("Fri-Mon", d.to_s)
   d.start = "Sat"
   assert_equal("Sat-Mon, Fri", d.to_s)
   d.start = "Monday"
   assert_equal("Mon, Fri-Sun", d.to_s)
end
end

end

···

Begin forwarded message: