Begin forwarded message: > From: Eric Torreborre <etorreborre / yahoo.com> > Date: August 31, 2006 4:20:10 PM CDT > To: submission / rubyquiz.com > Subject: Please Forward: Ruby Quiz Submission (92) > Reply-To: Eric Torreborre <etorreborre / yahoo.com> > > Hi all, > > This is my first submission to the quiz and I am very glad to do > it! I used this quiz to introduce Ruby to my fellow workers for > today's "Dojo" (see http://bossavit.com/dojo/and http:// > wiki.agilefinland.com/?CodingDojo). > > They found it a very gentle introduction to the language. > > As for myself, I found a great interest in writing properly things > down and then having a look at all other submissions, searching for > better ways to do things. > > Anyway, here is my submission, that goes around the following lines: > > -use of rspec (behavior driven development) to write acceptance tests > -use of the Set class to know if days identifiers are correct > -extension of the Range class to split an array into an array of > ranges for consecutive values > > Here's the code: > > =========================== > #day_range_spec.rb > =========================== > require "spec" > require "day_range" > > context "A new DayRange" do > specify "should accept a list of day numbers" do > DayRange.new([1, 2, 3]) > end > > specify "should accept a list of abbreviated day names" do > DayRange.new(%w{Mon Tue Fri}) > end > > specify "should accept a list of whole day names" do > DayRange.new(%w{Monday Tuesday Friday}) > end > > specify "should raise an argument error an invalid day number is > inputed in the list" do > lambda {DayRange.new([1, 8])}.should_raise(ArgumentError) > end > > specify "should raise an argument error an invalid abbreviated > day is inputed in the list" do > lambda {DayRange.new(["bla"])}.should_raise(ArgumentError) > end > > specify "should raise an argument error an invalid day name is > inputed in the list" do > lambda {DayRange.new(["lunedi"])}.should_raise(ArgumentError) > end > end > > context "A week with a single day" do > specify "should return the day short name only" do > DayRange.new([7]).to_s.should_equal('Sun') > end > end > > context "An initialized DayRange" do > specify "should sort days starting with Monday" do > DayRange.new([3, 1]).to_s.should_equal('Mon, Wed') > end > end > > context "A week DayRange" do > specify "should represent three or more consecutive days by > listing the first day followed by a hyphen (-), followed by the > last day of the range" do > DayRange.new([1, 2, 3, 4, 5, 6, 7]).to_s.should_equal('Mon-Sun') > end > end > context "A week without Thursday and Friday" do > specify "should return 'Mon-Wed, Sat, Sun' (added hyphen)" do > DayRange.new([1, 2, 3, 6, 7]).to_s.should_equal('Mon-Wed, Sat, > Sun') > end > end > > =========================== > # day_range.rb > =========================== > require 'set' > require 'range' > > class DayRange > def initialize(daylist) > raise ArgumentError, "#{daylist.to_s} is not valid" unless > Week.are_valid_identifiers?(daylist) > @days = Week.day_indexes(daylist) > end > > def to_s > ranges = Range.split(@days) > ranges.collect{|r| Week.short_names_from_range(r)}.join(', ') > end > > end > > class Week > DAYS = [[1, 'Mon', 'Monday'], > [2, 'Tue', 'Tuesday'], > [3, 'Wed', 'Wednesday'], > [4, 'Thu', 'Thursday'], > [5, 'Fri', 'Friday'], > [6, 'Sat', 'Saturday'], > [7, 'Sun', 'Sunday']] > > def self.are_valid_identifiers?(days) > return DAYS.flatten.to_set.superset?(days.to_set) > end > > def self.day_indexes(daylist) > return DAYS.select{|d| !d.to_set.intersection > (daylist.to_set).empty?}.collect{|d| d[0]}.sort! > end > > def self.short_names_from_range(range) > if range.to_a.size == 1 > return DAYS[range.first - 1][1] > elsif range.to_a.size == 2 > return DAYS[range.first - 1][1] + ', ' + DAYS[range.last - 1][1] > else > return DAYS[range.first - 1][1] + '-' + DAYS[range.last - 1][1] > end > end > end > > =========================== > #range_spec.rb > =========================== > require "spec" > require "range" > > context "A Range" do > specify "should split a [1] array in a 1..1 range" do > Range.split([1]).should_equal([1..1]) > end > > specify "should split a [1, 2] array in a 1..2 range" do > Range.split([1, 2]).should_equal([1..2]) > end > > specify "should split a [1, 2, 3] array in a 1..3 range" do > Range.split([1, 2, 3]).should_equal([1..3]) > end > > specify "should split a [1, 3] array in 2 ranges: [1..1, 3..3]" do > Range.split([1, 3]).should_equal([1..1, 3..3]) > end > > specify "should split a [1, 2, 4] array in 2 ranges: [1..2, > 4..4]" do > Range.split([1, 2, 4]).should_equal([1..2, 4..4]) > end > > end > =========================== > #range.rb > =========================== > class Range > def self.split(list) > list.inject([]) do |ranges, i| > last_range = ranges.last > if (last_range.nil? || i > last_range.last.next) > ranges << [i, i] > else > last_range[1] = i > end > ranges > end.collect{|r| r.first..r.last} # transform to Range objects > end > > end > > -------------------------------------------------- > Eric Torreborre > LTG - Product Manager > LEIRIOS > tel: 33(0)6.61.48.57.65/33(0)3.81.88.62.02 > e-mail: etorreborre / yahoo.com > blog: http://etorreborre.blogspot.com > -------------------------------------------------- > >