demingfactor-ri_cal 0.9.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.
Files changed (167) hide show
  1. checksums.yaml +7 -0
  2. data/History.txt +402 -0
  3. data/Manifest.txt +161 -0
  4. data/README.txt +410 -0
  5. data/Rakefile +69 -0
  6. data/VERSION +1 -0
  7. data/bin/ri_cal +8 -0
  8. data/component_attributes/alarm.yml +10 -0
  9. data/component_attributes/calendar.yml +4 -0
  10. data/component_attributes/component_property_defs.yml +180 -0
  11. data/component_attributes/event.yml +45 -0
  12. data/component_attributes/freebusy.yml +16 -0
  13. data/component_attributes/journal.yml +35 -0
  14. data/component_attributes/timezone.yml +3 -0
  15. data/component_attributes/timezone_period.yml +11 -0
  16. data/component_attributes/todo.yml +46 -0
  17. data/copyrights.txt +1 -0
  18. data/docs/draft-ietf-calsify-2446bis-08.txt +7280 -0
  19. data/docs/draft-ietf-calsify-rfc2445bis-09.txt +10416 -0
  20. data/docs/incrementers.txt +7 -0
  21. data/docs/rfc2445.pdf +0 -0
  22. data/lib/ri_cal/component/alarm.rb +19 -0
  23. data/lib/ri_cal/component/calendar.rb +257 -0
  24. data/lib/ri_cal/component/event.rb +58 -0
  25. data/lib/ri_cal/component/freebusy.rb +16 -0
  26. data/lib/ri_cal/component/journal.rb +27 -0
  27. data/lib/ri_cal/component/non_standard.rb +33 -0
  28. data/lib/ri_cal/component/t_z_info_timezone.rb +153 -0
  29. data/lib/ri_cal/component/timezone/daylight_period.rb +25 -0
  30. data/lib/ri_cal/component/timezone/standard_period.rb +23 -0
  31. data/lib/ri_cal/component/timezone/timezone_period.rb +76 -0
  32. data/lib/ri_cal/component/timezone.rb +197 -0
  33. data/lib/ri_cal/component/todo.rb +42 -0
  34. data/lib/ri_cal/component.rb +256 -0
  35. data/lib/ri_cal/core_extensions/array/conversions.rb +15 -0
  36. data/lib/ri_cal/core_extensions/array.rb +7 -0
  37. data/lib/ri_cal/core_extensions/date/conversions.rb +56 -0
  38. data/lib/ri_cal/core_extensions/date.rb +13 -0
  39. data/lib/ri_cal/core_extensions/date_time/conversions.rb +50 -0
  40. data/lib/ri_cal/core_extensions/date_time.rb +15 -0
  41. data/lib/ri_cal/core_extensions/object/conversions.rb +20 -0
  42. data/lib/ri_cal/core_extensions/object.rb +8 -0
  43. data/lib/ri_cal/core_extensions/string/conversions.rb +57 -0
  44. data/lib/ri_cal/core_extensions/string.rb +8 -0
  45. data/lib/ri_cal/core_extensions/time/calculations.rb +153 -0
  46. data/lib/ri_cal/core_extensions/time/conversions.rb +42 -0
  47. data/lib/ri_cal/core_extensions/time/tzid_access.rb +50 -0
  48. data/lib/ri_cal/core_extensions/time/week_day_predicates.rb +55 -0
  49. data/lib/ri_cal/core_extensions/time.rb +14 -0
  50. data/lib/ri_cal/core_extensions.rb +11 -0
  51. data/lib/ri_cal/fast_date_time.rb +234 -0
  52. data/lib/ri_cal/floating_timezone.rb +32 -0
  53. data/lib/ri_cal/invalid_property_value.rb +8 -0
  54. data/lib/ri_cal/invalid_timezone_identifier.rb +20 -0
  55. data/lib/ri_cal/occurrence_enumerator.rb +265 -0
  56. data/lib/ri_cal/occurrence_period.rb +17 -0
  57. data/lib/ri_cal/parser.rb +148 -0
  58. data/lib/ri_cal/properties/alarm.rb +390 -0
  59. data/lib/ri_cal/properties/calendar.rb +164 -0
  60. data/lib/ri_cal/properties/event.rb +1523 -0
  61. data/lib/ri_cal/properties/freebusy.rb +593 -0
  62. data/lib/ri_cal/properties/journal.rb +1237 -0
  63. data/lib/ri_cal/properties/timezone.rb +150 -0
  64. data/lib/ri_cal/properties/timezone_period.rb +416 -0
  65. data/lib/ri_cal/properties/todo.rb +1559 -0
  66. data/lib/ri_cal/properties.rb +12 -0
  67. data/lib/ri_cal/property_value/array.rb +27 -0
  68. data/lib/ri_cal/property_value/cal_address.rb +11 -0
  69. data/lib/ri_cal/property_value/date.rb +184 -0
  70. data/lib/ri_cal/property_value/date_time/additive_methods.rb +44 -0
  71. data/lib/ri_cal/property_value/date_time/time_machine.rb +159 -0
  72. data/lib/ri_cal/property_value/date_time/timezone_support.rb +100 -0
  73. data/lib/ri_cal/property_value/date_time.rb +359 -0
  74. data/lib/ri_cal/property_value/duration.rb +110 -0
  75. data/lib/ri_cal/property_value/geo.rb +11 -0
  76. data/lib/ri_cal/property_value/integer.rb +12 -0
  77. data/lib/ri_cal/property_value/occurrence_list.rb +144 -0
  78. data/lib/ri_cal/property_value/period.rb +86 -0
  79. data/lib/ri_cal/property_value/recurrence_rule/enumeration_support_methods.rb +100 -0
  80. data/lib/ri_cal/property_value/recurrence_rule/enumerator.rb +79 -0
  81. data/lib/ri_cal/property_value/recurrence_rule/initialization_methods.rb +148 -0
  82. data/lib/ri_cal/property_value/recurrence_rule/negative_setpos_enumerator.rb +53 -0
  83. data/lib/ri_cal/property_value/recurrence_rule/numbered_span.rb +31 -0
  84. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_day_incrementer.rb +86 -0
  85. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_hour_incrementer.rb +31 -0
  86. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_minute_incrementer.rb +32 -0
  87. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_month_incrementer.rb +52 -0
  88. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_monthday_incrementer.rb +31 -0
  89. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_numbered_day_incrementer.rb +38 -0
  90. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_second_incrementer.rb +32 -0
  91. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_weekno_incrementer.rb +69 -0
  92. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_yearday_incrementer.rb +31 -0
  93. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/daily_incrementer.rb +28 -0
  94. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/frequency_incrementer.rb +80 -0
  95. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/hourly_incrementer.rb +23 -0
  96. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/list_incrementer.rb +106 -0
  97. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/minutely_incrementer.rb +23 -0
  98. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/monthly_incrementer.rb +33 -0
  99. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/null_sub_cycle_incrementer.rb +43 -0
  100. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/secondly_incrementer.rb +28 -0
  101. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/weekly_incrementer.rb +37 -0
  102. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/yearly_incrementer.rb +57 -0
  103. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer.rb +135 -0
  104. data/lib/ri_cal/property_value/recurrence_rule/recurring_day.rb +131 -0
  105. data/lib/ri_cal/property_value/recurrence_rule/recurring_month_day.rb +64 -0
  106. data/lib/ri_cal/property_value/recurrence_rule/recurring_numbered_week.rb +33 -0
  107. data/lib/ri_cal/property_value/recurrence_rule/recurring_year_day.rb +53 -0
  108. data/lib/ri_cal/property_value/recurrence_rule/time_manipulation.rb +42 -0
  109. data/lib/ri_cal/property_value/recurrence_rule/validations.rb +125 -0
  110. data/lib/ri_cal/property_value/recurrence_rule.rb +154 -0
  111. data/lib/ri_cal/property_value/text.rb +44 -0
  112. data/lib/ri_cal/property_value/uri.rb +11 -0
  113. data/lib/ri_cal/property_value/utc_offset.rb +33 -0
  114. data/lib/ri_cal/property_value/zulu_date_time.rb +34 -0
  115. data/lib/ri_cal/property_value.rb +159 -0
  116. data/lib/ri_cal/required_timezones.rb +55 -0
  117. data/lib/ri_cal.rb +187 -0
  118. data/parked_specs/ri_cal/claudio_a_bug_spec.rb +100 -0
  119. data/performance/empty_propval/subject.rb +43 -0
  120. data/performance/paris_eastern/subject.rb +90 -0
  121. data/performance/penultimate_weekday/subject.rb +15 -0
  122. data/performance/psm_big_enum/ical.ics +3171 -0
  123. data/performance/psm_big_enum/subject.rb +16 -0
  124. data/performance/utah_cycling/subject.rb +55 -0
  125. data/ri_cal.gemspec +244 -0
  126. data/script/benchmark_subject +23 -0
  127. data/script/console +10 -0
  128. data/script/destroy +14 -0
  129. data/script/generate +14 -0
  130. data/script/profile_subject +29 -0
  131. data/script/txt2html +71 -0
  132. data/spec/ri_cal/bugreports_spec.rb +276 -0
  133. data/spec/ri_cal/component/alarm_spec.rb +12 -0
  134. data/spec/ri_cal/component/calendar_spec.rb +88 -0
  135. data/spec/ri_cal/component/event_spec.rb +735 -0
  136. data/spec/ri_cal/component/freebusy_spec.rb +12 -0
  137. data/spec/ri_cal/component/journal_spec.rb +37 -0
  138. data/spec/ri_cal/component/t_z_info_timezone_spec.rb +60 -0
  139. data/spec/ri_cal/component/timezone_spec.rb +236 -0
  140. data/spec/ri_cal/component/todo_spec.rb +112 -0
  141. data/spec/ri_cal/component_spec.rb +224 -0
  142. data/spec/ri_cal/core_extensions/string/conversions_spec.rb +78 -0
  143. data/spec/ri_cal/core_extensions/time/calculations_spec.rb +188 -0
  144. data/spec/ri_cal/core_extensions/time/week_day_predicates_spec.rb +45 -0
  145. data/spec/ri_cal/fast_date_time_spec.rb +77 -0
  146. data/spec/ri_cal/inf_loop_spec.rb +78 -0
  147. data/spec/ri_cal/occurrence_enumerator_spec.rb +611 -0
  148. data/spec/ri_cal/parser_spec.rb +337 -0
  149. data/spec/ri_cal/property_value/date_spec.rb +53 -0
  150. data/spec/ri_cal/property_value/date_time_spec.rb +383 -0
  151. data/spec/ri_cal/property_value/duration_spec.rb +126 -0
  152. data/spec/ri_cal/property_value/occurrence_list_spec.rb +72 -0
  153. data/spec/ri_cal/property_value/period_spec.rb +63 -0
  154. data/spec/ri_cal/property_value/recurrence_rule/recurring_year_day_spec.rb +21 -0
  155. data/spec/ri_cal/property_value/recurrence_rule_spec.rb +1814 -0
  156. data/spec/ri_cal/property_value/text_spec.rb +25 -0
  157. data/spec/ri_cal/property_value/utc_offset_spec.rb +48 -0
  158. data/spec/ri_cal/property_value_spec.rb +125 -0
  159. data/spec/ri_cal/required_timezones_spec.rb +67 -0
  160. data/spec/ri_cal_spec.rb +53 -0
  161. data/spec/spec.opts +4 -0
  162. data/spec/spec_helper.rb +50 -0
  163. data/tasks/gem_loader/load_active_support.rb +3 -0
  164. data/tasks/gem_loader/load_tzinfo_gem.rb +2 -0
  165. data/tasks/ri_cal.rake +412 -0
  166. data/tasks/spec.rake +102 -0
  167. metadata +246 -0
