chronic_2011 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
 - data/HISTORY.md +4 -0
 - data/LICENSE +21 -0
 - data/README.md +180 -0
 - data/Rakefile +46 -0
 - data/chronic.gemspec +18 -0
 - data/lib/chronic.rb +117 -0
 - data/lib/chronic/chronic.rb +346 -0
 - data/lib/chronic/grabber.rb +33 -0
 - data/lib/chronic/handler.rb +88 -0
 - data/lib/chronic/handlers.rb +553 -0
 - data/lib/chronic/mini_date.rb +38 -0
 - data/lib/chronic/numerizer.rb +121 -0
 - data/lib/chronic/ordinal.rb +47 -0
 - data/lib/chronic/pointer.rb +32 -0
 - data/lib/chronic/repeater.rb +142 -0
 - data/lib/chronic/repeaters/repeater_day.rb +53 -0
 - data/lib/chronic/repeaters/repeater_day_name.rb +52 -0
 - data/lib/chronic/repeaters/repeater_day_portion.rb +108 -0
 - data/lib/chronic/repeaters/repeater_fortnight.rb +71 -0
 - data/lib/chronic/repeaters/repeater_hour.rb +58 -0
 - data/lib/chronic/repeaters/repeater_minute.rb +58 -0
 - data/lib/chronic/repeaters/repeater_month.rb +79 -0
 - data/lib/chronic/repeaters/repeater_month_name.rb +94 -0
 - data/lib/chronic/repeaters/repeater_season.rb +109 -0
 - data/lib/chronic/repeaters/repeater_season_name.rb +43 -0
 - data/lib/chronic/repeaters/repeater_second.rb +42 -0
 - data/lib/chronic/repeaters/repeater_time.rb +128 -0
 - data/lib/chronic/repeaters/repeater_week.rb +74 -0
 - data/lib/chronic/repeaters/repeater_weekday.rb +85 -0
 - data/lib/chronic/repeaters/repeater_weekend.rb +66 -0
 - data/lib/chronic/repeaters/repeater_year.rb +77 -0
 - data/lib/chronic/scalar.rb +116 -0
 - data/lib/chronic/season.rb +26 -0
 - data/lib/chronic/separator.rb +94 -0
 - data/lib/chronic/span.rb +31 -0
 - data/lib/chronic/tag.rb +36 -0
 - data/lib/chronic/time_zone.rb +32 -0
 - data/lib/chronic/token.rb +47 -0
 - data/test/helper.rb +12 -0
 - data/test/test_chronic.rb +148 -0
 - data/test/test_daylight_savings.rb +118 -0
 - data/test/test_handler.rb +104 -0
 - data/test/test_mini_date.rb +32 -0
 - data/test/test_numerizer.rb +72 -0
 - data/test/test_parsing.rb +977 -0
 - data/test/test_repeater_day_name.rb +51 -0
 - data/test/test_repeater_day_portion.rb +254 -0
 - data/test/test_repeater_fortnight.rb +62 -0
 - data/test/test_repeater_hour.rb +68 -0
 - data/test/test_repeater_minute.rb +34 -0
 - data/test/test_repeater_month.rb +50 -0
 - data/test/test_repeater_month_name.rb +56 -0
 - data/test/test_repeater_season.rb +40 -0
 - data/test/test_repeater_time.rb +70 -0
 - data/test/test_repeater_week.rb +62 -0
 - data/test/test_repeater_weekday.rb +55 -0
 - data/test/test_repeater_weekend.rb +74 -0
 - data/test/test_repeater_year.rb +69 -0
 - data/test/test_span.rb +23 -0
 - data/test/test_token.rb +25 -0
 - metadata +156 -0
 
| 
         @@ -0,0 +1,109 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Chronic
         
     | 
| 
      
 2 
     | 
    
         
            +
              class RepeaterSeason < Repeater #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                SEASON_SECONDS = 7_862_400 # 91 * 24 * 60 * 60
         
     | 
