File: recurring_day.rb

package info (click to toggle)
mhc 1.2.1-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 2,452 kB
  • sloc: ruby: 12,700; lisp: 7,577; makefile: 70; sh: 68
file content (131 lines) | stat: -rw-r--r-- 3,841 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
module RiCal
  class PropertyValue
    class RecurrenceRule < PropertyValue
      #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
      #
      # Instances of RecurringDay are used to represent values in BYDAY recurrence rule parts
      #
      class RecurringDay # :nodoc: 
        
        attr_reader :wday, :index, :rrule

        DayNames = %w{SU MO TU WE TH FR SA} unless defined? DayNames
        day_nums = {}
        unless defined? DayNums
          DayNames.each_with_index { |name, i| day_nums[name] = i }
          DayNums = day_nums
        end

        attr_reader :source, :scope
        def initialize(source, rrule, scope = :monthly)
          @source = source
          @rrule = rrule
          @scope = scope
          wd_match = source.match(/([+-]?\d*)(SU|MO|TU|WE|TH|FR|SA)/)
          if wd_match
            @day, @ordinal = wd_match[2], wd_match[1]
            @wday = DayNums[@day]
            @index = (@ordinal == "") ? nil : @ordinal.to_i
          end
        end

        def valid?
          !@day.nil?
        end

        def ==(another)
          self.class === another && to_a = another.to_a
        end

        def to_a
          [@day, @ordinal]
        end
        
        # return a list id for a given time to allow the enumerator to cache lists
        def list_id(time)
          case @scope
          when :yearly
            time.year
          when :monthly
            (time.year * 100) + time.month
          when :weekly
            time.at_start_of_week_with_wkst(rrule.wkst_day).jd
          end
        end
        
        # return a list of times which match the time parameter within the scope of the RecurringDay
        def matches_for(time)
          case @scope
          when :yearly
            yearly_matches_for(time)
          when :monthly
            monthly_matches_for(time)
          when :weekly
            weekly_matches_for(time)
          else
            walkback = caller.grep(/recurrence/i)
            raise "Logic error!#{@scope.inspect}\n  #{walkback.join("\n  ")}"
          end         
        end
        
        def yearly_matches_for(time)
          if @ordinal == ""
            t = time.nth_wday_in_year(1, wday)
            result = []
            year = time.year
            while t.year == year
              result << t
              t = t.advance(:week => 1)
            end
            result
          else
            [time.nth_wday_in_year(@ordinal.to_i, wday)]
          end
        end
        
        def monthly_matches_for(time)
          if @ordinal == ""
            t = time.nth_wday_in_month(1, wday)
            result = []
            month = time.month
            while t.month == month
              result << t
              t = t.advance(:days => 7)
            end
            result
          else
            result = [time.nth_wday_in_month(index, wday)]
            result
          end
        end

        def weekly_matches_for(time)
          date = time.start_of_week_with_wkst(rrule.wkst_day)
          date += 1 while date.wday != wday
          [time.change(:year => date.year, :month => date.month, :day => date.day)]
        end

        def to_s
          "#{@ordinal}#{@day}"
        end
        
        def ordinal_match(date_or_time)
          if @ordinal == "" || @scope == :weekly
            true
          else
            if @scope == :yearly
              date_or_time.nth_wday_in_year?(index, wday) 
            else
              date_or_time.nth_wday_in_month?(index, wday)
            end
          end
        end

        # Determine if a particular date, time, or date_time is included in the recurrence
        def include?(date_or_time)
          date_or_time.wday == wday && ordinal_match(date_or_time)
        end
      end
    end
  end
end