ri_cal 0.5.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/History.txt +45 -0
- data/Manifest.txt +129 -0
- data/README.txt +394 -0
- data/Rakefile +31 -0
- data/bin/ri_cal +8 -0
- data/component_attributes/alarm.yml +10 -0
- data/component_attributes/calendar.yml +4 -0
- data/component_attributes/component_property_defs.yml +180 -0
- data/component_attributes/event.yml +45 -0
- data/component_attributes/freebusy.yml +16 -0
- data/component_attributes/journal.yml +35 -0
- data/component_attributes/timezone.yml +3 -0
- data/component_attributes/timezone_period.yml +11 -0
- data/component_attributes/todo.yml +46 -0
- data/copyrights.txt +1 -0
- data/docs/draft-ietf-calsify-2446bis-08.txt +7280 -0
- data/docs/draft-ietf-calsify-rfc2445bis-09.txt +10416 -0
- data/docs/incrementers.txt +7 -0
- data/docs/rfc2445.pdf +0 -0
- data/lib/ri_cal.rb +144 -0
- data/lib/ri_cal/component.rb +247 -0
- data/lib/ri_cal/component/alarm.rb +21 -0
- data/lib/ri_cal/component/calendar.rb +219 -0
- data/lib/ri_cal/component/event.rb +60 -0
- data/lib/ri_cal/component/freebusy.rb +18 -0
- data/lib/ri_cal/component/journal.rb +30 -0
- data/lib/ri_cal/component/t_z_info_timezone.rb +123 -0
- data/lib/ri_cal/component/timezone.rb +196 -0
- data/lib/ri_cal/component/timezone/daylight_period.rb +25 -0
- data/lib/ri_cal/component/timezone/standard_period.rb +23 -0
- data/lib/ri_cal/component/timezone/timezone_period.rb +53 -0
- data/lib/ri_cal/component/todo.rb +43 -0
- data/lib/ri_cal/core_extensions.rb +6 -0
- data/lib/ri_cal/core_extensions/array.rb +7 -0
- data/lib/ri_cal/core_extensions/array/conversions.rb +15 -0
- data/lib/ri_cal/core_extensions/date.rb +13 -0
- data/lib/ri_cal/core_extensions/date/conversions.rb +61 -0
- data/lib/ri_cal/core_extensions/date_time.rb +15 -0
- data/lib/ri_cal/core_extensions/date_time/conversions.rb +50 -0
- data/lib/ri_cal/core_extensions/object.rb +8 -0
- data/lib/ri_cal/core_extensions/object/conversions.rb +20 -0
- data/lib/ri_cal/core_extensions/string.rb +8 -0
- data/lib/ri_cal/core_extensions/string/conversions.rb +63 -0
- data/lib/ri_cal/core_extensions/time.rb +13 -0
- data/lib/ri_cal/core_extensions/time/calculations.rb +153 -0
- data/lib/ri_cal/core_extensions/time/conversions.rb +61 -0
- data/lib/ri_cal/core_extensions/time/tzid_access.rb +50 -0
- data/lib/ri_cal/core_extensions/time/week_day_predicates.rb +88 -0
- data/lib/ri_cal/floating_timezone.rb +32 -0
- data/lib/ri_cal/invalid_property_value.rb +8 -0
- data/lib/ri_cal/invalid_timezone_identifer.rb +20 -0
- data/lib/ri_cal/occurrence_enumerator.rb +206 -0
- data/lib/ri_cal/occurrence_period.rb +17 -0
- data/lib/ri_cal/parser.rb +138 -0
- data/lib/ri_cal/properties/alarm.rb +390 -0
- data/lib/ri_cal/properties/calendar.rb +164 -0
- data/lib/ri_cal/properties/event.rb +1526 -0
- data/lib/ri_cal/properties/freebusy.rb +594 -0
- data/lib/ri_cal/properties/journal.rb +1240 -0
- data/lib/ri_cal/properties/timezone.rb +151 -0
- data/lib/ri_cal/properties/timezone_period.rb +416 -0
- data/lib/ri_cal/properties/todo.rb +1562 -0
- data/lib/ri_cal/property_value.rb +149 -0
- data/lib/ri_cal/property_value/array.rb +27 -0
- data/lib/ri_cal/property_value/cal_address.rb +11 -0
- data/lib/ri_cal/property_value/date.rb +175 -0
- data/lib/ri_cal/property_value/date_time.rb +335 -0
- data/lib/ri_cal/property_value/date_time/additive_methods.rb +44 -0
- data/lib/ri_cal/property_value/date_time/time_machine.rb +181 -0
- data/lib/ri_cal/property_value/date_time/timezone_support.rb +96 -0
- data/lib/ri_cal/property_value/duration.rb +110 -0
- data/lib/ri_cal/property_value/geo.rb +11 -0
- data/lib/ri_cal/property_value/integer.rb +12 -0
- data/lib/ri_cal/property_value/occurrence_list.rb +144 -0
- data/lib/ri_cal/property_value/period.rb +82 -0
- data/lib/ri_cal/property_value/recurrence_rule.rb +145 -0
- data/lib/ri_cal/property_value/recurrence_rule/enumeration_support_methods.rb +97 -0
- data/lib/ri_cal/property_value/recurrence_rule/enumerator.rb +79 -0
- data/lib/ri_cal/property_value/recurrence_rule/initialization_methods.rb +148 -0
- data/lib/ri_cal/property_value/recurrence_rule/negative_setpos_enumerator.rb +53 -0
- data/lib/ri_cal/property_value/recurrence_rule/numbered_span.rb +31 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurence_incrementer.rb +793 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_day.rb +131 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_month_day.rb +60 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_numbered_week.rb +33 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_year_day.rb +49 -0
- data/lib/ri_cal/property_value/recurrence_rule/validations.rb +125 -0
- data/lib/ri_cal/property_value/text.rb +40 -0
- data/lib/ri_cal/property_value/uri.rb +11 -0
- data/lib/ri_cal/property_value/utc_offset.rb +33 -0
- data/lib/ri_cal/required_timezones.rb +55 -0
- data/ri_cal.gemspec +49 -0
- data/sample_ical_files/from_ical_dot_app/test1.ics +38 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +71 -0
- data/spec/ri_cal/component/alarm_spec.rb +12 -0
- data/spec/ri_cal/component/calendar_spec.rb +54 -0
- data/spec/ri_cal/component/event_spec.rb +601 -0
- data/spec/ri_cal/component/freebusy_spec.rb +12 -0
- data/spec/ri_cal/component/journal_spec.rb +37 -0
- data/spec/ri_cal/component/t_z_info_timezone_spec.rb +36 -0
- data/spec/ri_cal/component/timezone_spec.rb +218 -0
- data/spec/ri_cal/component/todo_spec.rb +112 -0
- data/spec/ri_cal/component_spec.rb +224 -0
- data/spec/ri_cal/core_extensions/string/conversions_spec.rb +78 -0
- data/spec/ri_cal/core_extensions/time/calculations_spec.rb +188 -0
- data/spec/ri_cal/core_extensions/time/week_day_predicates_spec.rb +45 -0
- data/spec/ri_cal/occurrence_enumerator_spec.rb +573 -0
- data/spec/ri_cal/parser_spec.rb +303 -0
- data/spec/ri_cal/property_value/date_spec.rb +53 -0
- data/spec/ri_cal/property_value/date_time_spec.rb +383 -0
- data/spec/ri_cal/property_value/duration_spec.rb +126 -0
- data/spec/ri_cal/property_value/occurrence_list_spec.rb +72 -0
- data/spec/ri_cal/property_value/period_spec.rb +49 -0
- data/spec/ri_cal/property_value/recurrence_rule/recurring_year_day_spec.rb +21 -0
- data/spec/ri_cal/property_value/recurrence_rule_spec.rb +1814 -0
- data/spec/ri_cal/property_value/text_spec.rb +25 -0
- data/spec/ri_cal/property_value/utc_offset_spec.rb +48 -0
- data/spec/ri_cal/property_value_spec.rb +125 -0
- data/spec/ri_cal/required_timezones_spec.rb +67 -0
- data/spec/ri_cal_spec.rb +53 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +46 -0
- data/tasks/gem_loader/load_active_support.rb +3 -0
- data/tasks/gem_loader/load_tzinfo_gem.rb +2 -0
- data/tasks/ri_cal.rake +410 -0
- data/tasks/spec.rake +50 -0
- metadata +221 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
module RiCal
|
|
2
|
+
class PropertyValue
|
|
3
|
+
# OccurrenceList is used to represent the value of an RDATE or EXDATE property.
|
|
4
|
+
#- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
|
|
5
|
+
#
|
|
6
|
+
class OccurrenceList < Array
|
|
7
|
+
attr_accessor :tzid #:nodoc:
|
|
8
|
+
|
|
9
|
+
class Enumerator # :nodoc:
|
|
10
|
+
|
|
11
|
+
attr_accessor :default_duration, :occurrence_list
|
|
12
|
+
|
|
13
|
+
# TODO: the component parameter should always be the parent
|
|
14
|
+
def initialize(occurrences, component) # :nodoc:
|
|
15
|
+
self.occurrence_list = occurrences
|
|
16
|
+
self.default_duration = component.default_duration
|
|
17
|
+
@index = 0
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def bounded?
|
|
21
|
+
true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def empty?
|
|
25
|
+
occurrence_list.empty?
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def next_occurrence
|
|
29
|
+
if @index < occurrence_list.length
|
|
30
|
+
result = occurrence_list[@index].occurrence_period(default_duration)
|
|
31
|
+
@index += 1
|
|
32
|
+
result
|
|
33
|
+
else
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def initialize(timezone_finder, options={}) # :nodoc:
|
|
40
|
+
super
|
|
41
|
+
validate_elements
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.convert(timezone_finder, *ruby_objects) # :nodoc:
|
|
45
|
+
# ruby_objects = [ruby_objects] unless Array === ruby_objects
|
|
46
|
+
source_elements = ruby_objects.inject([]) { |se, element|
|
|
47
|
+
if String === element
|
|
48
|
+
element.split(",").each {|str| se << str}
|
|
49
|
+
else
|
|
50
|
+
se << element
|
|
51
|
+
end
|
|
52
|
+
se
|
|
53
|
+
}
|
|
54
|
+
new(timezone_finder, :source_elements => source_elements )
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def values_to_elements(values) # :nodoc:
|
|
58
|
+
values.map {|val| val.to_ri_cal_occurrence_list_value(self)}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def tzid_from_source_elements # :nodoc:
|
|
62
|
+
if @source_elements && String === (first_source = @source_elements.first)
|
|
63
|
+
probe = first_source.to_ri_cal_occurrence_list_value rescue nil
|
|
64
|
+
unless probe
|
|
65
|
+
return @source_elements.shift
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def tzid_conflict(element_tzid) # :nodoc:
|
|
72
|
+
element_tzid && tzid != element_tzid
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def validate_elements # :nodoc:
|
|
76
|
+
if @source_elements
|
|
77
|
+
self.tzid = tzid_from_source_elements
|
|
78
|
+
@elements = values_to_elements(@source_elements)
|
|
79
|
+
@value = @elements.map {|prop| prop.value}
|
|
80
|
+
else
|
|
81
|
+
@elements = values_to_elements(@value)
|
|
82
|
+
self.tzid = params['TZID']
|
|
83
|
+
end
|
|
84
|
+
# if the tzid wasn't set by the parameters
|
|
85
|
+
self.tzid ||= @elements.map {|element| element.tzid}.find {|id| id}
|
|
86
|
+
@elements.each do |element|
|
|
87
|
+
raise InvalidPropertyValue.new("Mixed timezones are not allowed in an occurrence list") if tzid_conflict(element.tzid)
|
|
88
|
+
element.tzid = tzid
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def has_local_timezone? # :nodoc:
|
|
93
|
+
tzid && tzid != 'UTC'
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def visible_params # :nodoc:
|
|
97
|
+
result = params.dup
|
|
98
|
+
if has_local_timezone?
|
|
99
|
+
result['TZID'] = tzid
|
|
100
|
+
else
|
|
101
|
+
result.delete('TZID')
|
|
102
|
+
end
|
|
103
|
+
result
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def value # :nodoc:
|
|
107
|
+
@elements.map {|element| element.value}.join(",")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Return an array of the occurrences within the list
|
|
111
|
+
def ruby_value
|
|
112
|
+
@elements.map {|prop| prop.ruby_value}
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
attr_accessor :elements, :source_elements #:nodoc:
|
|
117
|
+
private :elements, :elements=, :source_elements=, :source_elements
|
|
118
|
+
|
|
119
|
+
def for_parent(parent) #:nodoc:
|
|
120
|
+
if timezone_finder.nil?
|
|
121
|
+
@timezone_finder = parent
|
|
122
|
+
self
|
|
123
|
+
elsif timezone_finder == parent
|
|
124
|
+
self
|
|
125
|
+
else
|
|
126
|
+
OccurrenceList.new(parent, :value => value)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Return an enumerator which can produce the elements of the occurrence list
|
|
131
|
+
def enumerator(component) # :nodoc:
|
|
132
|
+
OccurrenceList::Enumerator.new(@elements, component)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def add_date_times_to(required_timezones) #:nodoc:
|
|
136
|
+
if @elements
|
|
137
|
+
@elements.each do | occurrence |
|
|
138
|
+
occurrence.add_date_times_to(required_timezones)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
end
|
|
144
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module RiCal
|
|
2
|
+
class PropertyValue
|
|
3
|
+
#- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
|
|
4
|
+
#
|
|
5
|
+
# RiCal::PropertyValue::CalAddress represents an icalendar Period property value
|
|
6
|
+
# which is defined in
|
|
7
|
+
# rfc 2445 section 4.3.9 p 39
|
|
8
|
+
#
|
|
9
|
+
# Known bugs. This doesn't properly work when dtstart, dtend or duration are changed independently
|
|
10
|
+
class Period < PropertyValue
|
|
11
|
+
|
|
12
|
+
# The DATE-TIME on which the period starts
|
|
13
|
+
attr_accessor :dtstart
|
|
14
|
+
# The DATE-TIME on which the period ends
|
|
15
|
+
attr_accessor :dtend
|
|
16
|
+
# The DURATION of the period
|
|
17
|
+
attr_accessor :duration
|
|
18
|
+
|
|
19
|
+
def value=(string) # :nodoc:
|
|
20
|
+
starter, terminator = *string.split("/")
|
|
21
|
+
self.dtstart = PropertyValue::DateTime.new(self, :value => starter)
|
|
22
|
+
if /P/ =~ terminator
|
|
23
|
+
self.duration = PropertyValue::Duration.new(self, :value => terminator)
|
|
24
|
+
self.dtend = dtstart + duration
|
|
25
|
+
else
|
|
26
|
+
self.dtend = PropertyValue::DateTime.new(self, :value => terminator)
|
|
27
|
+
self.duration = PropertyValue::Duration.from_datetimes(self, dtstart.to_datetime, dtend.to_datetime)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def self.valid_string?(string) # :nodoc:
|
|
33
|
+
return false unless string.include?("/")
|
|
34
|
+
starter, terminator = *string.split("/")
|
|
35
|
+
return false unless PropertyValue::DateTime.valid_string?(starter)
|
|
36
|
+
if /P/ =~ terminator
|
|
37
|
+
return false unless PropertyValue::Duration.valid_string?(terminator)
|
|
38
|
+
else
|
|
39
|
+
return false unless PropertyValue::DateTime.valid_string?(terminator)
|
|
40
|
+
end
|
|
41
|
+
true
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Nop to allow occurrence list to try to set it
|
|
45
|
+
def tzid=(val)#:nodoc:
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def tzid #:nodoc:
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def for_parent(parent) #:nodoc:
|
|
53
|
+
if timezone_finder.nil
|
|
54
|
+
@timezone_finder = parent
|
|
55
|
+
self
|
|
56
|
+
elsif timezone_finder == parent
|
|
57
|
+
self
|
|
58
|
+
else
|
|
59
|
+
Period.new(parent, :value => value)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.convert(parent, ruby_object) # :nodoc:
|
|
64
|
+
ruby_object.to_ri_cal_period_value.for_parent(parent)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# return the receiver
|
|
68
|
+
def to_ri_cal_period_value
|
|
69
|
+
self
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def occurrence_period(default_duration) #:nodoc:
|
|
73
|
+
RiCal::OccurrencePeriod.new(self, (default_duration ? self + default_duration : nil))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def add_date_times_to(required_timezones) #:nodoc:
|
|
77
|
+
dtstart.add_date_times_to(required_timezones)
|
|
78
|
+
dtend.add_date_times_to(required_timezones)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
Dir[File.dirname(__FILE__) + "/recurrence_rule/*.rb"].sort.each do |path|
|
|
2
|
+
require path
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
module RiCal
|
|
6
|
+
class PropertyValue
|
|
7
|
+
#- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
|
|
8
|
+
#
|
|
9
|
+
# RiCal::PropertyValue::RecurrenceRule represents an icalendar Recurrence Rule property value
|
|
10
|
+
# which is defined in
|
|
11
|
+
# rfc 2445 section 4.3.10 pp 40-45
|
|
12
|
+
class RecurrenceRule < PropertyValue
|
|
13
|
+
|
|
14
|
+
def initialize(parent, value_hash) # :nodoc:
|
|
15
|
+
@by_list_hash = {}
|
|
16
|
+
super
|
|
17
|
+
init_by_lists
|
|
18
|
+
@by_list_hash = nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.convert(parent, value) #:nodoc:
|
|
22
|
+
if String === value
|
|
23
|
+
result = new(parent, :value => value)
|
|
24
|
+
else
|
|
25
|
+
result = new(parent, value)
|
|
26
|
+
end
|
|
27
|
+
result
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
include Validations
|
|
31
|
+
include InitializationMethods
|
|
32
|
+
include EnumerationSupportMethods
|
|
33
|
+
|
|
34
|
+
# The integer count value of the receiver, or nil
|
|
35
|
+
attr_reader :count
|
|
36
|
+
# The DATE-TIME value of until limit of the receiver, or nil
|
|
37
|
+
attr_reader :until
|
|
38
|
+
|
|
39
|
+
def value=(string) # :nodoc:
|
|
40
|
+
if string
|
|
41
|
+
@value = string
|
|
42
|
+
dup_hash = {}
|
|
43
|
+
string.split(";").each do |value_part|
|
|
44
|
+
initialize_from_value_part(value_part, dup_hash)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Set the frequency of the recurrence rule
|
|
50
|
+
# freq_value:: a String which should be in %w[SECONDLY MINUTELY HOURLY DAILY WEEKLY MONTHLY YEARLY]
|
|
51
|
+
#
|
|
52
|
+
# This method resets the receivers list of errors
|
|
53
|
+
def freq=(freq_value)
|
|
54
|
+
reset_errors
|
|
55
|
+
@freq = freq_value
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# return the frequency of the rule which will be a string
|
|
59
|
+
def freq
|
|
60
|
+
@freq.upcase
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# return the starting week day for the recurrence rule, which for a valid instance will be one of
|
|
64
|
+
# "SU", "MO", "TU", "WE", "TH", "FR", or "SA"
|
|
65
|
+
def wkst
|
|
66
|
+
@wkst || 'MO'
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def wkst_day # :nodoc:
|
|
70
|
+
@wkst_day ||= (%w{SU MO TU WE FR SA}.index(wkst) || 1)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Set the starting week day for the recurrence rule, which should be one of
|
|
74
|
+
# "SU", "MO", "TU", "WE", "TH", "FR", or "SA" for the instance to be valid.
|
|
75
|
+
# The parameter is however case-insensitive.
|
|
76
|
+
#
|
|
77
|
+
# This method resets the receivers list of errors
|
|
78
|
+
def wkst=(value)
|
|
79
|
+
reset_errors
|
|
80
|
+
@wkst = value
|
|
81
|
+
@wkst_day = nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Set the count parameter of the recurrence rule, the count value will be converted to an integer using to_i
|
|
85
|
+
#
|
|
86
|
+
# This method resets the receivers list of errors
|
|
87
|
+
|
|
88
|
+
def count=(count_value)
|
|
89
|
+
reset_errors
|
|
90
|
+
@count = count_value
|
|
91
|
+
@until = nil unless @count.nil? || @by_list_hash
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Set the until parameter of the recurrence rule
|
|
95
|
+
#
|
|
96
|
+
# until_value:: the value to be set, this may be either a string in RFC 2446 Date or DateTime value format
|
|
97
|
+
# Or a Date, Time, DateTime, RiCal::PropertyValue::Date, or RiCal::PropertyValue::DateTime
|
|
98
|
+
#
|
|
99
|
+
def until=(until_value)
|
|
100
|
+
reset_errors
|
|
101
|
+
@until = until_value && until_value.to_ri_cal_date_or_date_time_value(timezone_finder)
|
|
102
|
+
@count = nil unless @count.nil? || @by_list_hash
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# return the INTERVAL parameter of the recurrence rule
|
|
106
|
+
# This returns an Integer
|
|
107
|
+
def interval
|
|
108
|
+
@interval ||= 1
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Set the INTERVAL parameter of the recurrence rule
|
|
112
|
+
#
|
|
113
|
+
# interval_value:: an Integer
|
|
114
|
+
#
|
|
115
|
+
# This method resets the receivers list of errors
|
|
116
|
+
def interval=(interval_value)
|
|
117
|
+
reset_errors
|
|
118
|
+
@interval = interval_value
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def value #:nodoc:
|
|
122
|
+
@value || to_ical
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Return a string containing the RFC 2445 representation of the recurrence rule
|
|
126
|
+
def to_ical
|
|
127
|
+
result = ["FREQ=#{freq}"]
|
|
128
|
+
result << "INTERVAL=#{interval}" unless interval == 1
|
|
129
|
+
result << "COUNT=#{count}" if count
|
|
130
|
+
result << "UNTIL=#{self.until.value}" if self.until
|
|
131
|
+
%w{bysecond byminute byhour byday bymonthday byyearday byweekno bymonth bysetpos}.each do |by_part|
|
|
132
|
+
val = by_list[by_part.to_sym]
|
|
133
|
+
result << "#{by_part.upcase}=#{[val].flatten.join(',')}" if val
|
|
134
|
+
end
|
|
135
|
+
result << "WKST=#{wkst}" unless wkst == "MO"
|
|
136
|
+
result.join(";")
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Predicate to determine if the receiver generates a bounded or infinite set of occurrences
|
|
140
|
+
def bounded?
|
|
141
|
+
@count || @until
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
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
|
+
module EnumerationSupportMethods # :nodoc:
|
|
7
|
+
|
|
8
|
+
# if the recurrence rule has a bysetpos part we need to search starting with the
|
|
9
|
+
# first time in the frequency period containing the start time specified by DTSTART
|
|
10
|
+
def adjust_start(start_time) # :nodoc:
|
|
11
|
+
if by_list[:bysetpos]
|
|
12
|
+
case freq
|
|
13
|
+
when "SECONDLY"
|
|
14
|
+
start_time
|
|
15
|
+
when "MINUTELY"
|
|
16
|
+
start_time.change(:seconds => 0)
|
|
17
|
+
when "HOURLY"
|
|
18
|
+
start_time.change(
|
|
19
|
+
:minutes => 0,
|
|
20
|
+
:seconds => start_time.sec
|
|
21
|
+
)
|
|
22
|
+
when "DAILY"
|
|
23
|
+
start_time.change(
|
|
24
|
+
:hour => 0,
|
|
25
|
+
:minutes => start_time.min,
|
|
26
|
+
:seconds => start_time.sec
|
|
27
|
+
)
|
|
28
|
+
when "WEEKLY"
|
|
29
|
+
start_of_week(time)
|
|
30
|
+
when "MONTHLY"
|
|
31
|
+
start_time.change(
|
|
32
|
+
:day => 1,
|
|
33
|
+
:hour => start_time.hour,
|
|
34
|
+
:minutes => start_time.min,
|
|
35
|
+
:seconds => start_time.sec
|
|
36
|
+
)
|
|
37
|
+
when "YEARLY"
|
|
38
|
+
start_time.change(
|
|
39
|
+
:month => 1,
|
|
40
|
+
:day => start_time.day,
|
|
41
|
+
:hour => start_time.hour,
|
|
42
|
+
:minutes => start_time.min,
|
|
43
|
+
:seconds => start_time.sec
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
else
|
|
47
|
+
start_time
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def enumerator(component) # :nodoc:
|
|
52
|
+
Enumerator.for(self, component, by_list[:bysetpos])
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def exhausted?(count, time) # :nodoc:
|
|
56
|
+
(@count && count > @count) || (@until && (time > @until))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def in_same_set?(time1, time2) # :nodoc:
|
|
60
|
+
case freq
|
|
61
|
+
when "SECONDLY"
|
|
62
|
+
[time1.year, time1.month, time1.day, time1.hour, time1.min, time1.sec] ==
|
|
63
|
+
[time2.year, time2.month, time2.day, time2.hour, time2.min, time2.sec]
|
|
64
|
+
when "MINUTELY"
|
|
65
|
+
[time1.year, time1.month, time1.day, time1.hour, time1.min] ==
|
|
66
|
+
[time2.year, time2.month, time2.day, time2.hour, time2.min]
|
|
67
|
+
when "HOURLY"
|
|
68
|
+
[time1.year, time1.month, time1.day, time1.hour] ==
|
|
69
|
+
[time2.year, time2.month, time2.day, time2.hour]
|
|
70
|
+
when "DAILY"
|
|
71
|
+
[time1.year, time1.month, time1.day] ==
|
|
72
|
+
[time2.year, time2.month, time2.day]
|
|
73
|
+
when "WEEKLY"
|
|
74
|
+
sow1 = start_of_week(time1)
|
|
75
|
+
sow2 = start_of_week(time2)
|
|
76
|
+
[sow1.year, sow1.month, sow1.day] ==
|
|
77
|
+
[sow2.year, sow2.month, sow2.day]
|
|
78
|
+
when "MONTHLY"
|
|
79
|
+
[time1.year, time1.month] ==
|
|
80
|
+
[time2.year, time2.month]
|
|
81
|
+
when "YEARLY"
|
|
82
|
+
time1.year == time2.year
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def by_rule_list(which) # :nodoc:
|
|
87
|
+
if @by_list
|
|
88
|
+
@by_list[which]
|
|
89
|
+
else
|
|
90
|
+
nil
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|