On 10/21/07, Gordon Thiesfeld <gthiesfeld / gmail.com> wrote:
> Here's my solutions.  I used Runt for the heavy lifting.  I just had
> to parse the string and create Runt temporal expressions.

There was a bug in my code.  I shouldn't subtract a minute from the
end of minute ranges, just a second.  Here's the fixed code.

#time_window.rb
require 'runt_ext'

module Runt

  #extends REWeek to allow for spanning across weeks
  class REWeek

    def initialize(start_day,end_day=6)
      @start_day = start_day
      @end_day = end_day
    end

    def include?(date)
      return true if  @start_day==@end_day
      if @start_day < @end_day
        @start_day<=date.wday && @end_day>=date.wday
      else
        (@start_day<=date.wday && 6 >=date.wday) || (0 <=date.wday &&
@end_day >=date.wday)
      end
    end

  end

  class StringParser < Runt::Intersect

    def initialize(string)
      super()
      add parsed(string)
    end

    #recursive method to parse input string
    def parse(token)
      case token
      when ""
        REWeek.new(0)
      when /^(.+);(.+)/ # split at semicolons
        parse($1) | parse($2)
      when /(\D+) (\d.+)/ # split days and times
        parse($1) & parse($2)
      when /(\D+) (\D+)/, /(\d+-\d+) (\d+-\d+)/ # split at spaces
        parse($1) | parse($2)
      when /([A-Z][a-z][a-z])-([A-Z][a-z][a-z])/ # create range of days
        REWeek.new(Runt.const_get($1), Runt.const_get($2))
      when /([A-Z][a-z][a-z])/ # create single day
        DIWeek.new(Runt.const_get($1))
      when /(\d\d)(\d\d)-(\d\d)(\d\d)/ #create time range
        start = Time.mktime(2000,1,1,$1.to_i,$2.to_i)
        # 0600-0900 should work like 0600-0859,
        stop = Time.mktime(2000,1,1,$3.to_i,$4.to_i) - 1
        REDay.new(start.hour, start.min, stop.hour, stop.min)
      end
    end
    alias :parsed :parse

  end

end

class TimeWindow < Runt::StringParser
end