micahwedemeyer-ri_cal 0.8.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. data/.rvmrc +2 -0
  2. data/Gemfile +7 -0
  3. data/Gemfile.lock +21 -0
  4. data/History.txt +402 -0
  5. data/Manifest.txt +161 -0
  6. data/README.txt +410 -0
  7. data/Rakefile +66 -0
  8. data/VERSION +1 -0
  9. data/bin/ri_cal +8 -0
  10. data/component_attributes/alarm.yml +10 -0
  11. data/component_attributes/calendar.yml +4 -0
  12. data/component_attributes/component_property_defs.yml +180 -0
  13. data/component_attributes/event.yml +45 -0
  14. data/component_attributes/freebusy.yml +16 -0
  15. data/component_attributes/journal.yml +35 -0
  16. data/component_attributes/timezone.yml +3 -0
  17. data/component_attributes/timezone_period.yml +11 -0
  18. data/component_attributes/todo.yml +46 -0
  19. data/copyrights.txt +1 -0
  20. data/docs/draft-ietf-calsify-2446bis-08.txt +7280 -0
  21. data/docs/draft-ietf-calsify-rfc2445bis-09.txt +10416 -0
  22. data/docs/incrementers.txt +7 -0
  23. data/docs/rfc2445.pdf +0 -0
  24. data/lib/ri_cal/component/alarm.rb +19 -0
  25. data/lib/ri_cal/component/calendar.rb +257 -0
  26. data/lib/ri_cal/component/event.rb +58 -0
  27. data/lib/ri_cal/component/freebusy.rb +16 -0
  28. data/lib/ri_cal/component/journal.rb +27 -0
  29. data/lib/ri_cal/component/non_standard.rb +33 -0
  30. data/lib/ri_cal/component/t_z_info_timezone.rb +153 -0
  31. data/lib/ri_cal/component/timezone/daylight_period.rb +25 -0
  32. data/lib/ri_cal/component/timezone/standard_period.rb +23 -0
  33. data/lib/ri_cal/component/timezone/timezone_period.rb +76 -0
  34. data/lib/ri_cal/component/timezone.rb +197 -0
  35. data/lib/ri_cal/component/todo.rb +42 -0
  36. data/lib/ri_cal/component.rb +256 -0
  37. data/lib/ri_cal/core_extensions/array/conversions.rb +15 -0
  38. data/lib/ri_cal/core_extensions/array.rb +7 -0
  39. data/lib/ri_cal/core_extensions/date/conversions.rb +56 -0
  40. data/lib/ri_cal/core_extensions/date.rb +13 -0
  41. data/lib/ri_cal/core_extensions/date_time/conversions.rb +50 -0
  42. data/lib/ri_cal/core_extensions/date_time.rb +15 -0
  43. data/lib/ri_cal/core_extensions/object/conversions.rb +20 -0
  44. data/lib/ri_cal/core_extensions/object.rb +8 -0
  45. data/lib/ri_cal/core_extensions/string/conversions.rb +57 -0
  46. data/lib/ri_cal/core_extensions/string.rb +8 -0
  47. data/lib/ri_cal/core_extensions/time/calculations.rb +153 -0
  48. data/lib/ri_cal/core_extensions/time/conversions.rb +42 -0
  49. data/lib/ri_cal/core_extensions/time/tzid_access.rb +50 -0
  50. data/lib/ri_cal/core_extensions/time/week_day_predicates.rb +55 -0
  51. data/lib/ri_cal/core_extensions/time.rb +14 -0
  52. data/lib/ri_cal/core_extensions.rb +11 -0
  53. data/lib/ri_cal/fast_date_time.rb +234 -0
  54. data/lib/ri_cal/floating_timezone.rb +32 -0
  55. data/lib/ri_cal/invalid_property_value.rb +8 -0
  56. data/lib/ri_cal/invalid_timezone_identifier.rb +20 -0
  57. data/lib/ri_cal/occurrence_enumerator.rb +265 -0
  58. data/lib/ri_cal/occurrence_period.rb +17 -0
  59. data/lib/ri_cal/parser.rb +145 -0
  60. data/lib/ri_cal/properties/alarm.rb +390 -0
  61. data/lib/ri_cal/properties/calendar.rb +164 -0
  62. data/lib/ri_cal/properties/event.rb +1523 -0
  63. data/lib/ri_cal/properties/freebusy.rb +593 -0
  64. data/lib/ri_cal/properties/journal.rb +1237 -0
  65. data/lib/ri_cal/properties/timezone.rb +150 -0
  66. data/lib/ri_cal/properties/timezone_period.rb +416 -0
  67. data/lib/ri_cal/properties/todo.rb +1559 -0
  68. data/lib/ri_cal/properties.rb +12 -0
  69. data/lib/ri_cal/property_value/array.rb +27 -0
  70. data/lib/ri_cal/property_value/cal_address.rb +11 -0
  71. data/lib/ri_cal/property_value/date.rb +184 -0
  72. data/lib/ri_cal/property_value/date_time/additive_methods.rb +44 -0
  73. data/lib/ri_cal/property_value/date_time/time_machine.rb +159 -0
  74. data/lib/ri_cal/property_value/date_time/timezone_support.rb +100 -0
  75. data/lib/ri_cal/property_value/date_time.rb +359 -0
  76. data/lib/ri_cal/property_value/duration.rb +110 -0
  77. data/lib/ri_cal/property_value/geo.rb +11 -0
  78. data/lib/ri_cal/property_value/integer.rb +12 -0
  79. data/lib/ri_cal/property_value/occurrence_list.rb +144 -0
  80. data/lib/ri_cal/property_value/period.rb +86 -0
  81. data/lib/ri_cal/property_value/recurrence_rule/enumeration_support_methods.rb +100 -0
  82. data/lib/ri_cal/property_value/recurrence_rule/enumerator.rb +79 -0
  83. data/lib/ri_cal/property_value/recurrence_rule/initialization_methods.rb +148 -0
  84. data/lib/ri_cal/property_value/recurrence_rule/negative_setpos_enumerator.rb +53 -0
  85. data/lib/ri_cal/property_value/recurrence_rule/numbered_span.rb +31 -0
  86. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_day_incrementer.rb +86 -0
  87. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_hour_incrementer.rb +31 -0
  88. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_minute_incrementer.rb +32 -0
  89. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_month_incrementer.rb +52 -0
  90. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_monthday_incrementer.rb +31 -0
  91. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_numbered_day_incrementer.rb +38 -0
  92. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_second_incrementer.rb +32 -0
  93. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_weekno_incrementer.rb +69 -0
  94. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_yearday_incrementer.rb +31 -0
  95. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/daily_incrementer.rb +28 -0
  96. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/frequency_incrementer.rb +80 -0
  97. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/hourly_incrementer.rb +23 -0
  98. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/list_incrementer.rb +106 -0
  99. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/minutely_incrementer.rb +23 -0
  100. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/monthly_incrementer.rb +33 -0
  101. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/null_sub_cycle_incrementer.rb +43 -0
  102. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/secondly_incrementer.rb +28 -0
  103. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/weekly_incrementer.rb +37 -0
  104. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/yearly_incrementer.rb +57 -0
  105. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer.rb +135 -0
  106. data/lib/ri_cal/property_value/recurrence_rule/recurring_day.rb +131 -0
  107. data/lib/ri_cal/property_value/recurrence_rule/recurring_month_day.rb +64 -0
  108. data/lib/ri_cal/property_value/recurrence_rule/recurring_numbered_week.rb +33 -0
  109. data/lib/ri_cal/property_value/recurrence_rule/recurring_year_day.rb +53 -0
  110. data/lib/ri_cal/property_value/recurrence_rule/time_manipulation.rb +42 -0
  111. data/lib/ri_cal/property_value/recurrence_rule/validations.rb +125 -0
  112. data/lib/ri_cal/property_value/recurrence_rule.rb +154 -0
  113. data/lib/ri_cal/property_value/text.rb +44 -0
  114. data/lib/ri_cal/property_value/uri.rb +11 -0
  115. data/lib/ri_cal/property_value/utc_offset.rb +33 -0
  116. data/lib/ri_cal/property_value/zulu_date_time.rb +34 -0
  117. data/lib/ri_cal/property_value.rb +159 -0
  118. data/lib/ri_cal/required_timezones.rb +55 -0
  119. data/lib/ri_cal.rb +187 -0
  120. data/micahwedemeyer-ri_cal.gemspec +227 -0
  121. data/parked_specs/ri_cal/claudio_a_bug_spec.rb +100 -0
  122. data/performance/empty_propval/subject.rb +43 -0
  123. data/performance/paris_eastern/subject.rb +90 -0
  124. data/performance/penultimate_weekday/subject.rb +15 -0
  125. data/performance/psm_big_enum/ical.ics +3171 -0
  126. data/performance/psm_big_enum/subject.rb +16 -0
  127. data/performance/utah_cycling/subject.rb +55 -0
  128. data/sample_ical_files/from_ical_dot_app/test1.ics +38 -0
  129. data/script/benchmark_subject +23 -0
  130. data/script/console +10 -0
  131. data/script/destroy +14 -0
  132. data/script/generate +14 -0
  133. data/script/profile_subject +29 -0
  134. data/script/txt2html +71 -0
  135. data/spec/ri_cal/bugreports_spec.rb +287 -0
  136. data/spec/ri_cal/component/alarm_spec.rb +12 -0
  137. data/spec/ri_cal/component/calendar_spec.rb +88 -0
  138. data/spec/ri_cal/component/event_spec.rb +735 -0
  139. data/spec/ri_cal/component/freebusy_spec.rb +12 -0
  140. data/spec/ri_cal/component/journal_spec.rb +37 -0
  141. data/spec/ri_cal/component/t_z_info_timezone_spec.rb +60 -0
  142. data/spec/ri_cal/component/timezone_spec.rb +236 -0
  143. data/spec/ri_cal/component/todo_spec.rb +112 -0
  144. data/spec/ri_cal/component_spec.rb +224 -0
  145. data/spec/ri_cal/core_extensions/string/conversions_spec.rb +78 -0
  146. data/spec/ri_cal/core_extensions/time/calculations_spec.rb +188 -0
  147. data/spec/ri_cal/core_extensions/time/week_day_predicates_spec.rb +45 -0
  148. data/spec/ri_cal/fast_date_time_spec.rb +77 -0
  149. data/spec/ri_cal/inf_loop_spec.rb +78 -0
  150. data/spec/ri_cal/occurrence_enumerator_spec.rb +611 -0
  151. data/spec/ri_cal/parser_spec.rb +337 -0
  152. data/spec/ri_cal/property_value/date_spec.rb +53 -0
  153. data/spec/ri_cal/property_value/date_time_spec.rb +383 -0
  154. data/spec/ri_cal/property_value/duration_spec.rb +126 -0
  155. data/spec/ri_cal/property_value/occurrence_list_spec.rb +72 -0
  156. data/spec/ri_cal/property_value/period_spec.rb +63 -0
  157. data/spec/ri_cal/property_value/recurrence_rule/recurring_year_day_spec.rb +21 -0
  158. data/spec/ri_cal/property_value/recurrence_rule_spec.rb +1814 -0
  159. data/spec/ri_cal/property_value/text_spec.rb +25 -0
  160. data/spec/ri_cal/property_value/utc_offset_spec.rb +48 -0
  161. data/spec/ri_cal/property_value_spec.rb +125 -0
  162. data/spec/ri_cal/required_timezones_spec.rb +67 -0
  163. data/spec/ri_cal_spec.rb +53 -0
  164. data/spec/spec.opts +4 -0
  165. data/spec/spec_helper.rb +50 -0
  166. data/tasks/gem_loader/load_active_support.rb +3 -0
  167. data/tasks/gem_loader/load_tzinfo_gem.rb +2 -0
  168. data/tasks/ri_cal.rake +412 -0
  169. data/tasks/spec.rake +102 -0
  170. data/website/images/rubytrends.png +0 -0
  171. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  172. data/website/stylesheets/screen.css +159 -0
  173. metadata +307 -0