| 
      
 4 
     | 
    
         
            +
                SEASONS = {
         
     | 
| 
      
 5 
     | 
    
         
            +
                  :spring => Season.new(MiniDate.new(3,20), MiniDate.new(6,20)),
         
     | 
| 
      
 6 
     | 
    
         
            +
                  :summer => Season.new(MiniDate.new(6,21), MiniDate.new(9,22)),
         
     | 
| 
      
 7 
     | 
    
         
            +
                  :autumn => Season.new(MiniDate.new(9,23), MiniDate.new(12,21)),
         
     | 
| 
      
 8 
     | 
    
         
            +
                  :winter => Season.new(MiniDate.new(12,22), MiniDate.new(3,19))
         
     | 
| 
      
 9 
     | 
    
         
            +
                }
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def initialize(type)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  super
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def next(pointer)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  super
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  direction = pointer == :future ? 1 : -1
         
     | 
| 
      
 19 
     | 
    
         
            +
                  next_season = Season.find_next_season(find_current_season(MiniDate.from_time(@now)), direction)
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  find_next_season_span(direction, next_season)
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                def this(pointer = :future)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  super
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  direction = pointer == :future ? 1 : -1
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  today = Chronic.construct(@now.year, @now.month, @now.day)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  this_ssn = find_current_season(MiniDate.from_time(@now))
         
     | 
| 
      
 31 
     | 
    
         
            +
                  case pointer
         
     | 
| 
      
 32 
     | 
    
         
            +
                  when :past
         
     | 
| 
      
 33 
     | 
    
         
            +
                    this_ssn_start = today + direction * num_seconds_til_start(this_ssn, direction)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    this_ssn_end = today
         
     | 
| 
      
 35 
     | 
    
         
            +
                  when :future
         
     | 
| 
      
 36 
     | 
    
         
            +
                    this_ssn_start = today + RepeaterDay::DAY_SECONDS
         
     | 
| 
      
 37 
     | 
    
         
            +
                    this_ssn_end = today + direction * num_seconds_til_end(this_ssn, direction)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  when :none
         
     | 
| 
      
 39 
     | 
    
         
            +
                    this_ssn_start = today + direction * num_seconds_til_start(this_ssn, direction)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    this_ssn_end = today + direction * num_seconds_til_end(this_ssn, direction)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  construct_season(this_ssn_start, this_ssn_end)
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                def offset(span, amount, pointer)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  Span.new(offset_by(span.begin, amount, pointer), offset_by(span.end, amount, pointer))
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def offset_by(time, amount, pointer)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  direction = pointer == :future ? 1 : -1
         
     | 
| 
      
 52 
     | 
    
         
            +
                  time + amount * direction * SEASON_SECONDS
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                def width
         
     | 
| 
      
 56 
     | 
    
         
            +
                  SEASON_SECONDS
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 60 
     | 
    
         
            +
                  super << '-season'
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                private
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                def find_next_season_span(direction, next_season)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  unless @next_season_start or @next_season_end
         
     | 
| 
      
 67 
     | 
    
         
            +
                    @next_season_start = Chronic.construct(@now.year, @now.month, @now.day)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    @next_season_end = Chronic.construct(@now.year, @now.month, @now.day)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                  @next_season_start += direction * num_seconds_til_start(next_season, direction)
         
     | 
| 
      
 72 
     | 
    
         
            +
                  @next_season_end += direction * num_seconds_til_end(next_season, direction)
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  construct_season(@next_season_start, @next_season_end)
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                def find_current_season(md)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  [:spring, :summer, :autumn, :winter].find do |season|
         
     | 
| 
      
 79 
     | 
    
         
            +
                    md.is_between?(SEASONS[season].start, SEASONS[season].end)
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
                end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                def num_seconds_til(goal, direction)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  start = Chronic.construct(@now.year, @now.month, @now.day)
         
     | 
| 
      
 85 
     | 
    
         
            +
                  seconds = 0
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                  until MiniDate.from_time(start + direction * seconds).equals?(goal)
         
     | 
| 
      
 88 
     | 
    
         
            +
                    seconds += RepeaterDay::DAY_SECONDS
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                  seconds
         
     | 
