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,193 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[.. properties timezone.rb])
|
2
|
+
|
3
|
+
module RiCal
|
4
|
+
class Component
|
5
|
+
#- ©2009 Rick DeNatale
|
6
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
7
|
+
#
|
8
|
+
# An Timezone (VTIMEZONE) calendar component describes a timezone used within the calendar.
|
9
|
+
# A Timezone has two or more TimezonePeriod subcomponents which describe the transitions between
|
10
|
+
# standard and daylight saving time.
|
11
|
+
#
|
12
|
+
# to see the property accessing methods for this class see the RiCal::Properties::Timezone module
|
13
|
+
class Timezone < Component
|
14
|
+
include RiCal::Properties::Timezone
|
15
|
+
|
16
|
+
# The identifier of the timezone, e.g. "Europe/Paris".
|
17
|
+
def identifier
|
18
|
+
tzid
|
19
|
+
end
|
20
|
+
|
21
|
+
# An alias for identifier.
|
22
|
+
def name
|
23
|
+
# Don't use alias, as identifier gets overridden.
|
24
|
+
identifier
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the TimezonePeriod for the given UTC time. utc can either be a DateTime,
|
28
|
+
# Time or integer timestamp (Time.to_i). Any timezone information in utc is ignored (it is treated as a UTC time).
|
29
|
+
def period_for_utc(time)
|
30
|
+
last_period(last_before_utc(standard, time), last_before_utc(daylight, time))
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns the set of TimezonePeriod instances that are valid for the given
|
34
|
+
# local time as an array. If you just want a single period, use
|
35
|
+
# period_for_local instead and specify how ambiguities should be resolved.
|
36
|
+
# Returns an empty array if no periods are found for the given time.
|
37
|
+
def periods_for_local(local)
|
38
|
+
local = local.to_ri_cal_date_time_value
|
39
|
+
candidate_standard = last_before_local(standard, local)
|
40
|
+
candidate_daylight = last_before_local(daylight, local)
|
41
|
+
if candidate_daylight && candidate_daylight.swallows_local?(local, candidate_standard)
|
42
|
+
[] # Invalid local time
|
43
|
+
elsif candidate_standard
|
44
|
+
if candidate_daylight
|
45
|
+
if candidate_daylight.dtstart > candidate_standard.dtstart
|
46
|
+
[candidate_daylight]
|
47
|
+
elsif candidate_standard.ambiguous_local?(local)
|
48
|
+
[candidate_daylight, candidate_standard]
|
49
|
+
else
|
50
|
+
[candidate_standard].compact
|
51
|
+
end
|
52
|
+
else
|
53
|
+
[candidate_standard].compact
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
# Returns the TimezonePeriod for the given local time. local can either be
|
60
|
+
# a DateTime, Time or integer timestamp (Time.to_i). Any timezone
|
61
|
+
# information in local is ignored (it is treated as a time in the current
|
62
|
+
# timezone).
|
63
|
+
#
|
64
|
+
# Warning: There are local times that have no equivalent UTC times (e.g.
|
65
|
+
# in the transition from standard time to daylight savings time). There are
|
66
|
+
# also local times that have more than one UTC equivalent (e.g. in the
|
67
|
+
# transition from daylight savings time to standard time).
|
68
|
+
#
|
69
|
+
# In the first case (no equivalent UTC time), a PeriodNotFound exception
|
70
|
+
# will be raised.
|
71
|
+
#
|
72
|
+
# In the second case (more than one equivalent UTC time), an AmbiguousTime
|
73
|
+
# exception will be raised unless the optional dst parameter or block
|
74
|
+
# handles the ambiguity.
|
75
|
+
#
|
76
|
+
# If the ambiguity is due to a transition from daylight savings time to
|
77
|
+
# standard time, the dst parameter can be used to select whether the
|
78
|
+
# daylight savings time or local time is used. For example,
|
79
|
+
#
|
80
|
+
# Timezone.get('America/New_York').period_for_local(DateTime.new(2004,10,31,1,30,0))
|
81
|
+
#
|
82
|
+
# would raise an AmbiguousTime exception.
|
83
|
+
#
|
84
|
+
# Specifying dst=true would the daylight savings period from April to
|
85
|
+
# October 2004. Specifying dst=false would return the standard period
|
86
|
+
# from October 2004 to April 2005.
|
87
|
+
#
|
88
|
+
# If the dst parameter does not resolve the ambiguity, and a block is
|
89
|
+
# specified, it is called. The block must take a single parameter - an
|
90
|
+
# array of the periods that need to be resolved. The block can select and
|
91
|
+
# return a single period or return nil or an empty array
|
92
|
+
# to cause an AmbiguousTime exception to be raised.
|
93
|
+
#
|
94
|
+
# TODO: need to check for ambiguity
|
95
|
+
def period_for_local(local, dst=nil)
|
96
|
+
results = periods_for_local(local)
|
97
|
+
|
98
|
+
if results.empty?
|
99
|
+
raise TZInfo::PeriodNotFound
|
100
|
+
elsif results.size < 2
|
101
|
+
results.first
|
102
|
+
else
|
103
|
+
# ambiguous result try to resolve
|
104
|
+
|
105
|
+
unless dst.nil?
|
106
|
+
matches = results.find_all {|period| period.dst? == dst}
|
107
|
+
results = matches unless matches.empty?
|
108
|
+
end
|
109
|
+
|
110
|
+
if results.size < 2
|
111
|
+
results.first
|
112
|
+
else
|
113
|
+
# still ambiguous, try the block
|
114
|
+
|
115
|
+
if block_given?
|
116
|
+
results = yield results
|
117
|
+
end
|
118
|
+
|
119
|
+
if results.is_a?(TimezonePeriod)
|
120
|
+
results
|
121
|
+
elsif results && results.size == 1
|
122
|
+
results.first
|
123
|
+
else
|
124
|
+
raise TZInfo::AmbiguousTime, "#{local} is an ambiguous local time."
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# convert time from utc time to this time zone
|
131
|
+
def utc_to_local(time)
|
132
|
+
time = time.to_ri_cal_date_time_value
|
133
|
+
converted = time + period_for_utc(time).tzoffsetto_property
|
134
|
+
converted.tzid = identifier
|
135
|
+
converted
|
136
|
+
end
|
137
|
+
|
138
|
+
# convert time from this time zone to utc time
|
139
|
+
def local_to_utc(time)
|
140
|
+
time = time.to_ri_cal_date_time_value
|
141
|
+
period = period_for_local(time)
|
142
|
+
converted = time - period.tzoffsetto_property
|
143
|
+
converted.tzid = "UTC"
|
144
|
+
converted
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.entity_name #:nodoc:
|
149
|
+
"VTIMEZONE"
|
150
|
+
end
|
151
|
+
|
152
|
+
def standard #:nodoc:
|
153
|
+
@subcomponents["STANDARD"]
|
154
|
+
end
|
155
|
+
|
156
|
+
def daylight #:nodoc:
|
157
|
+
@subcomponents["DAYLIGHT"]
|
158
|
+
end
|
159
|
+
|
160
|
+
def last_period(standard, daylight) #:nodoc:
|
161
|
+
if standard
|
162
|
+
if daylight
|
163
|
+
standard.dtstart > daylight.dtstart ? standard : daylight
|
164
|
+
else
|
165
|
+
standard
|
166
|
+
end
|
167
|
+
else
|
168
|
+
daylight
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def last_before_utc(period_array, time) #:nodoc:
|
173
|
+
candidates = period_array.map {|period|
|
174
|
+
period.last_before_utc(time)
|
175
|
+
}
|
176
|
+
result = candidates.max {|a, b| a.dtstart_property <=> b.dtstart_property}
|
177
|
+
result
|
178
|
+
end
|
179
|
+
|
180
|
+
def last_before_local(period_array, time) #:nodoc:
|
181
|
+
candidates = period_array.map {|period|
|
182
|
+
period.last_before_local(time)
|
183
|
+
}
|
184
|
+
result = candidates.max {|a, b| a.dtstart_property <=> b.dtstart_property}
|
185
|
+
result
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
%w[timezone_period.rb daylight_period.rb standard_period.rb].each do |filename|
|
192
|
+
require "#{File.dirname(__FILE__)}/timezone/#{filename}"
|
193
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[.. properties todo.rb])
|
2
|
+
|
3
|
+
module RiCal
|
4
|
+
class Component
|
5
|
+
#- ©2009 Rick DeNatale
|
6
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
7
|
+
#
|
8
|
+
# A Todo (VTODO) calendar component groups properties describing a to-do
|
9
|
+
# Todos may have multiple occurrences
|
10
|
+
#
|
11
|
+
# Todos may also contain one or more ALARM subcomponents
|
12
|
+
# to see the property accessing methods for this class see the RiCal::Properties::Todo module
|
13
|
+
# to see the methods for enumerating occurrences of recurring to-dos see the RiCal::OccurrenceEnumerator module
|
14
|
+
class Todo < Component
|
15
|
+
include Properties::Todo
|
16
|
+
|
17
|
+
def self.entity_name #:nodoc:
|
18
|
+
"VTODO"
|
19
|
+
end
|
20
|
+
|
21
|
+
def subcomponent_class #:nodoc:
|
22
|
+
{:alarm => Alarm }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,224 @@
|
|
1
|
+
module RiCal
|
2
|
+
#- ©2009 Rick DeNatale
|
3
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
4
|
+
#
|
5
|
+
class Component
|
6
|
+
class ComponentBuilder #:nodoc:
|
7
|
+
def initialize(component)
|
8
|
+
@component = component
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(selector, *args, &init_block) #:nodoc:
|
12
|
+
if(sub_comp_class = @component.subcomponent_class[selector])
|
13
|
+
if init_block
|
14
|
+
sub_comp = sub_comp_class.new(@component)
|
15
|
+
if init_block.arity == 1
|
16
|
+
yield ComponentBuilder.new(sub_comp)
|
17
|
+
else
|
18
|
+
ComponentBuilder.new(sub_comp).instance_eval(&init_block)
|
19
|
+
end
|
20
|
+
self.add_subcomponent(sub_comp)
|
21
|
+
end
|
22
|
+
else
|
23
|
+
sel = selector.to_s
|
24
|
+
sel = "#{sel}=" unless /(^(add_)|(remove_))|(=$)/ =~ sel
|
25
|
+
if @component.respond_to?(sel)
|
26
|
+
@component.send(sel, *args)
|
27
|
+
else
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
autoload :Timezone, "#{File.dirname(__FILE__)}/component/timezone.rb"
|
35
|
+
|
36
|
+
attr_accessor :imported #:nodoc:
|
37
|
+
|
38
|
+
def initialize(parent=nil, &init_block) #:nodoc:
|
39
|
+
@parent = parent
|
40
|
+
if block_given?
|
41
|
+
if init_block.arity == 1
|
42
|
+
init_block.call(ComponentBuilder.new(self))
|
43
|
+
else
|
44
|
+
ComponentBuilder.new(self).instance_eval(&init_block)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def find_timezone(identifier) #:nodoc:
|
50
|
+
@parent.find_timezone(identifier)
|
51
|
+
end
|
52
|
+
|
53
|
+
def time_zone_for(ruby_object)
|
54
|
+
@parent.time_zone_for(ruby_object) #:nodoc:
|
55
|
+
end
|
56
|
+
|
57
|
+
def subcomponent_class #:nodoc:
|
58
|
+
{}
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.from_parser(parser, parent) #:nodoc:
|
62
|
+
entity = self.new(parent)
|
63
|
+
entity.imported = true
|
64
|
+
line = parser.next_separated_line
|
65
|
+
while parser.still_in(entity_name, line)
|
66
|
+
entity.process_line(parser, line)
|
67
|
+
line = parser.next_separated_line
|
68
|
+
end
|
69
|
+
entity
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.parse(io) #:nodoc:
|
73
|
+
Parser.new(io).parse
|
74
|
+
end
|
75
|
+
|
76
|
+
def imported? #:nodoc:
|
77
|
+
imported
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.parse_string(string) #:nodoc:
|
81
|
+
parse(StringIO.new(string))
|
82
|
+
end
|
83
|
+
|
84
|
+
def subcomponents #:nodoc:
|
85
|
+
@subcomponents ||= Hash.new {|h, k| h[k] = []}
|
86
|
+
end
|
87
|
+
|
88
|
+
def entity_name #:nodoc:
|
89
|
+
self.class.entity_name
|
90
|
+
end
|
91
|
+
|
92
|
+
# return an array of Alarm components within this component :nodoc:
|
93
|
+
# Alarms may be contained within Events, and Todos
|
94
|
+
def alarms
|
95
|
+
subcomponents["VALARM"]
|
96
|
+
end
|
97
|
+
|
98
|
+
def add_subcomponent(component) #:nodoc:
|
99
|
+
subcomponents[component.entity_name] << component
|
100
|
+
end
|
101
|
+
|
102
|
+
def parse_subcomponent(parser, line) #:nodoc:
|
103
|
+
subcomponents[line[:value]] << parser.parse_one(line, self)
|
104
|
+
end
|
105
|
+
|
106
|
+
def process_line(parser, line) #:nodoc:
|
107
|
+
if line[:name] == "BEGIN"
|
108
|
+
parse_subcomponent(parser, line)
|
109
|
+
else
|
110
|
+
setter = self.class.property_parser[line[:name]]
|
111
|
+
if setter
|
112
|
+
send(setter, line)
|
113
|
+
else
|
114
|
+
self.add_x_property(line[:name], PropertyValue::Text.new(self, line))
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# return a hash of any extended properties, (i.e. those with a property name starting with "X-"
|
120
|
+
# representing an extension to the RFC 2445 specification)
|
121
|
+
def x_properties
|
122
|
+
@x_properties ||= {}
|
123
|
+
end
|
124
|
+
|
125
|
+
# Add a n extended property
|
126
|
+
def add_x_property(name, prop)
|
127
|
+
x_properties[name] = prop
|
128
|
+
end
|
129
|
+
|
130
|
+
def method_missing(selector, *args, &b)
|
131
|
+
xprop_candidate = selector.to_s
|
132
|
+
if (match = /^x_(.+)(=?)$/.match(xprop_candidate))
|
133
|
+
if match[2] == "="
|
134
|
+
add_x_property("x_#{match[1]}", *args)
|
135
|
+
else
|
136
|
+
x_properties[xprop_candidate]
|
137
|
+
end
|
138
|
+
else
|
139
|
+
super
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Predicate to determine if the component is valid according to RFC 2445
|
144
|
+
def valid?
|
145
|
+
!mutual_exclusion_violation
|
146
|
+
end
|
147
|
+
|
148
|
+
def initialize_copy(original) #:nodoc:
|
149
|
+
end
|
150
|
+
|
151
|
+
def prop_string(prop_name, *properties) #:nodoc:
|
152
|
+
properties = properties.flatten.compact
|
153
|
+
if properties && !properties.empty?
|
154
|
+
properties.map {|prop| "#{prop_name}#{prop.to_s}"}.join("\n")
|
155
|
+
else
|
156
|
+
nil
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def add_property_date_times_to(required_timezones, property) #:nodoc:
|
161
|
+
if property
|
162
|
+
if Array === property
|
163
|
+
property.each do |prop|
|
164
|
+
prop.add_date_times_to(required_timezones)
|
165
|
+
end
|
166
|
+
else
|
167
|
+
property.add_date_times_to(required_timezones)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def export_prop_to(export_stream, name, prop) #:nodoc:
|
173
|
+
if prop
|
174
|
+
string = prop_string(name, prop)
|
175
|
+
export_stream.puts(string) if string
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def export_x_properties_to(export_stream) #:nodoc:
|
180
|
+
x_properties.each do |name, prop|
|
181
|
+
export_stream.puts("#{name}:#{prop}")
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def export_subcomponent_to(export_stream, subcomponent) #:nodoc:
|
186
|
+
subcomponent.each do |component|
|
187
|
+
component.export_to(export_stream)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# return a string containing the rfc2445 format of the component
|
192
|
+
def to_s
|
193
|
+
io = StringIO.new
|
194
|
+
export_to(io)
|
195
|
+
io.string
|
196
|
+
end
|
197
|
+
|
198
|
+
# Export this component to an export stream
|
199
|
+
def export_to(export_stream)
|
200
|
+
export_stream.puts("BEGIN:#{entity_name}")
|
201
|
+
export_properties_to(export_stream)
|
202
|
+
export_x_properties_to(export_stream)
|
203
|
+
subcomponents.values do |sub|
|
204
|
+
export_subcomponent_to(export_subcomponent_to, sub)
|
205
|
+
end
|
206
|
+
export_stream.puts("END:#{entity_name}")
|
207
|
+
end
|
208
|
+
|
209
|
+
# Export this single component as an iCalendar component containing only this component and
|
210
|
+
# any required additional components (i.e. VTIMEZONES referenced from this component)
|
211
|
+
# if stream is nil (the default) then this method will return a string,
|
212
|
+
# otherwise stream should be an IO to which the iCalendar file contents will be written
|
213
|
+
def export(stream=nil)
|
214
|
+
wrapper_calendar = Calendar.new
|
215
|
+
wrapper_calendar.add_subcomponent(self)
|
216
|
+
wrapper_calendar.export(stream)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
Dir[File.dirname(__FILE__) + "/component/*.rb"].sort.each do |path|
|
222
|
+
filename = File.basename(path)
|
223
|
+
require path
|
224
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RiCal
|
2
|
+
module CoreExtensions #:nodoc:
|
3
|
+
module Array #:nodoc:
|
4
|
+
#- ©2009 Rick DeNatale
|
5
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
6
|
+
#
|
7
|
+
module Conversions
|
8
|
+
# return the concatenation of the elements representation in rfc 2445 format
|
9
|
+
def to_rfc2445_string # :doc:
|
10
|
+
join(",")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RiCal
|
2
|
+
module CoreExtensions #:nodoc:
|
3
|
+
module Date #:nodoc:
|
4
|
+
#- ©2009 Rick DeNatale
|
5
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
6
|
+
#
|
7
|
+
module Conversions
|
8
|
+
# Return an RiCal::PropertyValue::DateTime representing the receiver
|
9
|
+
def to_ri_cal_date_time_value
|
10
|
+
RiCal::PropertyValue::DateTime.new(nil, :value => self)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Return an RiCal::PropertyValue::Date representing the receiver
|
14
|
+
def to_ri_cal_date_value
|
15
|
+
RiCal::PropertyValue::Date.new(nil, :value => self)
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method :to_ri_cal_date_or_date_time_value, :to_ri_cal_date_value
|
19
|
+
|
20
|
+
# Return the natural ri_cal_property for this object
|
21
|
+
def to_ri_cal_property_value
|
22
|
+
to_ri_cal_date_value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/date/conversions.rb"
|
2
|
+
require "#{File.dirname(__FILE__)}/time/week_day_predicates.rb"
|
3
|
+
require "#{File.dirname(__FILE__)}/time/calculations.rb"
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
class Date #:nodoc:
|
7
|
+
#- ©2009 Rick DeNatale
|
8
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
9
|
+
#
|
10
|
+
include RiCal::CoreExtensions::Time::WeekDayPredicates
|
11
|
+
include RiCal::CoreExtensions::Time::Calculations
|
12
|
+
include RiCal::CoreExtensions::Date::Conversions
|
13
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RiCal
|
2
|
+
module CoreExtensions #:nodoc:
|
3
|
+
module DateTime #:nodoc:
|
4
|
+
#- ©2009 Rick DeNatale
|
5
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
6
|
+
#
|
7
|
+
module Conversions
|
8
|
+
# Return an RiCal::PropertyValue::DateTime representing the receiver
|
9
|
+
def to_ri_cal_date_time_value
|
10
|
+
RiCal::PropertyValue::DateTime.from_time(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
alias_method :to_ri_cal_date_or_date_time_value, :to_ri_cal_date_time_value
|
14
|
+
|
15
|
+
# Return the natural ri_cal_property for this object
|
16
|
+
def to_ri_cal_property_value
|
17
|
+
to_ri_cal_date_time_value
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return a proxy to this object which will be interpreted as a floating time.
|
21
|
+
def with_floating_timezone
|
22
|
+
RiCal::TimeWithFloatingTimezone.new(self)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/date_time/conversions.rb"
|
2
|
+
require "#{File.dirname(__FILE__)}/time/week_day_predicates.rb"
|
3
|
+
require "#{File.dirname(__FILE__)}/time/calculations.rb"
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
class DateTime #:nodoc:
|
7
|
+
#- ©2009 Rick DeNatale
|
8
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
9
|
+
#
|
10
|
+
include RiCal::CoreExtensions::Time::WeekDayPredicates
|
11
|
+
include RiCal::CoreExtensions::Time::Calculations
|
12
|
+
include RiCal::CoreExtensions::DateTime::Conversions
|
13
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module RiCal
|
2
|
+
module CoreExtensions #:nodoc:
|
3
|
+
module Object #:nodoc:
|
4
|
+
#- ©2009 Rick DeNatale
|
5
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
6
|
+
#
|
7
|
+
module Conversions
|
8
|
+
# Used to format rfc2445 output for RiCal
|
9
|
+
def to_rfc2445_string
|
10
|
+
to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
# Used by RiCal specs returns the receiver
|
14
|
+
def to_ri_cal_ruby_value
|
15
|
+
self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module RiCal
|
2
|
+
module CoreExtensions #:nodoc:
|
3
|
+
module String #:nodoc:
|
4
|
+
#- ©2009 Rick DeNatale
|
5
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
6
|
+
#
|
7
|
+
module Conversions
|
8
|
+
# Parse the receiver as an RiCal::PropertyValue::DateTime
|
9
|
+
def to_ri_cal_date_time_value
|
10
|
+
RiCal::PropertyValue::DateTime.from_string(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
alias_method :to_ri_cal_date_or_date_time_value, :to_ri_cal_date_time_value
|
14
|
+
|
15
|
+
# Parse the receiver as an RiCal::PropertyValue::DurationValue
|
16
|
+
def to_ri_cal_duration_value
|
17
|
+
RiCal::PropertyValue::Duration.from_string(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
# code stolen from ActiveSupport Gem
|
21
|
+
unless ::String.instance_methods.include?("camelize")
|
22
|
+
# Convert the receiver to camelized form
|
23
|
+
# This method duplicates the method provided by ActiveSupport, and will only be defined
|
24
|
+
# by the RiCal gem if it is not already defined.
|
25
|
+
def camelize
|
26
|
+
self.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|