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,131 @@
|
|
|
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
|
+
# Instances of RecurringDay are used to represent values in BYDAY recurrence rule parts
|
|
7
|
+
#
|
|
8
|
+
class RecurringDay # :nodoc:
|
|
9
|
+
|
|
10
|
+
attr_reader :wday, :index, :rrule
|
|
11
|
+
|
|
12
|
+
DayNames = %w{SU MO TU WE TH FR SA} unless defined? DayNames
|
|
13
|
+
day_nums = {}
|
|
14
|
+
unless defined? DayNums
|
|
15
|
+
DayNames.each_with_index { |name, i| day_nums[name] = i }
|
|
16
|
+
DayNums = day_nums
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
attr_reader :source, :scope
|
|
20
|
+
def initialize(source, rrule, scope = :monthly)
|
|
21
|
+
@source = source
|
|
22
|
+
@rrule = rrule
|
|
23
|
+
@scope = scope
|
|
24
|
+
wd_match = source.match(/([+-]?\d*)(SU|MO|TU|WE|TH|FR|SA)/)
|
|
25
|
+
if wd_match
|
|
26
|
+
@day, @ordinal = wd_match[2], wd_match[1]
|
|
27
|
+
@wday = DayNums[@day]
|
|
28
|
+
@index = (@ordinal == "") ? nil : @ordinal.to_i
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def valid?
|
|
33
|
+
!@day.nil?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def ==(another)
|
|
37
|
+
self.class === another && to_a = another.to_a
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def to_a
|
|
41
|
+
[@day, @ordinal]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# return a list id for a given time to allow the enumerator to cache lists
|
|
45
|
+
def list_id(time)
|
|
46
|
+
case @scope
|
|
47
|
+
when :yearly
|
|
48
|
+
time.year
|
|
49
|
+
when :monthly
|
|
50
|
+
(time.year * 100) + time.month
|
|
51
|
+
when :weekly
|
|
52
|
+
time.at_start_of_week_with_wkst(rrule.wkst_day).jd
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# return a list of times which match the time parameter within the scope of the RecurringDay
|
|
57
|
+
def matches_for(time)
|
|
58
|
+
case @scope
|
|
59
|
+
when :yearly
|
|
60
|
+
yearly_matches_for(time)
|
|
61
|
+
when :monthly
|
|
62
|
+
monthly_matches_for(time)
|
|
63
|
+
when :weekly
|
|
64
|
+
weekly_matches_for(time)
|
|
65
|
+
else
|
|
66
|
+
walkback = caller.grep(/recurrence/i)
|
|
67
|
+
raise "Logic error!#{@scope.inspect}\n #{walkback.join("\n ")}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def yearly_matches_for(time)
|
|
72
|
+
if @ordinal == ""
|
|
73
|
+
t = time.nth_wday_in_year(1, wday)
|
|
74
|
+
result = []
|
|
75
|
+
year = time.year
|
|
76
|
+
while t.year == year
|
|
77
|
+
result << t
|
|
78
|
+
t = t.advance(:week => 1)
|
|
79
|
+
end
|
|
80
|
+
result
|
|
81
|
+
else
|
|
82
|
+
[time.nth_wday_in_year(@ordinal.to_i, wday)]
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def monthly_matches_for(time)
|
|
87
|
+
if @ordinal == ""
|
|
88
|
+
t = time.nth_wday_in_month(1, wday)
|
|
89
|
+
result = []
|
|
90
|
+
month = time.month
|
|
91
|
+
while t.month == month
|
|
92
|
+
result << t
|
|
93
|
+
t = t.advance(:days => 7)
|
|
94
|
+
end
|
|
95
|
+
result
|
|
96
|
+
else
|
|
97
|
+
result = [time.nth_wday_in_month(index, wday)]
|
|
98
|
+
result
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def weekly_matches_for(time)
|
|
103
|
+
date = time.start_of_week_with_wkst(rrule.wkst_day)
|
|
104
|
+
date += 1 while date.wday != wday
|
|
105
|
+
[time.change(:year => date.year, :month => date.month, :day => date.day)]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def to_s
|
|
109
|
+
"#{@ordinal}#{@day}"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def ordinal_match(date_or_time)
|
|
113
|
+
if @ordinal == "" || @scope == :weekly
|
|
114
|
+
true
|
|
115
|
+
else
|
|
116
|
+
if @scope == :yearly
|
|
117
|
+
date_or_time.nth_wday_in_year?(index, wday)
|
|
118
|
+
else
|
|
119
|
+
date_or_time.nth_wday_in_month?(index, wday)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Determine if a particular date, time, or date_time is included in the recurrence
|
|
125
|
+
def include?(date_or_time)
|
|
126
|
+
date_or_time.wday == wday && ordinal_match(date_or_time)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
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
|
+
# Instances of RecurringMonthDay represent BYMONTHDAY parts in recurrence rules
|
|
7
|
+
class RecurringMonthDay < NumberedSpan # :nodoc:
|
|
8
|
+
|
|
9
|
+
def last
|
|
10
|
+
31
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# return a list id for a given time to allow the enumerator to cache lists
|
|
14
|
+
def list_id(time)
|
|
15
|
+
time.month
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# return a list of times which match the time parameter within the scope of the RecurringDay
|
|
19
|
+
def matches_for(time)
|
|
20
|
+
[time.change(:day => 1).advance(:days => target_for(time)- 1)]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# return a list id for a given time to allow the enumerator to cache lists
|
|
24
|
+
def list_id(time)
|
|
25
|
+
time.month
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# return a list of times which match the time parameter within the scope of the RecurringDay
|
|
29
|
+
def matches_for(time)
|
|
30
|
+
[time.change(:day => 1).advance(:days => target_for(time)- 1)]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def target_date_time_for(date_time)
|
|
34
|
+
matches_for(date_time)[0]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# return a list of times which match the time parameter within the scope of the RecurringDay
|
|
38
|
+
def matches_for(time)
|
|
39
|
+
[time.change(:day => 1).advance(:days => target_for(time)- 1)]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def target_date_time_for(date_time)
|
|
43
|
+
matches_for(date_time)[0]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def target_for(date_or_time)
|
|
47
|
+
if @source > 0
|
|
48
|
+
@source
|
|
49
|
+
else
|
|
50
|
+
date_or_time.days_in_month + @source + 1
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def include?(date_or_time)
|
|
55
|
+
date_or_time.mday == target_for(date_or_time)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
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 RecurringNumberedWeek < NumberedSpan # :nodoc:
|
|
7
|
+
def last
|
|
8
|
+
53
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def rule_wkst
|
|
12
|
+
@rule && rule.wkst_day
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def default_wkst
|
|
16
|
+
rule_wkst || 1
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def adjusted_iso_weeknum(date_or_time)
|
|
20
|
+
if @source > 0
|
|
21
|
+
@source
|
|
22
|
+
else
|
|
23
|
+
date_or_time.iso_weeks_in_year(wkst) + @source + 1
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def include?(date_or_time, wkst=default_wkst)
|
|
28
|
+
date_or_time.iso_week_num(wkst) == adjusted_iso_weeknum(date_or_time)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
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 RecurringYearDay < NumberedSpan # :nodoc:
|
|
7
|
+
|
|
8
|
+
def last
|
|
9
|
+
366
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def leap_year?(year)
|
|
13
|
+
year % 4 == 0 && (year % 400 == 0 || year % 100 != 0)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def length_of_year(year)
|
|
18
|
+
leap_year?(year) ? 366 : 365
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# return a list id for a given time to allow the enumerator to cache lists
|
|
22
|
+
def list_id(time)
|
|
23
|
+
time.year
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# return a list of times which match the time parameter within the scope of the RecurringDay
|
|
27
|
+
def matches_for(time)
|
|
28
|
+
[time.change(:month => 1, :day => 1).advance(:days => target_for(time)- 1)]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def target_date_time_for(date_time)
|
|
32
|
+
matches_for(date_time)[0]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def target_for(date_or_time)
|
|
36
|
+
if @source > 0
|
|
37
|
+
@source
|
|
38
|
+
else
|
|
39
|
+
length_of_year(date_or_time.year) + @source + 1
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def include?(date_or_time)
|
|
44
|
+
date_or_time.yday == target_for(date_or_time)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
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 Validations #:nodoc:
|
|
7
|
+
# Validate that the parameters of the reciever conform to RFC 2445
|
|
8
|
+
# If errors are found they will be added to the receivers errors
|
|
9
|
+
#
|
|
10
|
+
# Whenever any of the parameters are set, e.g. with:
|
|
11
|
+
# recurrence_rule.count = 2
|
|
12
|
+
# the errors will be reset
|
|
13
|
+
def valid?
|
|
14
|
+
validate if @errors.nil?
|
|
15
|
+
errors.empty?
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Return any errors found during validation
|
|
19
|
+
# See #valid?
|
|
20
|
+
def errors
|
|
21
|
+
@errors ||= []
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def reset_errors # :nodoc:
|
|
25
|
+
@errors = nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Used by #valid? to validate that the parameters of the reciever conform to RFC 2445
|
|
29
|
+
# If errors are found they will be added to the receivers errors
|
|
30
|
+
#
|
|
31
|
+
# Whenever any of the parameters are set, e.g. with:
|
|
32
|
+
# recurrence_rule.count = 2
|
|
33
|
+
# the errors will be reset
|
|
34
|
+
def validate
|
|
35
|
+
@errors = []
|
|
36
|
+
validate_termination
|
|
37
|
+
validate_freq
|
|
38
|
+
validate_interval
|
|
39
|
+
validate_int_by_list(:bysecond, (0..59))
|
|
40
|
+
validate_int_by_list(:byminute, (0..59))
|
|
41
|
+
validate_int_by_list(:byhour, (0..23))
|
|
42
|
+
validate_int_by_list(:bymonth, (1..12))
|
|
43
|
+
validate_bysetpos
|
|
44
|
+
validate_byday_list
|
|
45
|
+
validate_bymonthday_list
|
|
46
|
+
validate_byyearday_list
|
|
47
|
+
validate_byweekno_list
|
|
48
|
+
validate_wkst
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def validate_termination
|
|
52
|
+
errors << "COUNT and UNTIL cannot both be specified" if @count && @until
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def validate_freq
|
|
56
|
+
if @freq
|
|
57
|
+
unless %w{
|
|
58
|
+
SECONDLY MINUTELY HOURLY DAILY
|
|
59
|
+
WEEKLY MONTHLY YEARLY
|
|
60
|
+
}.include?(@freq.upcase)
|
|
61
|
+
errors << "Invalid frequency '#{@freq}'"
|
|
62
|
+
end
|
|
63
|
+
else
|
|
64
|
+
errors << "RecurrenceRule must have a value for FREQ"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def validate_interval
|
|
69
|
+
if @interval
|
|
70
|
+
errors << "interval must be a positive integer" unless @interval > 0
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def validate_wkst
|
|
75
|
+
errors << "#{wkst.inspect} is invalid for wkst" unless %w{MO TU WE TH FR SA SU}.include?(wkst)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def validate_int_by_list(which, test)
|
|
79
|
+
vals = by_list[which] || []
|
|
80
|
+
vals.each do |val|
|
|
81
|
+
errors << "#{val} is invalid for #{which}" unless test === val
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def validate_bysetpos
|
|
86
|
+
vals = by_list[:bysetpos] || []
|
|
87
|
+
vals.each do |val|
|
|
88
|
+
errors << "#{val} is invalid for bysetpos" unless (-366..-1) === val || (1..366) === val
|
|
89
|
+
end
|
|
90
|
+
unless vals.empty?
|
|
91
|
+
errors << "bysetpos cannot be used without another by_xxx rule part" unless by_list.length > 1
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def validate_byday_list
|
|
96
|
+
days = by_list[:byday] || []
|
|
97
|
+
days.each do |day|
|
|
98
|
+
errors << "#{day.source.inspect} is not a valid day" unless day.valid?
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def validate_bymonthday_list
|
|
103
|
+
days = by_list[:bymonthday] || []
|
|
104
|
+
days.each do |day|
|
|
105
|
+
errors << "#{day.source.inspect} is not a valid month day" unless day.valid?
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def validate_byyearday_list
|
|
110
|
+
days = by_list[:byyearday] || []
|
|
111
|
+
days.each do |day|
|
|
112
|
+
errors << "#{day.source.inspect} is not a valid year day" unless day.valid?
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def validate_byweekno_list
|
|
117
|
+
days = by_list[:byweekno] || []
|
|
118
|
+
days.each do |day|
|
|
119
|
+
errors << "#{day.source.inspect} is not a valid week number" unless day.valid?
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
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::Text represents an icalendar Text property value
|
|
6
|
+
# which is defined in
|
|
7
|
+
# rfc 2445 section 4.3.11 pp 45-46
|
|
8
|
+
class Text < PropertyValue
|
|
9
|
+
|
|
10
|
+
# Return the string value of the receiver
|
|
11
|
+
def ruby_value
|
|
12
|
+
if value
|
|
13
|
+
value.gsub(/\\[;,nN\\]/) {|match|
|
|
14
|
+
case match[1,1]
|
|
15
|
+
when /[,;\\]/
|
|
16
|
+
match[1,1]
|
|
17
|
+
when 'n', 'N'
|
|
18
|
+
"\n"
|
|
19
|
+
else
|
|
20
|
+
match
|
|
21
|
+
end
|
|
22
|
+
}
|
|
23
|
+
else
|
|
24
|
+
nil
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.convert(parent, string) #:nodoc:
|
|
29
|
+
ical_str = string.gsub(/\n\r?|\r\n?|,|;|\\/) {|match|
|
|
30
|
+
if ["\n", "\r", "\n\r", "\r\n"].include?(match)
|
|
31
|
+
'\\n'
|
|
32
|
+
else
|
|
33
|
+
"\\#{match}"
|
|
34
|
+
end
|
|
35
|
+
}
|
|
36
|
+
self.new(parent, :value => ical_str)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
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::Uri represents an icalendar Uri property value
|
|
6
|
+
# which is defined in
|
|
7
|
+
# rfc 2445 section 4.8.4.6 p 110
|
|
8
|
+
class Uri < PropertyValue
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|