| 
      
 92 
     | 
    
         
            +
                end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                def num_seconds_til_start(season_symbol, direction)
         
     | 
| 
      
 95 
     | 
    
         
            +
                  num_seconds_til(SEASONS[season_symbol].start, direction)
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                def num_seconds_til_end(season_symbol, direction)
         
     | 
| 
      
 99 
     | 
    
         
            +
                  num_seconds_til(SEASONS[season_symbol].end, direction)
         
     | 
| 
      
 100 
     | 
    
         
            +
                end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                def construct_season(start, finish)
         
     | 
| 
      
 103 
     | 
    
         
            +
                  Span.new(
         
     | 
| 
      
 104 
     | 
    
         
            +
                    Chronic.construct(start.year, start.month, start.day),
         
     | 
| 
      
 105 
     | 
    
         
            +
                    Chronic.construct(finish.year, finish.month, finish.day)
         
     | 
| 
      
 106 
     | 
    
         
            +
                  )
         
     | 
| 
      
 107 
     | 
    
         
            +
                end
         
     | 
| 
      
 108 
     | 
    
         
            +
              end
         
     | 
| 
      
 109 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Chronic
         
     | 
| 
      
 2 
     | 
    
         
            +
              class RepeaterSeasonName < RepeaterSeason #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                SEASON_SECONDS = 7_862_400 # 91 * 24 * 60 * 60
         
     | 
| 
      
 4 
     | 
    
         
            +
                DAY_SECONDS = 86_400 # (24 * 60 * 60)
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                def next(pointer)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  direction = pointer == :future ? 1 : -1
         
     | 
| 
      
 8 
     | 
    
         
            +
                  find_next_season_span(direction, @type)
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def this(pointer = :future)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  direction = pointer == :future ? 1 : -1
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  today = Chronic.construct(@now.year, @now.month, @now.day)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  goal_ssn_start = today + direction * num_seconds_til_start(@type, direction)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  goal_ssn_end = today + direction * num_seconds_til_end(@type, direction)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  curr_ssn = find_current_season(MiniDate.from_time(@now))
         
     | 
| 
      
 18 
     | 
    
         
            +
                  case pointer
         
     | 
| 
      
 19 
     | 
    
         
            +
                  when :past
         
     | 
| 
      
 20 
     | 
    
         
            +
                    this_ssn_start = goal_ssn_start
         
     | 
| 
      
 21 
     | 
    
         
            +
                    this_ssn_end = (curr_ssn == @type) ? today : goal_ssn_end
         
     | 
| 
      
 22 
     | 
    
         
            +
                  when :future
         
     | 
| 
      
 23 
     | 
    
         
            +
                    this_ssn_start = (curr_ssn == @type) ? today + RepeaterDay::DAY_SECONDS : goal_ssn_start
         
     | 
| 
      
 24 
     | 
    
         
            +
                    this_ssn_end = goal_ssn_end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  when :none
         
     | 
| 
      
 26 
     | 
    
         
            +
                    this_ssn_start = goal_ssn_start
         
     | 
| 
      
 27 
     | 
    
         
            +
                    this_ssn_end = goal_ssn_end
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  construct_season(this_ssn_start, this_ssn_end)
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def offset(span, amount, pointer)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  Span.new(offset_by(span.begin, amount, pointer), offset_by(span.end, amount, pointer))
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                def offset_by(time, amount, pointer)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  direction = pointer == :future ? 1 : -1
         
     | 
| 
      
 39 
     | 
    
         
            +
                  time + amount * direction * RepeaterYear::YEAR_SECONDS
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,42 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Chronic
         
     | 
| 
      
 2 
     | 
    
         
            +
              class RepeaterSecond < Repeater #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                SECOND_SECONDS = 1 # haha, awesome
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(type)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  super
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def next(pointer = :future)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  super
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  direction = pointer == :future ? 1 : -1
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  if !@second_start
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @second_start = @now + (direction * SECOND_SECONDS)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  else
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @second_start += SECOND_SECONDS * direction
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  Span.new(@second_start, @second_start + SECOND_SECONDS)
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def this(pointer = :future)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  super
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  Span.new(@now, @now + 1)
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def offset(span, amount, pointer)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  direction = pointer == :future ? 1 : -1
         
     | 