@@ -0,0 +1,735 @@
1
+ # encoding: utf-8
2
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
3
+
4
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
5
+
6
+ describe RiCal::Component::Event do
7
+
8
+ context "with change management properties" do
9
+ it "should use zulu time for all change management datetime properties" do
10
+ new_york_offset = Rational(-1, 6)
11
+ cal = RiCal.Calendar
12
+ event = RiCal::Component::Event.new(cal)
13
+ event.dtstamp = result_time_in_zone(2010, 4, 1, 9, 23, 45, "America/New_York", new_york_offset)
14
+ event.created = result_time_in_zone(2010, 4, 1, 9, 23, 45, "America/New_York", new_york_offset)
15
+ event.last_modified = result_time_in_zone(2010, 4, 1, 12, 23, 45, "America/New_York", new_york_offset)
16
+ event.to_s.should == "BEGIN:VEVENT
17
+ CREATED;VALUE=DATE-TIME:20100401T132345Z
18
+ DTSTAMP;VALUE=DATE-TIME:20100401T132345Z
19
+ LAST-MODIFIED;VALUE=DATE-TIME:20100401T162345Z
20
+ END:VEVENT
21
+ "
22
+ end
23
+ end
24
+
25
+ context ".finish_time" do
26
+ it "should be the end of the start day for an event with a date dtstart and no dtend or duration" do
27
+ @it = RiCal.Event do |evt|
28
+ evt.dtstart = "20090704"
29
+ end
30
+ @it.finish_time.should == DateTime.parse("20090704T235959")
31
+ end
32
+
33
+ it "should be the end of the end day for an event with a date dtstart and a dtend" do
34
+ @it = RiCal.Event do |evt|
35
+ evt.dtstart = "20090704"
36
+ evt.dtend = "20090706"
37
+ end
38
+ @it.finish_time.should == DateTime.parse("20090706T235959")
39
+ end
40
+
41
+ it "should be the start time for an event with a datetime dtstart and no dtend or duration" do
42
+ @it = RiCal.Event do |evt|
43
+ evt.dtstart = "20090704T013000Z"
44
+ end
45
+ @it.finish_time.should == DateTime.parse("20090704T013000Z")
46
+ end
47
+
48
+ it "should be the end time for an event with a datetime dtend" do
49
+ @it = RiCal.Event do |evt|
50
+ evt.dtstart = "20090704"
51
+ evt.dtend = "20090706T120000"
52
+ end
53
+ @it.finish_time.should == DateTime.parse("20090706T120000")
54
+ end
55
+
56
+ it "should be the end time for an event with a datetime dtstart and a duration" do
57
+ @it = RiCal.Event do |evt|
58
+ evt.dtstart = "20090704T120000Z"
59
+ evt.duration = "PT1H30M"
60
+ end
61
+ @it.finish_time.should == DateTime.parse("20090704T133000Z")
62
+ end
63
+
64
+ it "should uset the timezone of dtstart when event has a duration" do
65
+ @it = RiCal.Event do |evt|
66
+ evt.dtstart = "TZID=Australia/Sydney:20090712T200000"
67
+ evt.duration = "PT1H"
68
+ end
69
+ @it.finish_time.should == DateTime.parse("2009-07-12T21:00:00+10:00")
70
+ end
71
+ end
72
+
73
+ context ".before_range?" do
74
+ context "with a Date dtstart and no dtend" do
75
+ before(:each) do
76
+ @it = RiCal.Event do |evt|
77
+ evt.dtstart = "20090704"
78
+ end
79
+ end
80
+
81
+ it "should be false if the range start is a date before the start date" do
82
+ @it.before_range?([Date.parse("20090703"), :anything]).should_not be
83
+ end
84
+
85
+ it "should be false if the range start is the start date" do
86
+ @it.before_range?([Date.parse("20090704"), :anything]).should_not be
87
+ end
88
+
89
+ it "should be true if the range start is a date after the start date" do
90
+ @it.before_range?([Date.parse("20090705"), :anything]).should be
91
+ end
92
+ end
93
+
94
+ context "with a Date dtstart and date dtend" do
95
+ before(:each) do
96
+ @it = RiCal.Event do |evt|
97
+ evt.dtstart = "20090704"
98
+ evt.dtend = "20090706"
99
+ end
100
+ end
101
+
102
+ it "should be false if the range start is a date before the end date" do
103
+ @it.before_range?([Date.parse("20090705"), :anything]).should_not be
104
+ end
105
+
106
+ it "should be false if the range start is the end date" do
107
+ @it.before_range?([Date.parse("20090706"), :anything]).should_not be
108
+ end
109
+
110
+ it "should be true if the range start is a date after the end date" do
111
+ @it.before_range?([Date.parse("20090707"), :anything]).should be
112
+ end
113
+ end
114
+ end
115
+
116
+ context "bug report from Noboyuki Tomizawa" do
117
+ before(:each) do
118
+
119
+ @it = RiCal.Calendar do |cal|
120
+ cal.event do |event|
121
+ event.description = "test"
122
+ event.dtstart = "TZID=Asia/Tokyo:20090530T123000"
123
+ event.dtend = "TZID=Asia/Tokyo:20090530T123001"
124
+ end
125
+ end
126
+ end
127
+
128
+ it "should not fail" do
129
+ lambda {@it.export}.should_not raise_error
130
+ end
131
+ end
132
+
133
+ context "rdate property methods" do
134
+ before(:each) do
135
+ @event = RiCal.Event do
136
+ rdate "20090101"
137
+ end
138
+ end
139
+
140
+ context "#rdate=" do
141
+
142
+ it "should accept a single Date and replace the existing rdate" do
143
+ @event.rdate = Date.parse("20090102")
144
+ @event.rdate.should == [[Date.parse("20090102")]]
145
+ end
146
+
147
+ it "should accept a single rfc2445 date format string and replace the existing rdate" do
148
+ @event.rdate = "20090102"
149
+ @event.rdate.should == [[Date.parse("20090102")]]
150
+ end
151
+
152
+ it "should accept a single DateTime and replace the existing rdate" do
153
+ @event.rdate = DateTime.parse("20090102T012345")
154
+ @event.rdate.should == [[DateTime.parse("20090102T012345")]]
155
+ end
156
+
157
+ it "should accept a single Time and replace the existing rdate" do
158
+ ::RiCal::PropertyValue::DateTime.default_tzid = 'UTC'
159
+ @event.rdate = Time.local(2009, 1, 2, 1, 23, 45)
160
+ @event.rdate.should == [[result_time_in_zone(2009, 1, 2, 1, 23, 45, "UTC")]]
161
+ end
162
+
163
+ it "should accept a single rfc2445 date-time format string and replace the existing rdate" do
164
+ @event.rdate = "20090102T012345"
165
+ @event.rdate.should == [[DateTime.parse("20090102T012345")]]
166
+ end
167
+
168
+ it "should accept a tzid prefixed rfc2445 date-time format string and replace the existing rdate" do
169
+ @event.rdate = "TZID=America/New_York:20090102T012345"
170
+ @event.rdate.should == [[result_time_in_zone(2009, 1, 2, 1, 23, 45, "America/New_York")]]
171
+ end
172
+
173
+ end
174
+
175
+ end
176
+
177
+ context "comment property methods" do
178
+ before(:each) do
179
+ @event = RiCal.Event
180
+ @event.comment = "Comment"
181
+ end
182
+
183
+ context "#comment=" do
184
+ it "should result in a single comment for the event" do
185
+ @event.comment.should == ["Comment"]
186
+ end
187
+
188
+ it "should replace existing comments" do
189
+ @event.comment = "Replacement"
190
+ @event.comment.should == ["Replacement"]
191
+ end
192
+ end
193
+
194
+ context "#comments=" do
195
+ it "should result in a multiple comments for the event replacing existing comments" do
196
+ @event.comments = "New1", "New2"
197
+ @event.comment.should == ["New1", "New2"]
198
+ end
199
+ end
200
+
201
+ context "#add_comment" do
202
+ it "should add a single comment" do
203
+ @event.add_comment "New1"
204
+ @event.comment.should == ["Comment", "New1"]
205
+ end
206
+ end
207
+
208
+ context "#add_comments" do
209
+ it "should add multiple comments" do
210
+ @event.add_comments "New1", "New2"
211
+ @event.comment.should == ["Comment", "New1", "New2"]
212
+ end
213
+ end
214
+
215
+ context "#remove_comment" do
216
+ it "should remove a single comment" do
217
+ @event.add_comment "New1"
218
+ @event.remove_comment "Comment"
219
+ @event.comment.should == ["New1"]
220
+ end
221
+ end
222
+
223
+ context "#remove_comments" do
224
+ it "should remove multiple comments" do
225
+ @event.add_comments "New1", "New2", "New3"
226
+ @event.remove_comments "New2", "Comment"
227
+ @event.comment.should == ["New1", "New3"]
228
+ end
229
+ end
230
+ end
231
+
232
+ context ".dtstart=" do
233
+ before(:each) do
234
+ @event = RiCal.Event
235
+ end
236
+
237
+ context "with a datetime only string" do
238
+ before(:each) do
239
+ @event.dtstart = "20090514T202400"
240
+ @it = @event.dtstart
241
+ end
242
+
243
+ it "should interpret it as the correct date-time" do
244
+ @it.should == DateTime.civil(2009, 5, 14, 20, 24, 00, Rational(0,24))
245
+ end
246
+
247
+ it "should interpret it as a floating date" do
248
+ @it.tzid.should == :floating
249
+ end
250
+ end
251
+
252
+ context "with a TZID and datetime string" do
253
+ before(:each) do
254
+ @event.dtstart = "TZID=America/New_York:20090514T202400"
255
+ @it = @event.dtstart
256
+ end
257
+
258
+ it "should interpret it as the correct date-time" do
259
+ @it.should == result_time_in_zone(2009, 5, 14, 20, 24, 00, "America/New_York")
260
+ end
261
+
262
+ it "should set the tzid to America/New_York" do
263
+ @it.tzid.should == "America/New_York"
264
+ end
265
+ end
266
+
267
+ context "with a zulu datetime only string" do
268
+ before(:each) do
269
+ @event.dtstart = "20090514T202400Z"
270
+ @it = @event.dtstart
271
+ end
272
+
273
+ it "should interpret it as the correct date-time" do
274
+ @it.should == DateTime.civil(2009, 5, 14, 20, 24, 00, Rational(0,24))
275
+ end
276
+
277
+ it "should set the tzid to UTC" do
278
+ @it.tzid.should == "UTC"
279
+ end
280
+ end
281
+
282
+ context "with a date string" do
283
+ before(:each) do
284
+ @event.dtstart = "20090514"
285
+ @it = @event.dtstart
286
+ end
287
+
288
+ it "should interpret it as the correct date-time" do
289
+ @it.should == Date.parse("14 May 2009")
290
+ end
291
+ end
292
+ end
293
+
294
+ context ".entity_name" do
295
+ it "should be VEVENT" do
296
+ RiCal::Component::Event.entity_name.should == "VEVENT"
297
+ end
298
+ end
299
+
300
+ context "with an rrule" do
301
+ before(:each) do
302
+ @it = RiCal::Component::Event.parse_string("BEGIN:VEVENT\nRRULE:FREQ=DAILY\nEND:VEVENT").first
303
+ end
304
+
305
+ it "should have an array of rrules" do
306
+ @it.rrule.should be_kind_of(Array)
307
+ end
308
+ end
309
+
310
+ context ".start_time" do
311
+
312
+ it "should be nil if there is no dtstart property" do
313
+ RiCal.Event.start_time.should be_nil
314
+ end
315
+
316
+ it "should be the same as dtstart for a date time" do
317
+ event = RiCal.Event {|e| e.dtstart = "20090525T151900"}
318
+ event.start_time.should == DateTime.civil(2009,05,25,15,19,0,0)
319
+ end
320
+
321
+ it "should be the start of the day of dtstart for a date" do
322
+ event = RiCal.Event {|e| e.dtstart = "20090525"}
323
+ event.start_time.should == DateTime.civil(2009,05,25,0,0,0,0)
324
+ end
325
+ end
326
+
327
+ context ".finish_time" do
328
+ before(:each) do
329
+ @event = RiCal.Event {|e| e.dtstart = "20090525T151900"}
330
+ end
331
+
332
+ context "with a given dtend" do
333
+ it "should be the same as dtend for a date time" do
334
+ @event.dtend = "20090525T161900"
335
+ @event.finish_time.should == DateTime.civil(2009,05,25,16,19,0,0)
336
+ end
337
+
338
+
339
+ end
340
+
341
+ context "with no dtend" do
342
+ context "and a duration" do
343
+ it "should be the dtstart plus the duration" do
344
+ @event.duration = "+PT1H"
345
+ @event.finish_time.should == DateTime.civil(2009,5,25,16,19,0,0)
346
+ end
347
+ end
348
+
349
+ context "and no duration" do
350
+ context "when the dtstart is not set" do
351
+ before(:each) do
352
+ @event.dtstart_property = nil
353
+ end
354
+
355
+ it "should be nil" do
356
+ @event.finish_time.should be_nil
357
+ end
358
+ end
359
+ context "when the dstart is a datetime" do
360
+ # For cases where a "VEVENT" calendar component
361
+ # specifies a "DTSTART" property with a DATE-TIME data type but no
362
+ # "DTEND" property, the event ends on the same calendar date and time
363
+ # of day specified by the "DTSTART" property. RFC 2445 p 53
364
+ it "should be the same as start_time" do
365
+ @event.finish_time.should == @event.start_time
366
+ end
367
+ end
368
+ context "when the dtstart is a date" do
369
+ # For cases where a "VEVENT" calendar component specifies a "DTSTART" property with a DATE data type
370
+ # but no "DTEND" property, the events non-inclusive end is the end of the calendar date specified by
371
+ # the "DTSTART" property. RFC 2445 p 53
372
+
373
+ it "should be the end of the same day as start_time" do
374
+ @event.dtstart = "20090525"
375
+ @event.finish_time.should == DateTime.civil(2009,5,25,23,59,59,0)
376
+ end
377
+ end
378
+ end
379
+ end
380
+
381
+ end
382
+
383
+ context ".zulu_occurrence_range_start_time" do
384
+
385
+ it "should be nil if there is no dtstart property" do
386
+ RiCal.Event.zulu_occurrence_range_start_time.should be_nil
387
+ end
388
+
389
+ it "should be the utc equivalent of dtstart for a date time" do
390
+ event = RiCal.Event {|e| e.dtstart = "TZID=America/New_York:20090525T151900"}
391
+ event.zulu_occurrence_range_start_time.should == DateTime.civil(2009,05,25,19,19,0,0)
392
+ end
393
+
394
+ it "should be the utc time of the start of the day of dtstart in the earliest timezone for a date" do
395
+ event = RiCal.Event {|e| e.dtstart = "20090525"}
396
+ result = event.zulu_occurrence_range_start_time
397
+ result.should == DateTime.civil(2009,05,24,12,0,0,0)
398
+ end
399
+
400
+ it "should be the utc time of the dtstart in the earliest timezone if dtstart is a floating datetime" do
401
+ event = RiCal.Event {|e| e.dtstart = "20090525T151900"}
402
+ event.zulu_occurrence_range_start_time.should == DateTime.civil(2009,05,25,3,19,0,0)
403
+ end
404
+ end
405
+
406
+ context ".zulu_occurrence_range_finish_time" do
407
+ before(:each) do
408
+ @event = RiCal.Event {|e| e.dtstart = "TZID=America/New_York:20090525T151900"}
409
+ end
410
+
411
+ context "with a given dtend" do
412
+ it "should be the utc equivalent of dtend if dtend is a date time" do
413
+ @event.dtend = "TZID=America/New_York:20090525T161900"
414
+ @event.zulu_occurrence_range_finish_time.should == DateTime.civil(2009,05,25, 20,19,0,0)
415
+ end
416
+ end
417
+
418
+ context "with no dtend" do
419
+ context "and a duration" do
420
+ it "should be the dtstart plus the duration" do
421
+ @event.duration = "+PT1H"
422
+ @event.zulu_occurrence_range_finish_time.should == DateTime.civil(2009,5,25,20 ,19,0,0)
423
+ end
424
+ end
425
+
426
+ context "and no duration" do
427
+ context "when the dtstart is not set" do
428
+ before(:each) do
429
+ @event.dtstart_property = nil
430
+ end
431
+
432
+ it "should be nil" do
433
+ @event.zulu_occurrence_range_finish_time.should be_nil
434
+ end
435
+ end
436
+
437
+ context "when the dstart is a datetime" do
438
+
439
+ it "should be the same as start_time" do
440
+ @event.zulu_occurrence_range_finish_time.should == @event.zulu_occurrence_range_start_time
441
+ end
442
+ end
443
+
444
+ context "when the dtstart is a date" do
445
+ it "should be the utc of end of the same day as start_time in the westermost time zone" do
446
+ @event.dtstart = "20090525"
447
+ @event.zulu_occurrence_range_finish_time.should == DateTime.civil(2009,5,26,11,59,59,0)
448
+ end
449
+ end
450
+ end
451
+ end
452
+ end
453
+
454
+ context "description property" do
455
+ before(:each) do
456
+ @ical_desc = "posted by Joyce per Zan\\nASheville\\, Rayan's Restauratn\\, Biltm\n ore Square"
457
+ @ruby_desc = "posted by Joyce per Zan\nASheville, Rayan's Restauratn, Biltmore Square"
458
+ @it = RiCal::Component::Event.parse_string("BEGIN:VEVENT\nDESCRIPTION:#{@ical_desc}\nEND:VEVENT").first
459
+ end
460
+
461
+ it "should product the converted ruby value" do
462
+ @it.description.should == @ruby_desc
463
+ end
464
+
465
+ it "should produce escaped text for ical" do
466
+ @it.description = "This is a\nnew description, yes; it is"
467
+ @it.description_property.value.should == 'This is a\nnew description\, yes\; it is'
468
+ end
469
+
470
+ end
471
+
472
+ context "with both dtend and duration specified" do
473
+ before(:each) do
474
+ @it = RiCal::Component::Event.parse_string("BEGIN:VEVENT\nDTEND:19970903T190000Z\nDURATION:H1\nEND:VEVENT").first
475
+ end
476
+
477
+ it "should be invalid" do
478
+ @it.should_not be_valid
479
+ end
480
+ end
481
+
482
+ context "with a duration property" do
483
+ before(:each) do
484
+ @it = RiCal::Component::Event.parse_string("BEGIN:VEVENT\nDURATION:H1\nEND:VEVENT").first
485
+ end
486
+
487
+ it "should have a duration property" do
488
+ @it.duration_property.should be
489
+ end
490
+
491
+ it "should have a duration of 1 Hour" do
492
+ @it.duration_property.value.should == "H1"
493
+ end
494
+
495
+ it "should reset the duration property if the dtend property is set" do
496
+ @it.dtend_property = "19970101T123456".to_ri_cal_date_time_value
497
+ @it.duration_property.should be_nil
498
+ end
499
+
500
+ it "should reset the duration property if the dtend ruby value is set" do
501
+ @it.dtend = "19970101"
502
+ @it.duration_property.should == nil
503
+ end
504
+ end
505
+
506
+ context "with a dtend property" do
507
+ before(:each) do
508
+ @it = RiCal::Component::Event.parse_string("BEGIN:VEVENT\nDTEND:19970903T190000Z\nEND:VEVENT").first
509
+ end
510
+
511
+ it "should have a duration property" do
512
+ @it.dtend_property.should be
513
+ end
514
+
515
+ it "should reset the dtend property if the duration property is set" do
516
+ @it.duration_property = "PT1H".to_ri_cal_duration_value
517
+ @it.dtend_property.should be_nil
518
+ end
519
+
520
+ it "should reset the dtend property if the duration ruby value is set" do
521
+ @it.duration = "PT1H".to_ri_cal_duration_value
522
+ @it.dtend_property.should be_nil
523
+ end
524
+ end
525
+
526
+ context "with a nested alarm component" do
527
+ before(:each) do
528
+ @it = RiCal::Component::Event.parse_string("BEGIN:VEVENT\nDTEND:19970903T190000Z\n\nBEGIN:VALARM\nEND:VALARM\nEND:VEVENT").first
529
+ end
530
+
531
+ it "should have one alarm" do
532
+ @it.alarms.length.should == 1
533
+ end
534
+
535
+ it "which should be an Alarm component" do
536
+ @it.alarms.first.should be_kind_of(RiCal::Component::Alarm)
537
+ end
538
+ end
539
+
540
+ context ".export" do
541
+ require 'rubygems'
542
+ require 'tzinfo'
543
+
544
+ def date_time_with_tzinfo_zone(date_time, timezone="America/New_York")
545
+ date_time.dup.set_tzid(timezone)
546
+ end
547
+
548
+ # Undo the effects of RFC2445 line folding
549
+ def unfold(string)
550
+ string.gsub("\n ", "")
551
+ end
552
+
553
+ before(:each) do
554
+ cal = RiCal.Calendar
555
+ @it = RiCal::Component::Event.new(cal)
556
+ end
557
+
558
+ it "should cause a VTIMEZONE to be included for a dtstart with a local timezone" do
559
+ @it.dtstart = date_time_with_tzinfo_zone(DateTime.parse("April 22, 2009 17:55"), "America/New_York")
560
+ unfold(@it.export).should match(/BEGIN:VTIMEZONE\nTZID;X-RICAL-TZSOURCE=TZINFO:America\/New_York\n/)
561
+ end
562
+
563
+ it "should properly format dtstart with a UTC date-time" do
564
+ @it.dtstart = DateTime.parse("April 22, 2009 1:23:45").set_tzid("UTC")
565
+ unfold(@it.export).should match(/^DTSTART;VALUE=DATE-TIME:20090422T012345Z$/)
566
+ end
567
+
568
+ it "should properly format dtstart with a floating date-time" do
569
+ @it.dtstart = DateTime.parse("April 22, 2009 1:23:45").with_floating_timezone
570
+ unfold(@it.export).should match(/^DTSTART;VALUE=DATE-TIME:20090422T012345$/)
571
+ end
572
+
573
+ it "should properly format dtstart with a local time zone" do
574
+ @it.dtstart = date_time_with_tzinfo_zone(DateTime.parse("April 22, 2009 17:55"), "America/New_York")
575
+ unfold(@it.export).should match(/^DTSTART;TZID=America\/New_York;VALUE=DATE-TIME:20090422T175500$/)
576
+ end
577
+
578
+ it "should properly format dtstart with a date" do
579
+ @it.dtstart = Date.parse("April 22, 2009")
580
+ unfold(@it.export).should match(/^DTSTART;VALUE=DATE:20090422$/)
581
+ end
582
+
583
+ it "should properly fold on export when the description contains a carriage return" do
584
+ @it.description = "Weather report looks nice, 80 degrees and partly cloudy, so following Michael's suggestion, let's meet at the food court at Crossroads:\n\rhttp://www.shopcrossroadsplaza.c...\n"
585
+ export_string = @it.export
586
+ export_string.should match(%r(^DESCRIPTION:Weather report looks nice\\, 80 degrees and partly cloudy\\, so$))
587
+ export_string.should match(%r(^ following Michael's suggestion\\, let's meet at the food court at Crossr$))
588
+ export_string.should match(%r(^ oads:\\nhttp://www\.shopcrossroadsplaza.c\.\.\.\\n$))
589
+ end
590
+
591
+ it "should properly fold on export when the description contains multi-byte UTF-8 Characters" do
592
+ @it.description = "Juin 2009 <<Alliance Francaise Reunion>> lieu Café périferôl"
593
+ export_string = @it.export
594
+ export_string.should match(%r(^DESCRIPTION:Juin 2009 <<Alliance Francaise Reunion>> lieu Café périfer$))
595
+ export_string.should match(%r(^ ôl$))
596
+ end
597
+ end
598
+
599
+ if RiCal::TimeWithZone
600
+ context "with ActiveSupport loaded" do
601
+
602
+ context "an event with an timezoned exdate" do
603
+ before(:each) do
604
+ @old_timezone = Time.zone
605
+ Time.zone = "America/New_York"
606
+ @exception_date_time = Time.zone.local(2009, 5, 19, 11, 13)
607
+ cal = RiCal.Calendar do |cal|
608
+ cal.event do |event|
609
+ event.add_exdate @exception_date_time
610
+ end
611
+ end
612
+ @event = cal.events.first
613
+ end
614
+
615
+ after(:each) do
616
+ Time.zone = @old_timezone
617
+ end
618
+
619
+ it "should pickup the timezone in the exdate property" do
620
+ @event.exdate.first.first.tzid.should == "America/New_York"
621
+ end
622
+
623
+ it "should have the timezone in the ical representation of the exdate property" do
624
+ @event.exdate_property.first.to_s.should match(%r{;TZID=America/New_York[:;]})
625
+ end
626
+ end
627
+
628
+ context "An event in a non-tzinfo source calendar" do
629
+ before(:each) do
630
+ cals = RiCal.parse_string <<ENDCAL
631
+ BEGIN:VCALENDAR
632
+ X-WR-TIMEZONE:America/New_York
633
+ PRODID:-//Apple Inc.//iCal 3.0//EN
634
+ CALSCALE:GREGORIAN
635
+ BEGIN:VTIMEZONE
636
+ TZID:US/Eastern
637
+ BEGIN:DAYLIGHT
638
+ TZOFFSETFROM:-0500
639
+ TZOFFSETTO:-0400
640
+ DTSTART:20070311T020000
641
+ RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
642
+ TZNAME:EDT
643
+ END:DAYLIGHT
644
+ BEGIN:STANDARD
645
+ TZOFFSETFROM:-0400
646
+ TZOFFSETTO:-0500
647
+ DTSTART:20071104T020000
648
+ RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
649
+ TZNAME:EST
650
+ END:STANDARD
651
+ END:VTIMEZONE
652
+ BEGIN:VEVENT
653
+ SEQUENCE:5
654
+ TRANSP:OPAQUE
655
+ UID:00481E53-9258-4EA7-9F8D-947D3041A3F2
656
+ DTSTART;TZID=US/Eastern:20090224T090000
657
+ DTSTAMP:20090225T000908Z
658
+ SUMMARY:Test Event
659
+ CREATED:20090225T000839Z
660
+ DTEND;TZID=US/Eastern:20090224T100000
661
+ RRULE:FREQ=DAILY;INTERVAL=1;UNTIL=20090228T045959Z
662
+ END:VEVENT
663
+ END:VCALENDAR
664
+ ENDCAL
665
+ @event = cals.first.events.first
666
+ end
667
+
668
+ it "should produce a DateTime for dtstart" do
669
+ @event.dtstart.should be_instance_of(DateTime)
670
+ end
671
+ end
672
+
673
+ context "An event starting in Paris and ending in New York" do
674
+
675
+ before(:each) do
676
+ @start = Time.now.utc.in_time_zone("Europe/Paris")
677
+ @finish = Time.now.utc.in_time_zone("America/New_York")
678
+ cal = RiCal.Calendar do |ical|
679
+ ical.event do |ievent|
680
+ ievent.dtstart @start
681
+ ievent.dtend @finish
682
+ end
683
+ end
684
+ @event = cal.events.first
685
+ end
686
+
687
+ it "should have the right time zone for dtstart" do
688
+ @event.dtstart.tzid.should == "Europe/Paris"
689
+ end
690
+
691
+ it "should produce a TimeWithZone for dtstart" do
692
+ @event.dtstart.should be_instance_of(RiCal::TimeWithZone)
693
+ end
694
+
695
+ # ActiveRecord::TimeWithZone doesn't implement == as expected
696
+ it "should produce a dtstart which looks like the provided value" do
697
+ @event.dtstart.to_s.should == @start.to_s
698
+ end
699
+
700
+ it "should have the right time zone for dtend" do
701
+ @event.dtend.tzid.should == "America/New_York"
702
+ end
703
+
704
+ it "should produce a TimeWithZone for dtend" do
705
+ @event.dtend.should be_instance_of(RiCal::TimeWithZone)
706
+ end
707
+
708
+ # ActiveRecord::TimeWithZone doesn't implement == as expected
709
+ it "should produce a dtend which looks like the provided value" do
710
+ @event.dtend.to_s.should == @finish.to_s
711
+ end
712
+ end
713
+ end
714
+ end
715
+
716
+ context "An event with a floating start" do
717
+
718
+ before(:each) do
719
+ cal = RiCal.Calendar do |ical|
720
+ ical.event do |ievent|
721
+ ievent.dtstart "20090530T120000"
722
+ end
723
+ end
724
+ @event = cal.events.first
725
+ end
726
+
727
+ it "should produce a DateTime for dtstart" do
728
+ @event.dtstart.should be_instance_of(DateTime)
729
+ end
730
+
731
+ it "should have a floating dtstart" do
732
+ @event.dtstart.should have_floating_timezone
733
+ end
734
+ end
735
+ end