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.
- checksums.yaml +7 -0
- data/History.txt +402 -0
- data/Manifest.txt +161 -0
- data/README.txt +410 -0
- data/Rakefile +69 -0
- data/VERSION +1 -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/component/alarm.rb +19 -0
- data/lib/ri_cal/component/calendar.rb +257 -0
- data/lib/ri_cal/component/event.rb +58 -0
- data/lib/ri_cal/component/freebusy.rb +16 -0
- data/lib/ri_cal/component/journal.rb +27 -0
- data/lib/ri_cal/component/non_standard.rb +33 -0
- data/lib/ri_cal/component/t_z_info_timezone.rb +153 -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 +76 -0
- data/lib/ri_cal/component/timezone.rb +197 -0
- data/lib/ri_cal/component/todo.rb +42 -0
- data/lib/ri_cal/component.rb +256 -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 +56 -0
- data/lib/ri_cal/core_extensions/date.rb +13 -0
- data/lib/ri_cal/core_extensions/date_time/conversions.rb +50 -0
- data/lib/ri_cal/core_extensions/date_time.rb +15 -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 +57 -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 +42 -0
- data/lib/ri_cal/core_extensions/time/tzid_access.rb +50 -0
- data/lib/ri_cal/core_extensions/time/week_day_predicates.rb +55 -0
- data/lib/ri_cal/core_extensions/time.rb +14 -0
- data/lib/ri_cal/core_extensions.rb +11 -0
- data/lib/ri_cal/fast_date_time.rb +234 -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_identifier.rb +20 -0
- data/lib/ri_cal/occurrence_enumerator.rb +265 -0
- data/lib/ri_cal/occurrence_period.rb +17 -0
- data/lib/ri_cal/parser.rb +148 -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 +1523 -0
- data/lib/ri_cal/properties/freebusy.rb +593 -0
- data/lib/ri_cal/properties/journal.rb +1237 -0
- data/lib/ri_cal/properties/timezone.rb +150 -0
- data/lib/ri_cal/properties/timezone_period.rb +416 -0
- data/lib/ri_cal/properties/todo.rb +1559 -0
- data/lib/ri_cal/properties.rb +12 -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 +184 -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 +159 -0
- data/lib/ri_cal/property_value/date_time/timezone_support.rb +100 -0
- data/lib/ri_cal/property_value/date_time.rb +359 -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 +86 -0
- data/lib/ri_cal/property_value/recurrence_rule/enumeration_support_methods.rb +100 -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/occurrence_incrementer/by_day_incrementer.rb +86 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_hour_incrementer.rb +31 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_minute_incrementer.rb +32 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_month_incrementer.rb +52 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_monthday_incrementer.rb +31 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_numbered_day_incrementer.rb +38 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_second_incrementer.rb +32 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_weekno_incrementer.rb +69 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_yearday_incrementer.rb +31 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/daily_incrementer.rb +28 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/frequency_incrementer.rb +80 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/hourly_incrementer.rb +23 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/list_incrementer.rb +106 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/minutely_incrementer.rb +23 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/monthly_incrementer.rb +33 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/null_sub_cycle_incrementer.rb +43 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/secondly_incrementer.rb +28 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/weekly_incrementer.rb +37 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/yearly_incrementer.rb +57 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer.rb +135 -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 +64 -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 +53 -0
- data/lib/ri_cal/property_value/recurrence_rule/time_manipulation.rb +42 -0
- data/lib/ri_cal/property_value/recurrence_rule/validations.rb +125 -0
- data/lib/ri_cal/property_value/recurrence_rule.rb +154 -0
- data/lib/ri_cal/property_value/text.rb +44 -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/property_value/zulu_date_time.rb +34 -0
- data/lib/ri_cal/property_value.rb +159 -0
- data/lib/ri_cal/required_timezones.rb +55 -0
- data/lib/ri_cal.rb +187 -0
- data/parked_specs/ri_cal/claudio_a_bug_spec.rb +100 -0
- data/performance/empty_propval/subject.rb +43 -0
- data/performance/paris_eastern/subject.rb +90 -0
- data/performance/penultimate_weekday/subject.rb +15 -0
- data/performance/psm_big_enum/ical.ics +3171 -0
- data/performance/psm_big_enum/subject.rb +16 -0
- data/performance/utah_cycling/subject.rb +55 -0
- data/ri_cal.gemspec +244 -0
- data/script/benchmark_subject +23 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/profile_subject +29 -0
- data/script/txt2html +71 -0
- data/spec/ri_cal/bugreports_spec.rb +276 -0
- data/spec/ri_cal/component/alarm_spec.rb +12 -0
- data/spec/ri_cal/component/calendar_spec.rb +88 -0
- data/spec/ri_cal/component/event_spec.rb +735 -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 +60 -0
- data/spec/ri_cal/component/timezone_spec.rb +236 -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/fast_date_time_spec.rb +77 -0
- data/spec/ri_cal/inf_loop_spec.rb +78 -0
- data/spec/ri_cal/occurrence_enumerator_spec.rb +611 -0
- data/spec/ri_cal/parser_spec.rb +337 -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 +63 -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 +50 -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 +412 -0
- data/tasks/spec.rake +102 -0
- metadata +246 -0
@@ -0,0 +1,359 @@
|
|
1
|
+
require 'date'
|
2
|
+
module RiCal
|
3
|
+
class PropertyValue
|
4
|
+
#- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
|
5
|
+
#
|
6
|
+
# RiCal::PropertyValue::CalAddress represents an icalendar CalAddress property value
|
7
|
+
# which is defined in RFC 2445 section 4.3.5 pp 35-37
|
8
|
+
class DateTime < PropertyValue
|
9
|
+
|
10
|
+
Dir[File.dirname(__FILE__) + "/date_time/*.rb"].sort.each do |path|
|
11
|
+
require path
|
12
|
+
end
|
13
|
+
|
14
|
+
include Comparable
|
15
|
+
include AdditiveMethods
|
16
|
+
include TimezoneSupport
|
17
|
+
include TimeMachine
|
18
|
+
|
19
|
+
def self.or_date(parent, line) # :nodoc:
|
20
|
+
if /T/.match(line[:value] || "")
|
21
|
+
new(parent, line)
|
22
|
+
else
|
23
|
+
PropertyValue::Date.new(parent, line)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.valid_string?(string) #:nodoc:
|
28
|
+
string =~ /^\d{8}T\d{6}Z?$/
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.default_tzid # :nodoc:
|
32
|
+
@default_tzid ||= "UTC"
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.params_for_tzid(tzid) #:nodoc:
|
36
|
+
if tzid == :floating
|
37
|
+
{}
|
38
|
+
else
|
39
|
+
{'TZID' => tzid}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Set the default tzid to be used when instantiating an instance from a ruby object
|
44
|
+
# see RiCal::PropertyValue::DateTime.from_time
|
45
|
+
#
|
46
|
+
# The parameter tzid is a string value to be used for the default tzid, a value of :floating will cause
|
47
|
+
# values with NO timezone to be produced, which will be interpreted by iCalendar as floating times
|
48
|
+
# i.e. they are interpreted in the timezone of each client. Floating times are typically used
|
49
|
+
# to represent events which are 'repeated' in the various time zones, like the first hour of the year.
|
50
|
+
def self.default_tzid=(tzid)
|
51
|
+
@default_tzid = tzid
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.default_tzid_hash # :nodoc:
|
55
|
+
if default_tzid.to_s == 'none'
|
56
|
+
{}
|
57
|
+
else
|
58
|
+
{'TZID' => default_tzid}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def inspect # :nodoc:
|
63
|
+
"#{@date_time_value}:#{tzid}"
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns the value of the receiver as an RFC 2445 iCalendar string
|
67
|
+
def value
|
68
|
+
if @date_time_value
|
69
|
+
"#{@date_time_value.ical_str}#{tzid == "UTC" ? "Z" : ""}"
|
70
|
+
else
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_ri_cal_zulu_date_time
|
76
|
+
ZuluDateTime.new(nil, :value => self.utc.fast_date_tme)
|
77
|
+
end
|
78
|
+
|
79
|
+
def fast_date_tme # :nodoc:
|
80
|
+
@date_time_value
|
81
|
+
end
|
82
|
+
|
83
|
+
# Set the value of the property to val
|
84
|
+
#
|
85
|
+
# val may be either:
|
86
|
+
#
|
87
|
+
# * A string which can be parsed as a DateTime
|
88
|
+
# * A Time instance
|
89
|
+
# * A Date instance
|
90
|
+
# * A DateTime instance
|
91
|
+
def value=(val) # :nodoc:
|
92
|
+
case val
|
93
|
+
when nil
|
94
|
+
@date_time_value = nil
|
95
|
+
when String
|
96
|
+
@date_time_value = FastDateTime.from_date_time(::DateTime.parse(val))
|
97
|
+
if val =~/Z/
|
98
|
+
self.tzid = 'UTC'
|
99
|
+
else
|
100
|
+
@tzid ||= :floating
|
101
|
+
end
|
102
|
+
when FastDateTime
|
103
|
+
@date_time_value = val
|
104
|
+
when ::DateTime
|
105
|
+
@date_time_value = FastDateTime.from_date_time(val)
|
106
|
+
when ::Date, ::Time
|
107
|
+
@date_time_value = FastDateTime.from_date_time(::DateTime.parse(val.to_s))
|
108
|
+
end
|
109
|
+
reset_cached_values
|
110
|
+
end
|
111
|
+
|
112
|
+
# Extract the time and timezone identifier from an object used to set the value of a DATETIME property.
|
113
|
+
#
|
114
|
+
# If the object is a string it should be of the form [TZID=identifier:]
|
115
|
+
#
|
116
|
+
# Otherwise determine if the object acts like an activesupport enhanced time, and extract its timezone
|
117
|
+
# idenfifier if it has one.
|
118
|
+
#
|
119
|
+
def self.time_and_parameters(object)
|
120
|
+
parameters = {}
|
121
|
+
if ::String === object
|
122
|
+
object, parameters = self.time_and_parameters_from_string(object)
|
123
|
+
else
|
124
|
+
identifier = object.tzid rescue nil
|
125
|
+
parameters["TZID"] = identifier if identifier
|
126
|
+
end
|
127
|
+
[object, parameters]
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
def self.convert(timezone_finder, ruby_object) # :nodoc:
|
132
|
+
ruby_object.to_ri_cal_date_or_date_time_value(timezone_finder)
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.from_string(string) # :nodoc:
|
136
|
+
if string.match(/Z$/)
|
137
|
+
new(nil, :value => string, :tzid => 'UTC')
|
138
|
+
else
|
139
|
+
new(nil, :value => string)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def for_parent(parent) #:nodoc:
|
144
|
+
if timezone_finder.nil?
|
145
|
+
@timezone_finder = parent
|
146
|
+
self
|
147
|
+
elsif parent == timezone_finder
|
148
|
+
self
|
149
|
+
else
|
150
|
+
DateTime.new(parent, :value => @date_time_value, :params => params, :tzid => tzid)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def visible_params # :nodoc:
|
155
|
+
result = {"VALUE" => "DATE-TIME"}.merge(params)
|
156
|
+
if has_local_timezone?
|
157
|
+
result['TZID'] = tzid
|
158
|
+
else
|
159
|
+
result.delete('TZID')
|
160
|
+
end
|
161
|
+
result
|
162
|
+
end
|
163
|
+
|
164
|
+
def params=(value) #:nodoc:
|
165
|
+
@params = value.dup
|
166
|
+
if params_timezone = @params['TZID']
|
167
|
+
self.tzid = @params['TZID']
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Return a Hash representing this properties parameters
|
172
|
+
def params
|
173
|
+
result = @params.dup
|
174
|
+
case tzid
|
175
|
+
when :floating, nil, "UTC"
|
176
|
+
result.delete('TZID')
|
177
|
+
else
|
178
|
+
result['TZID'] = tzid
|
179
|
+
end
|
180
|
+
result
|
181
|
+
end
|
182
|
+
|
183
|
+
# Compare the receiver with another object which must respond to the to_datetime message
|
184
|
+
# The comparison is done using the Ruby DateTime representations of the two objects
|
185
|
+
def <=>(other)
|
186
|
+
other.cmp_fast_date_time_value(@date_time_value)
|
187
|
+
end
|
188
|
+
|
189
|
+
def cmp_fast_date_time_value(other)
|
190
|
+
other <=> @date_time_value
|
191
|
+
end
|
192
|
+
|
193
|
+
# Determine if the receiver and other are in the same month
|
194
|
+
def in_same_month_as?(other)
|
195
|
+
[other.year, other.month] == [year, month]
|
196
|
+
end
|
197
|
+
|
198
|
+
def with_date_time_value(date_time_value)
|
199
|
+
PropertyValue::DateTime.new(
|
200
|
+
timezone_finder,
|
201
|
+
:value => date_time_value,
|
202
|
+
:params => (params),
|
203
|
+
:tzid => tzid
|
204
|
+
)
|
205
|
+
end
|
206
|
+
|
207
|
+
def nth_wday_in_month(n, which_wday) #:nodoc:
|
208
|
+
with_date_time_value(@date_time_value.nth_wday_in_month(n, which_wday))
|
209
|
+
end
|
210
|
+
|
211
|
+
def nth_wday_in_year(n, which_wday) #:nodoc:
|
212
|
+
with_date_time_value(@date_time_value.nth_wday_in_year(n, which_wday))
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.civil(year, month, day, hour, min, sec, offset, start, params) #:nodoc:
|
216
|
+
PropertyValue::DateTime.new(
|
217
|
+
:value => ::DateTime.civil(year, month, day, hour, min, sec, offset, start),
|
218
|
+
:params =>(params ? params.dup : nil)
|
219
|
+
)
|
220
|
+
end
|
221
|
+
|
222
|
+
# Return the number of days in the month containing the receiver
|
223
|
+
def days_in_month
|
224
|
+
@date_time_value.days_in_month
|
225
|
+
end
|
226
|
+
|
227
|
+
# Determine if the receiver and another object are equivalent RiCal::PropertyValue::DateTime instances
|
228
|
+
def ==(other)
|
229
|
+
if self.class === other
|
230
|
+
self.value == other.value && self.visible_params == other.visible_params && self.tzid == other.tzid
|
231
|
+
else
|
232
|
+
super
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# TODO: consider if this should be a period rather than a hash
|
237
|
+
def occurrence_period(default_duration) # :nodoc:
|
238
|
+
RiCal::OccurrencePeriod.new(self, (default_duration ? self + default_duration : nil))
|
239
|
+
end
|
240
|
+
|
241
|
+
# Return the year (including the century)
|
242
|
+
def year
|
243
|
+
@date_time_value.year
|
244
|
+
end
|
245
|
+
|
246
|
+
# Return the month of the year (1..12)
|
247
|
+
def month
|
248
|
+
@date_time_value.month
|
249
|
+
end
|
250
|
+
|
251
|
+
# Return the day of the month
|
252
|
+
def day
|
253
|
+
@date_time_value.day
|
254
|
+
end
|
255
|
+
|
256
|
+
alias_method :mday, :day
|
257
|
+
|
258
|
+
# Return the day of the week
|
259
|
+
def wday
|
260
|
+
@date_time_value.wday
|
261
|
+
end
|
262
|
+
|
263
|
+
# Return the hour
|
264
|
+
def hour
|
265
|
+
@date_time_value.hour
|
266
|
+
end
|
267
|
+
|
268
|
+
# Return the minute
|
269
|
+
def min
|
270
|
+
@date_time_value.min
|
271
|
+
end
|
272
|
+
|
273
|
+
# Return the second
|
274
|
+
def sec
|
275
|
+
@date_time_value.sec
|
276
|
+
end
|
277
|
+
|
278
|
+
|
279
|
+
# Return an RiCal::PropertyValue::DateTime representing the receiver.
|
280
|
+
def to_ri_cal_date_time_value(timezone=nil)
|
281
|
+
for_parent(timezone)
|
282
|
+
end
|
283
|
+
|
284
|
+
def iso_year_and_week_one_start(wkst) #:nodoc:
|
285
|
+
@date_time_value.iso_year_and_week_one_start(wkst)
|
286
|
+
end
|
287
|
+
|
288
|
+
def iso_weeks_in_year(wkst) #:nodoc:
|
289
|
+
@date_time_value.iso_weeks_in_year(wkst) #:nodoc:
|
290
|
+
end
|
291
|
+
|
292
|
+
# Return the "Natural' property value for the receover, in this case the receiver itself."
|
293
|
+
def to_ri_cal_date_or_date_time_value(timezone_finder = nil) #:nodoc:
|
294
|
+
self.for_parent(timezone_finder)
|
295
|
+
end
|
296
|
+
|
297
|
+
# Return a Date property for this DateTime
|
298
|
+
def to_ri_cal_date_value(timezone_finder=nil)
|
299
|
+
PropertyValue::Date.new(timezone_finder, :value => @date_time_value.ical_date_str)
|
300
|
+
end
|
301
|
+
|
302
|
+
# Return the Ruby DateTime representation of the receiver
|
303
|
+
def to_datetime #:nodoc:
|
304
|
+
@date_time_value.to_datetime
|
305
|
+
end
|
306
|
+
|
307
|
+
# Returns a ruby DateTime object representing the receiver.
|
308
|
+
def ruby_value
|
309
|
+
if has_valid_tzinfo_tzid? && RiCal::TimeWithZone && tz_info_source?
|
310
|
+
RiCal::TimeWithZone.new(utc.to_datetime, ::Time.__send__(:get_zone, @tzid))
|
311
|
+
else
|
312
|
+
::DateTime.civil(year, month, day, hour, min, sec, rational_tz_offset).set_tzid(@tzid)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
alias_method :to_ri_cal_ruby_value, :to_datetime
|
317
|
+
alias_method :to_finish_time, :ruby_value
|
318
|
+
|
319
|
+
def to_zulu_time
|
320
|
+
utc.to_datetime
|
321
|
+
end
|
322
|
+
|
323
|
+
# If a time is floating, then the utc of it's start time may actually be as early
|
324
|
+
# as 12 hours earlier if the occurrence is being viewed in a time zone just west
|
325
|
+
# of the International Date Line
|
326
|
+
def to_zulu_occurrence_range_start_time
|
327
|
+
if floating?
|
328
|
+
@date_time_value.advance(:hours => -12, :offset => 0).to_datetime
|
329
|
+
else
|
330
|
+
to_zulu_time
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
|
335
|
+
# If a time is floating, then the utc of it's start time may actually be as early
|
336
|
+
# as 12 hours later if the occurrence is being viewed in a time zone just east
|
337
|
+
# of the International Date Line
|
338
|
+
def to_zulu_occurrence_range_finish_time
|
339
|
+
if floating?
|
340
|
+
utc.advance(:hours => 12).to_datetime
|
341
|
+
else
|
342
|
+
to_zulu_time
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
def add_date_times_to(required_timezones) #:nodoc:
|
347
|
+
required_timezones.add_datetime(self, tzid) if has_local_timezone?
|
348
|
+
end
|
349
|
+
|
350
|
+
def start_of_day?
|
351
|
+
[hour, min, sec] == [0,0,0]
|
352
|
+
end
|
353
|
+
|
354
|
+
def for_occurrence(occurrence)
|
355
|
+
occurrence.to_ri_cal_date_time_value(timezone_finder)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
@@ -0,0 +1,110 @@
|
|
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 Duration property value
|
6
|
+
# which is defined in
|
7
|
+
# rfc 2445 section 4.3.6 p 37
|
8
|
+
class Duration < PropertyValue
|
9
|
+
|
10
|
+
def self.value_part(unit, diff) # :nodoc:
|
11
|
+
(diff == 0) ? nil : "#{diff}#{unit}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.from_datetimes(parent, start, finish, sign='+') # :nodoc:
|
15
|
+
if start > finish
|
16
|
+
from_datetimes(self, finish, start, '-')
|
17
|
+
else
|
18
|
+
diff = finish - start
|
19
|
+
days_diff = diff.to_i
|
20
|
+
hours = (diff - days_diff) * 24
|
21
|
+
hour_diff = hours.to_i
|
22
|
+
minutes = (hours - hour_diff) * 60
|
23
|
+
min_diff = minutes.to_i
|
24
|
+
seconds = (minutes - min_diff) * 60
|
25
|
+
sec_diff = seconds.to_i
|
26
|
+
|
27
|
+
day_part = value_part('D',days_diff)
|
28
|
+
hour_part = value_part('H', hour_diff)
|
29
|
+
min_part = value_part('M', min_diff)
|
30
|
+
sec_part = value_part('S', sec_diff)
|
31
|
+
t_part = (hour_diff.abs + min_diff.abs + sec_diff.abs) == 0 ? "" : "T"
|
32
|
+
new(parent, :value => "#{sign}P#{day_part}#{t_part}#{hour_part}#{min_part}#{sec_part}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.convert(parent, ruby_object) # :nodoc:
|
37
|
+
ruby_object.to_ri_cal_duration_value
|
38
|
+
end
|
39
|
+
|
40
|
+
def value=(string) # :nodoc:
|
41
|
+
super
|
42
|
+
match = /([+-])?P(.*)$/.match(string)
|
43
|
+
@days = @hours = @minutes = @seconds = @weeks = 0
|
44
|
+
if match
|
45
|
+
@sign = match[1] == '-' ? -1 : 1
|
46
|
+
match[2].scan(/(\d+)([DHMSW])/) do |digits, unit|
|
47
|
+
number = digits.to_i
|
48
|
+
case unit
|
49
|
+
when 'D'
|
50
|
+
@days = number
|
51
|
+
when 'H'
|
52
|
+
@hours = number
|
53
|
+
when 'M'
|
54
|
+
@minutes = number
|
55
|
+
when 'S'
|
56
|
+
@seconds = number
|
57
|
+
when 'W'
|
58
|
+
@weeks = number
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.valid_string?(string) #:nodoc:
|
65
|
+
string =~ /^[+-]?P((\d+D)(T((\d+)[HMS])+)?)|(T((\d+)[HMS])+)|(\d+W)$/
|
66
|
+
end
|
67
|
+
|
68
|
+
def days # :nodoc:
|
69
|
+
@days * @sign
|
70
|
+
end
|
71
|
+
|
72
|
+
def weeks # :nodoc:
|
73
|
+
@weeks * @sign
|
74
|
+
end
|
75
|
+
|
76
|
+
def hours # :nodoc:
|
77
|
+
@hours * @sign
|
78
|
+
end
|
79
|
+
|
80
|
+
def minutes # :nodoc:
|
81
|
+
@minutes * @sign
|
82
|
+
end
|
83
|
+
|
84
|
+
def seconds # :nodoc:
|
85
|
+
@seconds * @sign
|
86
|
+
end
|
87
|
+
|
88
|
+
# Determine whether another object is an equivalent RiCal::PropertyValue::Duration
|
89
|
+
def ==(other)
|
90
|
+
other.kind_of?(PropertyValue::Duration) && value == other.value
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns the receiver
|
94
|
+
def to_ri_cal_duration_value
|
95
|
+
self
|
96
|
+
end
|
97
|
+
|
98
|
+
# Double-dispatch method to support RiCal::PropertyValue::DateTime.-
|
99
|
+
def subtract_from_date_time_value(date_time_value)
|
100
|
+
date_time_value.advance(:weeks => -weeks, :days => -days, :hours => -hours, :minutes => -minutes, :seconds => -seconds)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Double-dispatch method to support RiCal::PropertyValue::DateTime.+
|
104
|
+
def add_to_date_time_value(date_time_value)
|
105
|
+
date_time_value.advance(:weeks => weeks, :days => days, :hours => hours, :minutes => minutes, :seconds => seconds)
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
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::CalAddress represents an icalendar Duration property value
|
6
|
+
# which is defined in
|
7
|
+
# rfc 2445 section 4.8.1.6 pp 82-83
|
8
|
+
class Geo < PropertyValue
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -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
|