| 
      
 31 
     | 
    
         
            +
                  span + direction * amount * SECOND_SECONDS
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def width
         
     | 
| 
      
 35 
     | 
    
         
            +
                  SECOND_SECONDS
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 39 
     | 
    
         
            +
                  super << '-second'
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
              end
         
     | 
| 
      
 42 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,128 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Chronic
         
     | 
| 
      
 2 
     | 
    
         
            +
              class RepeaterTime < Repeater #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Tick #:nodoc:
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_accessor :time
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(time, ambiguous = false)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @time = time
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @ambiguous = ambiguous
         
     | 
| 
      
 9 
     | 
    
         
            +
                  end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def ambiguous?
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @ambiguous
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def *(other)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    Tick.new(@time * other, @ambiguous)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def to_f
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @time.to_f
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def to_s
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @time.to_s + (@ambiguous ? '?' : '')
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def initialize(time)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  t = time.gsub(/\:/, '')
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  @type =
         
     | 
| 
      
 33 
     | 
    
         
            +
                  case t.size
         
     | 
| 
      
 34 
     | 
    
         
            +
                  when 1..2
         
     | 
| 
      
 35 
     | 
    
         
            +
                    hours = t.to_i
         
     | 
| 
      
 36 
     | 
    
         
            +
                    Tick.new((hours == 12 ? 0 : hours) * 60 * 60, true)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  when 3
         
     | 
| 
      
 38 
     | 
    
         
            +
                    hours = t[0..0].to_i
         
     | 
| 
      
 39 
     | 
    
         
            +
                    ambiguous = hours > 0
         
     | 
| 
      
 40 
     | 
    
         
            +
                    Tick.new((hours * 60 * 60) + (t[1..2].to_i * 60), ambiguous)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  when 4
         
     | 
| 
      
 42 
     | 
    
         
            +
                    ambiguous = time =~ /:/ && t[0..0].to_i != 0 && t[0..1].to_i <= 12
         
     | 
| 
      
 43 
     | 
    
         
            +
                    hours = t[0..1].to_i
         
     | 
| 
      
 44 
     | 
    
         
            +
                    hours == 12 ? Tick.new(0 * 60 * 60 + t[2..3].to_i * 60, ambiguous) : Tick.new(hours * 60 * 60 + t[2..3].to_i * 60, ambiguous)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  when 5
         
     | 
| 
      
 46 
     | 
    
         
            +
                    Tick.new(t[0..0].to_i * 60 * 60 + t[1..2].to_i * 60 + t[3..4].to_i, true)
         
     | 
| 
      
 47 
     | 
    
         
            +
                  when 6
         
     | 
| 
      
 48 
     | 
    
         
            +
                    ambiguous = time =~ /:/ && t[0..0].to_i != 0 && t[0..1].to_i <= 12
         
     | 
| 
      
 49 
     | 
    
         
            +
                    hours = t[0..1].to_i
         
     | 
| 
      
 50 
     | 
    
         
            +
                    hours == 12 ? Tick.new(0 * 60 * 60 + t[2..3].to_i * 60 + t[4..5].to_i, ambiguous) : Tick.new(hours * 60 * 60 + t[2..3].to_i * 60 + t[4..5].to_i, ambiguous)
         
     | 
| 
      
 51 
     | 
    
         
            +
                  else
         
     | 
| 
      
 52 
     | 
    
         
            +
                    raise("Time cannot exceed six digits")
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                # Return the next past or future Span for the time that this Repeater represents
         
     | 
| 
      
 57 
     | 
    
         
            +
                #   pointer - Symbol representing which temporal direction to fetch the next day
         
     | 
| 
      
 58 
     | 
    
         
            +
                #             must be either :past or :future
         
     | 
| 
      
 59 
     | 
    
         
            +
                def next(pointer)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  super
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  half_day = 60 * 60 * 12
         
     | 
