From: Jason Merrill Date: 2006-08-28T13:34:13+09:00 Subject: Re: [Solution][QUIZ] DayRange (#92) This solution does more or less the absolute minimum required by the quiz, but it is fairly short and easy to follow, I believe. This is my first time submitting a solution, and I'm fairly new to ruby. Ideally, I'd like to make the class methods private, but I was having some trouble getting that to work out. If I make them private as things stand now, I get a no method error, "private method called" in the constructor. I thought one could fix that by calling the class methods without a reciever, but for some reason, when I call these class methods without a reciever, I also get a no method error. To be concrete, if I change the line @string = DateRange.build_string(arr) to @string = build_string(arr), when I run the unit tests below I get NoMethodError: undefined method 'build_string' for :DateRange ./daterange.rb:21:in 'initialize' daterangetest.rb:7:in 'test_init' Any advice anyone could offer about how to do this private_class_method buisiness correctly would be greatly appreciated. -- Jason Merrill require 'test/unit' class DateRange DAY_NUMBERS = { 1 => 'Mon', 2 => 'Tue', 3 => 'Wed', 4 => 'Thu', 5 => 'Fri', 6 => 'Sat', 7 => 'Sun' } # Creates a new DateRange from a list of representations of days of the week def initialize(*args) # Convert the arguments to an array of day numbers arr = args.collect {|rep| DateRange.day_num(rep)} arr.uniq! arr.sort! @string = DateRange.build_string(arr) end # Given a sorted array of day numbers, build the string representation def self.build_string(arr) result = '' while i = arr.shift # Add the day name to the string result << "#{DAY_NUMBERS[i]}" # If there is a run of 3 or more consecutive days, add a '-' character, # and then put the last day of the run after it if arr[1] == i + 2 result << '-' i = arr.shift while arr.first == i + 1 result << "#{DAY_NUMBERS[i]}" end # Unless this is the last day result << ', ' if arr.first end result end # Returns the number representation of a day of the week specified by number, # name, or abbreviation # # DateRange.day_num(2) => 2 # DateRange.day_num('Fri') => 5 # DateRange.day_num('saturday') => 6 def self.day_num(rep) if (1..7).include?(rep.to_i) rep.to_i else result = DAY_NUMBERS.index(rep[0,3].capitalize) raise ArgumentError unless result result end end def to_s @string end end class DateRangeTest < Test::Unit::TestCase def test_init assert_equal('Mon-Sun', DateRange.new(1,2,3,4,5,6,7).to_s) assert_equal('Mon-Wed, Sat, Sun', DateRange.new(1,2,3,6,7).to_s) assert_equal('Mon, Wed-Sat', DateRange.new(1,3,4,5,6).to_s) assert_equal('Tue-Thu, Sat, Sun', DateRange.new(2,3,4,6,7).to_s) assert_equal('Mon, Wed, Thu, Sat, Sun', DateRange.new(1,3,4,6,7).to_s) assert_equal('Sun', DateRange.new(7).to_s) assert_equal('Mon, Sun', DateRange.new(1,7).to_s) assert_equal('Mon-Fri', DateRange.new(*%w(Wednesday Monday Tuesday Thursday Friday Monday)).to_s) assert_raise(ArgumentError) {DateRange.new(1,8)} end end