In article <20060825130122.XQZJ22014.centrmmtao02.cox.net / eastrmimpo01.cox.net>,
	Ruby Quiz <james / grayproductions.net> writes:

one remark:
I don't like the suggested interface (though I used and didn't work out an
alternative). It does not seem reasonable to instanciate an object providing
all the information in the constructor and the only thing one can do with
that object is call one method once (multiple calls to to_s should be avoided
for performance).
Of course one could extend that api providing additional means that justify
the use of a class, but as is, it does not make sense to me. A simple function
(probably packed into a module for namespace reasons) would do the job just
as good. Or do I miss something?
I just added this remark since the quiz explicitly asks for he best "Ruby 
way"

My solutions takes a list of days which may be grouped to a list of arrays.
Duplicate entries are removed. The to_s method provides an optional parameter
to output full day names.

#! /usr/bin/ruby

class Array
  # split array into array of contiguous slices
  # a slice is contiguous if each item value is the successor of the
  # value of the previous item
  def split_contiguous()
    self.inject( [ [] ] ) do | list, item |
      list[-1].empty? || list[-1][-1].succ == item ? 
	      list[-1] << item : list << [ item ]
      list
    end
  end
end

class DayRange
  # define weekday names as constants
  @@WEEKDAY = [ nil, 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ]
  @@FULLWEEKDAY = [ nil, 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ]

  # prepare for fast weekday to day of week resolution
  @@DAYOFWEEK = {}
  @@WEEKDAY[1,7].each_with_index { | day,idx | @@DAYOFWEEK[day] = idx + 1 }
  @@FULLWEEKDAY[1,7].each_with_index { | day,idx | @@DAYOFWEEK[day] = idx + 1 }

  # take a list of objects or arrays of objects and convert them to an
  # unique sorted array of day of week numbers
  def initialize( *days )
    @days = days.flatten.collect do | day0 |
      day = @@DAYOFWEEK[day0] || day0.to_i # allow for non integer input
      raise ArgumentError.new(day0.inspect) if day < 1 or day > 7 # check input
      day
    end.sort.uniq
  end

  # provide a list of weekdays or weekday ranges
  def day_range( full = false )
    weekday = full ? @@FULLWEEKDAY : @@WEEKDAY
    @days.split_contiguous.inject( [] ) do | list, range |
      list << ( range.size <= 2 ? weekday[range[0]] : 
		 weekday[range[0]] + '-' + weekday[range[-1]] )
      list << weekday[range[1]] if range.size == 2
      list
    end
  end

  def to_s( full = false )
    day_range(full).join(', ')
  end
end

puts DayRange.new( 1,'Tue',3,4,5,6,7 ).to_s(true)
puts DayRange.new(1,2,3,4,5,6,7)
puts DayRange.new(1,2,3,6,7)
puts DayRange.new(1,3,4,5,6)
puts DayRange.new(2,3,4,6,7)
puts DayRange.new(1,3,4,6,7)
puts DayRange.new(7)
puts DayRange.new(1,7)
puts DayRange.new(1,8)