| 
      
 63 
     | 
    
         
            +
                  full_day = 60 * 60 * 24
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  first = false
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  unless @current_time
         
     | 
| 
      
 68 
     | 
    
         
            +
                    first = true
         
     | 
| 
      
 69 
     | 
    
         
            +
                    midnight = Chronic.time_class.local(@now.year, @now.month, @now.day)
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                    yesterday_midnight = midnight - full_day
         
     | 
| 
      
 72 
     | 
    
         
            +
                    tomorrow_midnight = midnight + full_day
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                    offset_fix = midnight.gmt_offset - tomorrow_midnight.gmt_offset
         
     | 
| 
      
 75 
     | 
    
         
            +
                    tomorrow_midnight += offset_fix
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                    catch :done do
         
     | 
| 
      
 78 
     | 
    
         
            +
                      if pointer == :future
         
     | 
| 
      
 79 
     | 
    
         
            +
                        if @type.ambiguous?
         
     | 
| 
      
 80 
     | 
    
         
            +
                          [midnight + @type.time + offset_fix, midnight + half_day + @type.time + offset_fix, tomorrow_midnight + @type.time].each do |t|
         
     | 
| 
      
 81 
     | 
    
         
            +
                            (@current_time = t; throw :done) if t >= @now
         
     | 
| 
      
 82 
     | 
    
         
            +
                          end
         
     | 
| 
      
 83 
     | 
    
         
            +
                        else
         
     | 
| 
      
 84 
     | 
    
         
            +
                          [midnight + @type.time + offset_fix, tomorrow_midnight + @type.time].each do |t|
         
     | 
| 
      
 85 
     | 
    
         
            +
                            (@current_time = t; throw :done) if t >= @now
         
     | 
| 
      
 86 
     | 
    
         
            +
                          end
         
     | 
| 
      
 87 
     | 
    
         
            +
                        end
         
     | 
| 
      
 88 
     | 
    
         
            +
                      else # pointer == :past
         
     | 
| 
      
 89 
     | 
    
         
            +
                        if @type.ambiguous?
         
     | 
| 
      
 90 
     | 
    
         
            +
                          [midnight + half_day + @type.time + offset_fix, midnight + @type.time + offset_fix, yesterday_midnight + @type.time + half_day].each do |t|
         
     | 
| 
      
 91 
     | 
    
         
            +
                            (@current_time = t; throw :done) if t <= @now
         
     | 
| 
      
 92 
     | 
    
         
            +
                          end
         
     | 
| 
      
 93 
     | 
    
         
            +
                        else
         
     | 
| 
      
 94 
     | 
    
         
            +
                          [midnight + @type.time + offset_fix, yesterday_midnight + @type.time].each do |t|
         
     | 
| 
      
 95 
     | 
    
         
            +
                            (@current_time = t; throw :done) if t <= @now
         
     | 
| 
      
 96 
     | 
    
         
            +
                          end
         
     | 
| 
      
 97 
     | 
    
         
            +
                        end
         
     | 
| 
      
 98 
     | 
    
         
            +
                      end
         
     | 
| 
      
 99 
     | 
    
         
            +
                    end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                    @current_time || raise("Current time cannot be nil at this point")
         
     | 
| 
      
 102 
     | 
    
         
            +
                  end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                  unless first
         
     | 
| 
      
 105 
     | 
    
         
            +
                    increment = @type.ambiguous? ? half_day : full_day
         
     | 
| 
      
 106 
     | 
    
         
            +
                    @current_time += pointer == :future ? increment : -increment
         
     | 
| 
      
 107 
     | 
    
         
            +
                  end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                  Span.new(@current_time, @current_time + width)
         
     | 
| 
      
 110 
     | 
    
         
            +
                end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                def this(context = :future)
         
     | 
| 
      
 113 
     | 
    
         
            +
                  super
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                  context = :future if context == :none
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                  self.next(context)
         
     | 
| 
      
 118 
     | 
    
         
            +
                end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                def width
         
     | 
| 
      
 121 
     | 
    
         
            +
                  1
         
     | 
