Begin forwarded message: > 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