@@ -0,0 +1,52 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ class OccurrenceIncrementer # :nodoc:
7
+ class ByMonthIncrementer < ListIncrementer #:nodoc:
8
+
9
+ def self.for_rrule(rrule)
10
+ conditional_incrementer(rrule, :bymonth, MonthlyIncrementer)
11
+ end
12
+
13
+ def occurrences_for(date_time)
14
+ if contains_daily_incrementer?
15
+ list.map {|value| date_time.change(:month => value, :day => 1)}
16
+ else
17
+ list.map {|value| date_time.in_month(value)}
18
+ end
19
+ end
20
+
21
+ def range_advance(date_time)
22
+ advance_year(date_time)
23
+ end
24
+
25
+ def start_of_cycle(date_time)
26
+ if contains_daily_incrementer?
27
+ date_time.change(:month => 1, :day => 1)
28
+ else
29
+ date_time.change(:month => 1)
30
+ end
31
+ end
32
+
33
+ def varying_time_attribute
34
+ :month
35
+ end
36
+
37
+ def advance_cycle(date_time)
38
+ if contains_daily_incrementer?
39
+ first_day_of_year(advance_year(date_time))
40
+ else
41
+ advance_year(date_time).change(:month => 1)
42
+ end
43
+ end
44
+
45
+ def end_of_occurrence(date_time)
46
+ date_time.end_of_month
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,31 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ class OccurrenceIncrementer # :nodoc:
7
+ class ByMonthdayIncrementer < ByNumberedDayIncrementer #:nodoc:
8
+ def self.for_rrule(rrule)
9
+ conditional_incrementer(rrule, :bymonthday, DailyIncrementer)
10
+ end
11
+
12
+ def scope_of(date_time)
13
+ date_time.month
14
+ end
15
+
16
+ def start_of_cycle(date_time)
17
+ date_time.change(:day => 1)
18
+ end
19
+
20
+ def advance_cycle(date_time)
21
+ first_day_of_month(advance_month(date_time))
22
+ end
23
+
24
+ def end_of_occurrence(date_time)
25
+ date_time.end_of_day
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,38 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ class OccurrenceIncrementer # :nodoc:
7
+ class ByNumberedDayIncrementer < ListIncrementer #:nodoc:
8
+
9
+ def daily_incrementer?
10
+ true
11
+ end
12
+
13
+ def unneeded?(candidate)
14
+ list.length == 1 && list.first.fixed_day?
15
+ end
16
+
17
+ def occurrences_for(date_time)
18
+ if occurrences && @scoping_value == scope_of(date_time)
19
+ occurrences
20
+ else
21
+ @scoping_value = scope_of(date_time)
22
+ self.occurrences = list.map {|numbered_day| numbered_day.target_date_time_for(date_time)}.uniq.sort
23
+ occurrences
24
+ end
25
+ end
26
+
27
+ def end_of_occurrence(date_time)
28
+ date_time.end_of_day
29
+ end
30
+
31
+ def candidate_acceptable?(candidate)
32
+ list.any? {|by_part| by_part.include?(candidate)}
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,32 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ class OccurrenceIncrementer # :nodoc:
7
+ class BySecondIncrementer < ListIncrementer #:nodoc:
8
+
9
+ def self.for_rrule(rrule)
10
+ conditional_incrementer(rrule, :bysecond, SecondlyIncrementer)
11
+ end
12
+
13
+ def varying_time_attribute
14
+ :sec
15
+ end
16
+
17
+ def start_of_cycle(date_time)
18
+ date_time.start_of_minute
19
+ end
20
+
21
+ def advance_cycle(date_time)
22
+ date_time.advance(:minutes => 1).start_of_minute
23
+ end
24
+
25
+ def end_of_occurrence(date_time)
26
+ date_time
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,69 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ class OccurrenceIncrementer # :nodoc:
7
+ class ByWeekNoIncrementer < ListIncrementer #:nodoc:
8
+ attr_reader :wkst
9
+ # include WeeklyBydayMethods
10
+
11
+ def initialize(rrule, list, sub_cycle_incrementer)
12
+ @wkst = rrule.wkst_day
13
+ super(rrule, list, sub_cycle_incrementer)
14
+ end
15
+
16
+ def self.for_rrule(rrule)
17
+ conditional_incrementer(rrule, :byweekno, WeeklyIncrementer)
18
+ end
19
+
20
+ def weeknum_incrementer?
21
+ true
22
+ end
23
+
24
+ def unneeded?(candidate)
25
+ false
26
+ end
27
+
28
+ def first_within_outer_cycle(previous_occurrence, outer_range)
29
+ new_range_start = outer_range.first
30
+ new_range_end = new_range_start.end_of_iso_year(wkst)
31
+ super(previous_occurrence, outer_range.first..new_range_end)
32
+ end
33
+
34
+ def start_of_cycle(date_time)
35
+ result = date_time.at_start_of_iso_year(wkst)
36
+ result
37
+ end
38
+
39
+ def occurrences_for(date_time)
40
+ iso_year, year_start = *date_time.iso_year_and_week_one_start(wkst)
41
+ week_one_occurrence = date_time.change(
42
+ :year => year_start.year,
43
+ :month => year_start.month,
44
+ :day => year_start.day
45
+ )
46
+ weeks_in_year_plus_one = week_one_occurrence.iso_weeks_in_year(wkst)
47
+ weeks = list.map {|recurring_weeknum|
48
+ wk_num = recurring_weeknum.ordinal
49
+ (wk_num > 0) ? wk_num : weeks_in_year_plus_one + wk_num
50
+ }.uniq.sort
51
+ weeks.map {|wk_num| week_one_occurrence.advance(:days => (wk_num - 1) * 7)}
52
+ end
53
+
54
+ def candidate_acceptable?(candidate)
55
+ list.include?(candidate.iso_week_num(wkst))
56
+ end
57
+
58
+ def advance_cycle(date_time)
59
+ date_time.at_start_of_next_iso_year(wkst)
60
+ end
61
+
62
+ def end_of_occurrence(date_time)
63
+ date_time.end_of_week_with_wkst(wkst)
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,31 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ class OccurrenceIncrementer # :nodoc:
7
+ class ByYeardayIncrementer < ByNumberedDayIncrementer #:nodoc:
8
+ def self.for_rrule(rrule)
9
+ conditional_incrementer(rrule, :byyearday, ByMonthdayIncrementer)
10
+ end
11
+
12
+ def start_of_cycle(date_time)
13
+ date_time.change(:month => 1, :day => 1)
14
+ end
15
+
16
+ def scope_of(date_time)
17
+ date_time.year
18
+ end
19
+
20
+ def advance_cycle(date_time)
21
+ first_day_of_year(advance_year(date_time))
22
+ end
23
+
24
+ def end_of_occurrence(date_time)
25
+ date_time.end_of_day
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,28 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ class OccurrenceIncrementer # :nodoc:
7
+ class DailyIncrementer < FrequencyIncrementer #:nodoc:
8
+
9
+ def self.for_rrule(rrule)
10
+ conditional_incrementer(rrule, "DAILY", OccurrenceIncrementer::ByHourIncrementer)
11
+ end
12
+
13
+ def daily_incrementer?
14
+ true
15
+ end
16
+
17
+ def advance_what
18
+ :days
19
+ end
20
+
21
+ def end_of_occurrence(date_time)
22
+ date_time.end_of_day
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,80 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ class OccurrenceIncrementer # :nodoc:
7
+
8
+ # A FrequenceIncrementer represents the xxxLY and FREQ parts of a recurrence rule
9
+ # A FrequenceIncrementer has a single occurrence within each cycle.
10
+ class FrequencyIncrementer < OccurrenceIncrementer #:nodoc:
11
+ attr_accessor :interval, :outer_occurrence, :skip_increment
12
+
13
+ alias_method :cycle_start, :current_occurrence
14
+
15
+ def initialize(rrule, sub_cycle_incrementer)
16
+ super(rrule, sub_cycle_incrementer)
17
+ self.interval = rrule.interval
18
+ end
19
+
20
+ def self.conditional_incrementer(rrule, freq_str, sub_cycle_class)
21
+ sub_cycle_incrementer = sub_cycle_class.for_rrule(rrule)
22
+ if rrule.freq == freq_str
23
+ new(rrule, sub_cycle_incrementer)
24
+ else
25
+ sub_cycle_incrementer
26
+ end
27
+ end
28
+
29
+ def multiplier
30
+ 1
31
+ end
32
+
33
+ def step(occurrence)
34
+ occurrence.advance(advance_what => (interval * multiplier))
35
+ end
36
+
37
+ def sub_cycle_incrementer
38
+ if @sub_cycle_incrementer.unneeded?(current_occurrence || @previous_occurrence)
39
+ NullSubCycleIncrementer
40
+ else
41
+ super
42
+ end
43
+ end
44
+
45
+ def first_within_outer_cycle(previous_occurrence, outer_cycle_range)
46
+ if outer_range
47
+ first_occurrence = outer_cycle_range.first
48
+ else
49
+ first_occurrence = step(previous_occurrence)
50
+ end
51
+ self.outer_range = outer_cycle_range
52
+ sub_cycle_incrementer.first_within_outer_cycle(previous_occurrence, update_cycle_range(first_occurrence))
53
+ end
54
+
55
+ # Advance to the next occurrence, if the result is within the current cycles of all outer incrementers
56
+ def next_cycle(previous_occurrence)
57
+ @sub_cycle_dtstart = previous_occurrence
58
+ if current_occurrence
59
+ candidate = sub_cycle_incrementer.cycle_adjust(step(current_occurrence))
60
+ else
61
+ candidate = step(previous_occurrence)
62
+ end
63
+ if outermost?
64
+ sub_occurrence = sub_cycle_incrementer.first_within_outer_cycle(previous_occurrence, update_cycle_range(candidate))
65
+ until sub_occurrence
66
+ candidate = sub_cycle_incrementer.cycle_adjust(step(candidate))
67
+ sub_occurrence = sub_cycle_incrementer.first_within_outer_cycle(previous_occurrence, update_cycle_range(candidate))
68
+ end
69
+ sub_occurrence
70
+ elsif in_outer_cycle?(candidate)
71
+ sub_cycle_incrementer.first_within_outer_cycle(previous_occurrence, update_cycle_range(candidate))
72
+ else
73
+ nil
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,23 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ class OccurrenceIncrementer # :nodoc:
7
+ class HourlyIncrementer < FrequencyIncrementer #:nodoc:
8
+ def self.for_rrule(rrule)
9
+ conditional_incrementer(rrule, "HOURLY", ByMinuteIncrementer)
10
+ end
11
+
12
+ def advance_what
13
+ :hours
14
+ end
15
+
16
+ def end_of_occurrence(date_time)
17
+ date_time.end_of_hour
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,106 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ class OccurrenceIncrementer # :nodoc:
7
+
8
+ # A ListIncrementer represents a byxxx part of a recurrence rule
9
+ # It contains a list of simple values or recurring values
10
+ # It keeps a collection of occurrences within a given range called a cycle
11
+ # When the collection of occurrences is exhausted it is refreshed if there is no
12
+ # outer incrementer, or if a new cycle would start in the current cycle of the outer incrementers.
13
+ class ListIncrementer < OccurrenceIncrementer #:nodoc:
14
+ attr_accessor :occurrences, :list, :outer_occurrence, :cycle_start
15
+
16
+ def initialize(rrule, list, sub_cycle_incrementer)
17
+ super(rrule, sub_cycle_incrementer)
18
+ self.list = list
19
+ end
20
+
21
+ def self.conditional_incrementer(rrule, by_part, sub_cycle_class)
22
+ sub_cycle_incrementer = sub_cycle_class.for_rrule(rrule)
23
+ list = rrule.by_rule_list(by_part)
24
+ if list
25
+ new(rrule, list, sub_cycle_incrementer)
26
+ else
27
+ sub_cycle_incrementer
28
+ end
29
+ end
30
+
31
+ # Advance to the next occurrence, if the result is within the current cycles of all outer incrementers
32
+ def next_cycle(previous_occurrence)
33
+ unless occurrences
34
+ self.occurrences = occurrences_for(previous_occurrence)
35
+ end
36
+ candidate = next_candidate(previous_occurrence)
37
+ if candidate
38
+ sub_cycle_incrementer.first_within_outer_cycle(previous_occurrence, update_cycle_range(candidate))
39
+ else
40
+ nil
41
+ end
42
+ end
43
+
44
+ def unneeded?(candidate)
45
+ sub_cycle_incrementer.unneeded?(candidate) &&
46
+ list.length == 1 &&
47
+ candidate_acceptable?(candidate)
48
+ end
49
+
50
+ def candidate_acceptable?(candidate)
51
+ list.any? {|value| candidate.send(varying_time_attribute) == value}
52
+ end
53
+
54
+ def first_within_outer_cycle(previous_occurrence, outer_range)
55
+ self.outer_range = outer_range
56
+ self.occurrences = occurrences_within(outer_range)
57
+ occurrences.each { |occurrence|
58
+ sub = sub_cycle_incrementer.first_within_outer_cycle(previous_occurrence, update_cycle_range(occurrence))
59
+ return sub if sub && sub > previous_occurrence
60
+ }
61
+ nil
62
+ end
63
+
64
+ def next_candidate(date_time)
65
+ candidate = next_in_list(date_time)
66
+ if outermost?
67
+ while candidate.nil?
68
+ get_next_occurrences
69
+ candidate = next_in_list(date_time)
70
+ end
71
+ end
72
+ candidate
73
+ end
74
+
75
+ def next_in_list(date_time)
76
+ occurrences.find {|occurrence| occurrence > date_time}
77
+ end
78
+
79
+ def get_next_occurrences
80
+ adv_cycle = advance_cycle(start_of_cycle(occurrences.first))
81
+ self.occurrences = occurrences_for(adv_cycle)
82
+ end
83
+
84
+ def cycle_adjust(date_time)
85
+ sub_cycle_incrementer.cycle_adjust(start_of_cycle(date_time))
86
+ end
87
+
88
+ def occurrences_for(date_time)
89
+ list.map {|value| date_time.change(varying_time_attribute => value)}
90
+ end
91
+
92
+ def occurrences_within(date_time_range)
93
+ result = []
94
+ date_time = date_time_range.first
95
+ while date_time <= date_time_range.last
96
+ result << occurrences_for(date_time)
97
+ date_time = advance_cycle(date_time)
98
+ end
99
+ result.flatten
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+
@@ -0,0 +1,23 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ class OccurrenceIncrementer # :nodoc:
7
+ class MinutelyIncrementer < FrequencyIncrementer #:nodoc:
8
+ def self.for_rrule(rrule)
9
+ conditional_incrementer(rrule, "MINUTELY", BySecondIncrementer)
10
+ end
11
+
12
+ def advance_what
13
+ :minutes
14
+ end
15
+
16
+ def end_of_occurrence(date_time)
17
+ date_time.end_of_minute
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,33 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ class OccurrenceIncrementer # :nodoc:
7
+ class MonthlyIncrementer < FrequencyIncrementer #:nodoc:
8
+
9
+ def self.for_rrule(rrule)
10
+ conditional_incrementer(rrule, "MONTHLY", ByWeekNoIncrementer)
11
+ end
12
+
13
+ def advance_what
14
+ :months
15
+ end
16
+
17
+ def step(date_time)
18
+ if contains_daily_incrementer?
19
+ result = super(date_time).change(:day => 1)
20
+ result
21
+ else
22
+ super(date_time)
23
+ end
24
+ end
25
+
26
+ def end_of_occurrence(date_time)
27
+ date_time.end_of_month
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,43 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ class OccurrenceIncrementer # :nodoc:
5
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
6
+ #
7
+ class NullSubCycleIncrementer #:nodoc:
8
+ def self.next_time(previous)
9
+ nil
10
+ end
11
+
12
+ def self.add_outer_incrementer(incrementer)
13
+ end
14
+
15
+ def self.unneeded?(candidate)
16
+ true
17
+ end
18
+
19
+ def self.first_within_outer_cycle(previous_occurrence, outer_cycle_range)
20
+ outer_cycle_range.first
21
+ end
22
+
23
+ def self.first_sub_occurrence(previous_occurrence, outer_cycle_range)
24
+ nil
25
+ end
26
+
27
+ def self.cycle_adjust(date_time)
28
+ date_time
29
+ end
30
+
31
+ def self.to_s
32
+ "NULL-INCR"
33
+ end
34
+
35
+ def inspect
36
+ to_s
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
@@ -0,0 +1,28 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ class OccurrenceIncrementer # :nodoc:
7
+ class SecondlyIncrementer < FrequencyIncrementer #:nodoc:
8
+
9
+ def self.for_rrule(rrule)
10
+ if rrule.freq == "SECONDLY"
11
+ new(rrule, nil)
12
+ else
13
+ nil
14
+ end
15
+ end
16
+
17
+ def advance_what
18
+ :seconds
19
+ end
20
+
21
+ def end_of_occurrence(date_time)
22
+ date_time
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,37 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class RecurrenceRule < PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ class OccurrenceIncrementer # :nodoc:
7
+ class WeeklyIncrementer < FrequencyIncrementer #:nodoc:
8
+
9
+ attr_reader :wkst
10
+
11
+ # include WeeklyBydayMethods
12
+
13
+ def initialize(rrule, parent)
14
+ @wkst = rrule.wkst_day
15
+ super(rrule, parent)
16
+ end
17
+
18
+ def self.for_rrule(rrule)
19
+ conditional_incrementer(rrule, "WEEKLY", ByDayIncrementer)
20
+ end
21
+
22
+ def multiplier
23
+ 7
24
+ end
25
+
26
+ def advance_what
27
+ :days
28
+ end
29
+
30
+ def end_of_occurrence(date_time)
31
+ date_time.end_of_week_with_wkst(wkst)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end