| 
      
 122 
     | 
    
         
            +
                end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 125 
     | 
    
         
            +
                  super << '-time-' << @type.to_s
         
     | 
| 
      
 126 
     | 
    
         
            +
                end
         
     | 
| 
      
 127 
     | 
    
         
            +
              end
         
     | 
| 
      
 128 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,74 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Chronic
         
     | 
| 
      
 2 
     | 
    
         
            +
              class RepeaterWeek < Repeater #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                WEEK_SECONDS = 604800 # (7 * 24 * 60 * 60)
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(type)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  super
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def next(pointer)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  super
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  if !@current_week_start
         
     | 
| 
      
 13 
     | 
    
         
            +
                    case pointer
         
     | 
| 
      
 14 
     | 
    
         
            +
                    when :future
         
     | 
| 
      
 15 
     | 
    
         
            +
                      sunday_repeater = RepeaterDayName.new(:sunday)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      sunday_repeater.start = @now
         
     | 
| 
      
 17 
     | 
    
         
            +
                      next_sunday_span = sunday_repeater.next(:future)
         
     | 
| 
      
 18 
     | 
    
         
            +
                      @current_week_start = next_sunday_span.begin
         
     | 
| 
      
 19 
     | 
    
         
            +
                    when :past
         
     | 
| 
      
 20 
     | 
    
         
            +
                      sunday_repeater = RepeaterDayName.new(:sunday)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      sunday_repeater.start = (@now + RepeaterDay::DAY_SECONDS)
         
     | 
| 
      
 22 
     | 
    
         
            +
                      sunday_repeater.next(:past)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      last_sunday_span = sunday_repeater.next(:past)
         
     | 
| 
      
 24 
     | 
    
         
            +
                      @current_week_start = last_sunday_span.begin
         
     | 
| 
      
 25 
     | 
    
         
            +
                    end
         
     | 
| 
      
 26 
     | 
    
         
            +
                  else
         
     | 
| 
      
 27 
     | 
    
         
            +
                    direction = pointer == :future ? 1 : -1
         
     | 
| 
      
 28 
     | 
    
         
            +
                    @current_week_start += direction * WEEK_SECONDS
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  Span.new(@current_week_start, @current_week_start + WEEK_SECONDS)
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def this(pointer = :future)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  super
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  case pointer
         
     | 
| 
      
 38 
     | 
    
         
            +
                  when :future
         
     | 
| 
      
 39 
     | 
    
         
            +
                    this_week_start = Chronic.time_class.local(@now.year, @now.month, @now.day, @now.hour) + RepeaterHour::HOUR_SECONDS
         
     | 
| 
      
 40 
     | 
    
         
            +
                    sunday_repeater = RepeaterDayName.new(:sunday)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    sunday_repeater.start = @now
         
     | 
| 
      
 42 
     | 
    
         
            +
                    this_sunday_span = sunday_repeater.this(:future)
         
     | 
| 
      
 43 
     | 
    
         
            +
                    this_week_end = this_sunday_span.begin
         
     | 
| 
      
 44 
     | 
    
         
            +
                    Span.new(this_week_start, this_week_end)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  when :past
         
     | 
| 
      
 46 
     | 
    
         
            +
                    this_week_end = Chronic.time_class.local(@now.year, @now.month, @now.day, @now.hour)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    sunday_repeater = RepeaterDayName.new(:sunday)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    sunday_repeater.start = @now
         
     | 
| 
      
 49 
     | 
    
         
            +
                    last_sunday_span = sunday_repeater.next(:past)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    this_week_start = last_sunday_span.begin
         
     | 
| 
      
 51 
     | 
    
         
            +
                    Span.new(this_week_start, this_week_end)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  when :none
         
     | 
| 
      
 53 
     | 
    
         
            +
                    sunday_repeater = RepeaterDayName.new(:sunday)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    sunday_repeater.start = @now
         
     | 
| 
      
 55 
     | 
    
         
            +
                    last_sunday_span = sunday_repeater.next(:past)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    this_week_start = last_sunday_span.begin
         
     | 
