rubyredrick-ri_cal 0.0.2
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 +3 -0
- data/Manifest.txt +122 -0
- data/README.txt +271 -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 +2 -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/component/alarm.rb +22 -0
- data/lib/ri_cal/component/calendar.rb +199 -0
- data/lib/ri_cal/component/event.rb +30 -0
- data/lib/ri_cal/component/freebusy.rb +19 -0
- data/lib/ri_cal/component/journal.rb +22 -0
- data/lib/ri_cal/component/t_z_info_timezone.rb +124 -0
- data/lib/ri_cal/component/timezone/daylight_period.rb +26 -0
- data/lib/ri_cal/component/timezone/standard_period.rb +24 -0
- data/lib/ri_cal/component/timezone/timezone_period.rb +54 -0
- data/lib/ri_cal/component/timezone.rb +193 -0
- data/lib/ri_cal/component/todo.rb +26 -0
- data/lib/ri_cal/component.rb +224 -0
- data/lib/ri_cal/core_extensions/array/conversions.rb +15 -0
- data/lib/ri_cal/core_extensions/array.rb +7 -0
- data/lib/ri_cal/core_extensions/date/conversions.rb +27 -0
- data/lib/ri_cal/core_extensions/date.rb +13 -0
- data/lib/ri_cal/core_extensions/date_time/conversions.rb +27 -0
- data/lib/ri_cal/core_extensions/date_time.rb +13 -0
- data/lib/ri_cal/core_extensions/object/conversions.rb +20 -0
- data/lib/ri_cal/core_extensions/object.rb +8 -0
- data/lib/ri_cal/core_extensions/string/conversions.rb +32 -0
- data/lib/ri_cal/core_extensions/string.rb +8 -0
- data/lib/ri_cal/core_extensions/time/calculations.rb +153 -0
- data/lib/ri_cal/core_extensions/time/conversions.rb +27 -0
- data/lib/ri_cal/core_extensions/time/week_day_predicates.rb +88 -0
- data/lib/ri_cal/core_extensions/time.rb +11 -0
- data/lib/ri_cal/core_extensions.rb +6 -0
- data/lib/ri_cal/invalid_timezone_identifer.rb +20 -0
- data/lib/ri_cal/occurrence_enumerator.rb +172 -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/array.rb +19 -0
- data/lib/ri_cal/property_value/cal_address.rb +12 -0
- data/lib/ri_cal/property_value/date.rb +119 -0
- data/lib/ri_cal/property_value/date_time/additive_methods.rb +43 -0
- data/lib/ri_cal/property_value/date_time/time_machine.rb +180 -0
- data/lib/ri_cal/property_value/date_time/timezone_support.rb +65 -0
- data/lib/ri_cal/property_value/date_time.rb +324 -0
- data/lib/ri_cal/property_value/duration.rb +106 -0
- data/lib/ri_cal/property_value/geo.rb +12 -0
- data/lib/ri_cal/property_value/integer.rb +13 -0
- data/lib/ri_cal/property_value/occurrence_list.rb +82 -0
- data/lib/ri_cal/property_value/period.rb +63 -0
- data/lib/ri_cal/property_value/recurrence_rule/enumeration_support_methods.rb +98 -0
- data/lib/ri_cal/property_value/recurrence_rule/enumerator.rb +77 -0
- data/lib/ri_cal/property_value/recurrence_rule/initialization_methods.rb +149 -0
- data/lib/ri_cal/property_value/recurrence_rule/negative_setpos_enumerator.rb +54 -0
- data/lib/ri_cal/property_value/recurrence_rule/numbered_span.rb +32 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurence_incrementer.rb +794 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_day.rb +132 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_month_day.rb +61 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_numbered_week.rb +34 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_year_day.rb +50 -0
- data/lib/ri_cal/property_value/recurrence_rule/validations.rb +126 -0
- data/lib/ri_cal/property_value/recurrence_rule.rb +146 -0
- data/lib/ri_cal/property_value/text.rb +41 -0
- data/lib/ri_cal/property_value/uri.rb +12 -0
- data/lib/ri_cal/property_value/utc_offset.rb +34 -0
- data/lib/ri_cal/property_value.rb +110 -0
- data/lib/ri_cal/required_timezones.rb +56 -0
- data/lib/ri_cal/time_with_floating_timezone.rb +59 -0
- data/lib/ri_cal.rb +134 -0
- data/ri_cal.gemspec +47 -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 +13 -0
- data/spec/ri_cal/component/calendar_spec.rb +55 -0
- data/spec/ri_cal/component/event_spec.rb +157 -0
- data/spec/ri_cal/component/freebusy_spec.rb +13 -0
- data/spec/ri_cal/component/journal_spec.rb +13 -0
- data/spec/ri_cal/component/t_z_info_timezone_spec.rb +37 -0
- data/spec/ri_cal/component/timezone_spec.rb +155 -0
- data/spec/ri_cal/component/todo_spec.rb +61 -0
- data/spec/ri_cal/component_spec.rb +212 -0
- data/spec/ri_cal/core_extensions/time/calculations_spec.rb +189 -0
- data/spec/ri_cal/core_extensions/time/week_day_predicates_spec.rb +46 -0
- data/spec/ri_cal/occurrence_enumerator_spec.rb +218 -0
- data/spec/ri_cal/parser_spec.rb +304 -0
- data/spec/ri_cal/property_value/date_spec.rb +22 -0
- data/spec/ri_cal/property_value/date_time_spec.rb +448 -0
- data/spec/ri_cal/property_value/duration_spec.rb +80 -0
- data/spec/ri_cal/property_value/period_spec.rb +50 -0
- data/spec/ri_cal/property_value/recurrence_rule/recurring_year_day_spec.rb +22 -0
- data/spec/ri_cal/property_value/recurrence_rule_spec.rb +1815 -0
- data/spec/ri_cal/property_value/text_spec.rb +14 -0
- data/spec/ri_cal/property_value/utc_offset_spec.rb +49 -0
- data/spec/ri_cal/property_value_spec.rb +111 -0
- data/spec/ri_cal/required_timezones_spec.rb +68 -0
- data/spec/ri_cal_spec.rb +54 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +24 -0
- data/tasks/ri_cal.rake +403 -0
- data/tasks/spec.rake +35 -0
- metadata +201 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
module RiCal
|
2
|
+
class PropertyValue
|
3
|
+
class RecurrenceRule < PropertyValue
|
4
|
+
#- ©2009 Rick DeNatale
|
5
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
6
|
+
#
|
7
|
+
class Enumerator # :nodoc:
|
8
|
+
# base_time gets changed everytime the time is updated by the recurrence rule's frequency
|
9
|
+
attr_accessor :start_time, :duration, :next_time, :recurrence_rule, :base_time
|
10
|
+
def initialize(recurrence_rule, component, setpos_list)
|
11
|
+
self.recurrence_rule = recurrence_rule
|
12
|
+
self.start_time = component.default_start_time
|
13
|
+
self.duration = component.default_duration
|
14
|
+
self.next_time = recurrence_rule.adjust_start(self.start_time)
|
15
|
+
self.base_time = next_time
|
16
|
+
@bounded = recurrence_rule.bounded?
|
17
|
+
@count = 0
|
18
|
+
@setpos_list = setpos_list
|
19
|
+
@setpos = 1
|
20
|
+
@next_occurrence_count = 0
|
21
|
+
@incrementer = YearlyIncrementer.from_rrule(recurrence_rule, start_time)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.for(recurrence_rule, component, setpos_list) # :nodoc:
|
25
|
+
if !setpos_list || setpos_list.all? {|setpos| setpos > 1}
|
26
|
+
self.new(recurrence_rule, component, setpos_list)
|
27
|
+
else
|
28
|
+
NegativeSetposEnumerator.new(recurrence_rule, component, setpos_list)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def bounded?
|
34
|
+
@bounded
|
35
|
+
end
|
36
|
+
|
37
|
+
def result_hash(date_time_value)
|
38
|
+
{:start => date_time_value, :end => nil}
|
39
|
+
end
|
40
|
+
|
41
|
+
def result_passes_setpos_filter?(result)
|
42
|
+
result_setpos = @setpos
|
43
|
+
if recurrence_rule.in_same_set?(result, next_time)
|
44
|
+
@setpos += 1
|
45
|
+
else
|
46
|
+
@setpos = 1
|
47
|
+
end
|
48
|
+
if (result == start_time) || (result > start_time && @setpos_list.include?(result_setpos))
|
49
|
+
return true
|
50
|
+
else
|
51
|
+
return false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def result_passes_filters?(result)
|
56
|
+
if @setpos_list
|
57
|
+
result_passes_setpos_filter?(result)
|
58
|
+
else
|
59
|
+
result >= start_time
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def next_occurrence
|
64
|
+
while true
|
65
|
+
@next_occurrence_count += 1
|
66
|
+
result = next_time
|
67
|
+
self.next_time = @incrementer.next_time(result)
|
68
|
+
if result_passes_filters?(result)
|
69
|
+
@count += 1
|
70
|
+
return recurrence_rule.exhausted?(@count, result) ? nil : result_hash(result)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module RiCal
|
2
|
+
class PropertyValue
|
3
|
+
class RecurrenceRule < PropertyValue
|
4
|
+
#- ©2009 Rick DeNatale
|
5
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
6
|
+
#
|
7
|
+
module InitializationMethods # :nodoc:
|
8
|
+
|
9
|
+
attr_reader :by_day_scope
|
10
|
+
|
11
|
+
def add_to_options_hash(options_hash, key, value)
|
12
|
+
options_hash[key] = value if value
|
13
|
+
options_hash
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_byrule_strings_to_options_hash(options_hash, key)
|
17
|
+
if (rules = by_list[key])
|
18
|
+
if rules.length = 1
|
19
|
+
options_hash[key] = rules.first.source
|
20
|
+
else
|
21
|
+
options_hash[key] = rules.map {|rule| rule.source}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_options_hash
|
27
|
+
options_hash = {:freq => freq, :interval => interval}
|
28
|
+
options_hash[:params] = params unless params.empty?
|
29
|
+
add_to_options_hash(options_hash, :count, @count)
|
30
|
+
add_to_options_hash(options_hash, :until, @until)
|
31
|
+
add_to_options_hash(options_hash, :interval, @interval)
|
32
|
+
[:bysecond, :byminute, :byhour, :bymonth, :bysetpos].each do |bypart|
|
33
|
+
add_to_options_hash(options_hash, bypart, by_list[bypart])
|
34
|
+
end
|
35
|
+
[:byday, :bymonthday, :byyearday, :byweekno].each do |bypart|
|
36
|
+
add_byrule_strings_to_options_hash(options_hash, bypart)
|
37
|
+
end
|
38
|
+
options_hash
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialize_from_value_part(part, dup_hash) # :nodoc:
|
42
|
+
part_name, value = part.split("=")
|
43
|
+
attribute = part_name.downcase
|
44
|
+
errors << "Repeated rule part #{attribute} last occurrence was used" if dup_hash[attribute]
|
45
|
+
case attribute
|
46
|
+
when "freq"
|
47
|
+
self.freq = value
|
48
|
+
when "wkst"
|
49
|
+
self.wkst = value
|
50
|
+
when "until"
|
51
|
+
@until = PropertyValue.date_or_date_time(self, :value => value)
|
52
|
+
when "count"
|
53
|
+
@count = value.to_i
|
54
|
+
when "interval"
|
55
|
+
self.interval = value.to_i
|
56
|
+
when "bysecond", "byminute", "byhour", "bymonthday", "byyearday", "byweekno", "bymonth", "bysetpos"
|
57
|
+
send("#{attribute}=", value.split(",").map {|int| int.to_i})
|
58
|
+
when "byday"
|
59
|
+
self.byday = value.split(",")
|
60
|
+
else
|
61
|
+
errors << "Invalid rule part #{part}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def by_list
|
66
|
+
@by_list ||= {}
|
67
|
+
end
|
68
|
+
|
69
|
+
def calc_by_day_scope
|
70
|
+
case freq
|
71
|
+
when "YEARLY"
|
72
|
+
scope = :yearly
|
73
|
+
when "MONTHLY"
|
74
|
+
scope = :monthly
|
75
|
+
when "WEEKLY"
|
76
|
+
scope = :weekly
|
77
|
+
else
|
78
|
+
scope = :daily
|
79
|
+
end
|
80
|
+
scope = :monthly if scope != :weekly && @by_list_hash[:bymonth]
|
81
|
+
scope = :weekly if scope != :daily && @by_list_hash[:byweekno]
|
82
|
+
@by_day_scope = scope
|
83
|
+
end
|
84
|
+
|
85
|
+
def bysecond=(val)
|
86
|
+
@by_list_hash[:bysecond] = val
|
87
|
+
end
|
88
|
+
|
89
|
+
def byminute=(val)
|
90
|
+
@by_list_hash[:byminute] = val
|
91
|
+
end
|
92
|
+
|
93
|
+
def byhour=(val)
|
94
|
+
@by_list_hash[:byhour] = val
|
95
|
+
end
|
96
|
+
|
97
|
+
def bymonth=(val)
|
98
|
+
@by_list_hash[:bymonth] = val
|
99
|
+
end
|
100
|
+
|
101
|
+
def bysetpos=(val)
|
102
|
+
@by_list_hash[:bysetpos] = val
|
103
|
+
end
|
104
|
+
|
105
|
+
def byday=(val)
|
106
|
+
@by_list_hash[:byday] = val
|
107
|
+
end
|
108
|
+
|
109
|
+
def bymonthday=(val)
|
110
|
+
@by_list_hash[:bymonthday] = val
|
111
|
+
end
|
112
|
+
|
113
|
+
def byyearday=(val)
|
114
|
+
@by_list_hash[:byyearday] = val
|
115
|
+
end
|
116
|
+
|
117
|
+
def byweekno=(val)
|
118
|
+
@by_list_hash[:byweekno] = val
|
119
|
+
end
|
120
|
+
|
121
|
+
def init_by_lists
|
122
|
+
[:bysecond,
|
123
|
+
:byminute,
|
124
|
+
:byhour,
|
125
|
+
:bymonth,
|
126
|
+
:bysetpos
|
127
|
+
].each do |which|
|
128
|
+
if val = @by_list_hash[which]
|
129
|
+
by_list[which] = [val].flatten.sort
|
130
|
+
end
|
131
|
+
end
|
132
|
+
if val = @by_list_hash[:byday]
|
133
|
+
byday_scope = calc_by_day_scope
|
134
|
+
by_list[:byday] = [val].flatten.map {|day| RecurringDay.new(day, self, byday_scope)}
|
135
|
+
end
|
136
|
+
if val = @by_list_hash[:bymonthday]
|
137
|
+
by_list[:bymonthday] = [val].flatten.map {|md| RecurringMonthDay.new(md)}
|
138
|
+
end
|
139
|
+
if val = @by_list_hash[:byyearday]
|
140
|
+
by_list[:byyearday] = [val].flatten.map {|yd| RecurringYearDay.new(yd)}
|
141
|
+
end
|
142
|
+
if val = @by_list_hash[:byweekno]
|
143
|
+
by_list[:byweekno] = [val].flatten.map {|wkno| RecurringNumberedWeek.new(wkno, self)}
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module RiCal
|
2
|
+
class PropertyValue
|
3
|
+
class RecurrenceRule < PropertyValue
|
4
|
+
#- ©2009 Rick DeNatale
|
5
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
6
|
+
#
|
7
|
+
class NegativeSetposEnumerator < Enumerator # :nodoc:
|
8
|
+
|
9
|
+
def initialize(recurrence_rule, component, setpos_list)
|
10
|
+
super
|
11
|
+
@current_set = []
|
12
|
+
@valids = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def next_occurrence
|
16
|
+
while true
|
17
|
+
result = advance
|
18
|
+
if result >= start_time
|
19
|
+
@count += 1
|
20
|
+
return recurrence_rule.exhausted?(@count, result) ? nil : result_hash(result)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
def advance
|
28
|
+
if @valids.empty?
|
29
|
+
fill_set
|
30
|
+
@valids = @setpos_list.map {|sp| sp < 0 ? @current_set.length + sp : sp - 1}
|
31
|
+
current_time_index = @current_set.index(@start_time)
|
32
|
+
if current_time_index
|
33
|
+
@valids << current_time_index
|
34
|
+
end
|
35
|
+
@valids = @valids.uniq.sort
|
36
|
+
end
|
37
|
+
@current_set[@valids.shift]
|
38
|
+
end
|
39
|
+
|
40
|
+
def fill_set
|
41
|
+
@current_set = [next_time]
|
42
|
+
while true
|
43
|
+
self.next_time = @incrementer.next_time(next_time)
|
44
|
+
if recurrence_rule.in_same_set?(@current_set.last, next_time)
|
45
|
+
@current_set << next_time
|
46
|
+
else
|
47
|
+
return
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module RiCal
|
2
|
+
class PropertyValue
|
3
|
+
class RecurrenceRule < PropertyValue
|
4
|
+
#- ©2009 Rick DeNatale
|
5
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
6
|
+
#
|
7
|
+
class NumberedSpan # :nodoc:
|
8
|
+
attr_reader :source
|
9
|
+
def initialize(source, rule = nil)
|
10
|
+
@source = source
|
11
|
+
@rule = rule
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?
|
15
|
+
(1..last).include?(source) || (-last..-1).include?(source)
|
16
|
+
end
|
17
|
+
|
18
|
+
def ==(another)
|
19
|
+
self.class == another.class && source == another.source
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
source.to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
def ordinal
|
27
|
+
@source
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|