| 
      
 57 
     | 
    
         
            +
                    Span.new(this_week_start, this_week_start + WEEK_SECONDS)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                def offset(span, amount, pointer)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  direction = pointer == :future ? 1 : -1
         
     | 
| 
      
 63 
     | 
    
         
            +
                  span + direction * amount * WEEK_SECONDS
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                def width
         
     | 
| 
      
 67 
     | 
    
         
            +
                  WEEK_SECONDS
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 71 
     | 
    
         
            +
                  super << '-week'
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
              end
         
     | 
| 
      
 74 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,85 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Chronic
         
     | 
| 
      
 2 
     | 
    
         
            +
              class RepeaterWeekday < Repeater #:nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                DAY_SECONDS = 86400 # (24 * 60 * 60)
         
     | 
| 
      
 4 
     | 
    
         
            +
                DAYS = {
         
     | 
| 
      
 5 
     | 
    
         
            +
                  :sunday => 0,
         
     | 
| 
      
 6 
     | 
    
         
            +
                  :monday => 1,
         
     | 
| 
      
 7 
     | 
    
         
            +
                  :tuesday => 2,
         
     | 
| 
      
 8 
     | 
    
         
            +
                  :wednesday => 3,
         
     | 
| 
      
 9 
     | 
    
         
            +
                  :thursday => 4,
         
     | 
| 
      
 10 
     | 
    
         
            +
                  :friday => 5,
         
     | 
| 
      
 11 
     | 
    
         
            +
                  :saturday => 6
         
     | 
| 
      
 12 
     | 
    
         
            +
                }
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def initialize(type)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  super
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def next(pointer)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  super
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  direction = pointer == :future ? 1 : -1
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  if !@current_weekday_start
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @current_weekday_start = Chronic.construct(@now.year, @now.month, @now.day)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    @current_weekday_start += direction * DAY_SECONDS
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    until is_weekday?(@current_weekday_start.wday)
         
     | 
| 
      
 28 
     | 
    
         
            +
                      @current_weekday_start += direction * DAY_SECONDS
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
                  else
         
     | 
| 
      
 31 
     | 
    
         
            +
                    loop do
         
     | 
| 
      
 32 
     | 
    
         
            +
                      @current_weekday_start += direction * DAY_SECONDS
         
     | 
| 
      
 33 
     | 
    
         
            +
                      break if is_weekday?(@current_weekday_start.wday)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  Span.new(@current_weekday_start, @current_weekday_start + DAY_SECONDS)
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                def this(pointer = :future)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  super
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  case pointer
         
     | 
| 
      
 44 
     | 
    
         
            +
                  when :past
         
     | 
| 
      
 45 
     | 
    
         
            +
                    self.next(:past)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  when :future, :none
         
     | 
| 
      
 47 
     | 
    
         
            +
                    self.next(:future)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                def offset(span, amount, pointer)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  direction = pointer == :future ? 1 : -1
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  num_weekdays_passed = 0; offset = 0
         
     | 
| 
      
 55 
     | 
    
         
            +
                  until num_weekdays_passed == amount
         
     | 
| 
      
 56 
     | 
    
         
            +
                    offset += direction * DAY_SECONDS
         
     | 
| 
      
 57 
     | 
    
         
            +
                    num_weekdays_passed += 1 if is_weekday?((span.begin+offset).wday)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  span + offset
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                def width
         
     | 
| 
      
 64 
     | 
    
         
            +
                  DAY_SECONDS
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                def to_s
         
     | 
| 
      
 68 
     | 
    
         
            +
                  super << '-weekday'
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                private
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                def is_weekend?(day)
         
     | 
| 
      
 74 
     | 
    
         
            +
                  day == symbol_to_number(:saturday) || day == symbol_to_number(:sunday)
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                def is_weekday?(day)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  !is_weekend?(day)
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                def symbol_to_number(sym)
         
     | 
| 
      
 82 
     | 
    
         
            +
                  DAYS[sym] || raise("Invalid symbol specified")
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
              end
         
     | 
| 
      
 85 
     | 
    
         
            +
            end
         
     |