ri_cal 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. data/History.txt +45 -0
  2. data/Manifest.txt +129 -0
  3. data/README.txt +394 -0
  4. data/Rakefile +31 -0
  5. data/bin/ri_cal +8 -0
  6. data/component_attributes/alarm.yml +10 -0
  7. data/component_attributes/calendar.yml +4 -0
  8. data/component_attributes/component_property_defs.yml +180 -0
  9. data/component_attributes/event.yml +45 -0
  10. data/component_attributes/freebusy.yml +16 -0
  11. data/component_attributes/journal.yml +35 -0
  12. data/component_attributes/timezone.yml +3 -0
  13. data/component_attributes/timezone_period.yml +11 -0
  14. data/component_attributes/todo.yml +46 -0
  15. data/copyrights.txt +1 -0
  16. data/docs/draft-ietf-calsify-2446bis-08.txt +7280 -0
  17. data/docs/draft-ietf-calsify-rfc2445bis-09.txt +10416 -0
  18. data/docs/incrementers.txt +7 -0
  19. data/docs/rfc2445.pdf +0 -0
  20. data/lib/ri_cal.rb +144 -0
  21. data/lib/ri_cal/component.rb +247 -0
  22. data/lib/ri_cal/component/alarm.rb +21 -0
  23. data/lib/ri_cal/component/calendar.rb +219 -0
  24. data/lib/ri_cal/component/event.rb +60 -0
  25. data/lib/ri_cal/component/freebusy.rb +18 -0
  26. data/lib/ri_cal/component/journal.rb +30 -0
  27. data/lib/ri_cal/component/t_z_info_timezone.rb +123 -0
  28. data/lib/ri_cal/component/timezone.rb +196 -0
  29. data/lib/ri_cal/component/timezone/daylight_period.rb +25 -0
  30. data/lib/ri_cal/component/timezone/standard_period.rb +23 -0
  31. data/lib/ri_cal/component/timezone/timezone_period.rb +53 -0
  32. data/lib/ri_cal/component/todo.rb +43 -0
  33. data/lib/ri_cal/core_extensions.rb +6 -0
  34. data/lib/ri_cal/core_extensions/array.rb +7 -0
  35. data/lib/ri_cal/core_extensions/array/conversions.rb +15 -0
  36. data/lib/ri_cal/core_extensions/date.rb +13 -0
  37. data/lib/ri_cal/core_extensions/date/conversions.rb +61 -0
  38. data/lib/ri_cal/core_extensions/date_time.rb +15 -0
  39. data/lib/ri_cal/core_extensions/date_time/conversions.rb +50 -0
  40. data/lib/ri_cal/core_extensions/object.rb +8 -0
  41. data/lib/ri_cal/core_extensions/object/conversions.rb +20 -0
  42. data/lib/ri_cal/core_extensions/string.rb +8 -0
  43. data/lib/ri_cal/core_extensions/string/conversions.rb +63 -0
  44. data/lib/ri_cal/core_extensions/time.rb +13 -0
  45. data/lib/ri_cal/core_extensions/time/calculations.rb +153 -0
  46. data/lib/ri_cal/core_extensions/time/conversions.rb +61 -0
  47. data/lib/ri_cal/core_extensions/time/tzid_access.rb +50 -0
  48. data/lib/ri_cal/core_extensions/time/week_day_predicates.rb +88 -0
  49. data/lib/ri_cal/floating_timezone.rb +32 -0
  50. data/lib/ri_cal/invalid_property_value.rb +8 -0
  51. data/lib/ri_cal/invalid_timezone_identifer.rb +20 -0
  52. data/lib/ri_cal/occurrence_enumerator.rb +206 -0
  53. data/lib/ri_cal/occurrence_period.rb +17 -0
  54. data/lib/ri_cal/parser.rb +138 -0
  55. data/lib/ri_cal/properties/alarm.rb +390 -0
  56. data/lib/ri_cal/properties/calendar.rb +164 -0
  57. data/lib/ri_cal/properties/event.rb +1526 -0
  58. data/lib/ri_cal/properties/freebusy.rb +594 -0
  59. data/lib/ri_cal/properties/journal.rb +1240 -0
  60. data/lib/ri_cal/properties/timezone.rb +151 -0
  61. data/lib/ri_cal/properties/timezone_period.rb +416 -0
  62. data/lib/ri_cal/properties/todo.rb +1562 -0
  63. data/lib/ri_cal/property_value.rb +149 -0
  64. data/lib/ri_cal/property_value/array.rb +27 -0
  65. data/lib/ri_cal/property_value/cal_address.rb +11 -0
  66. data/lib/ri_cal/property_value/date.rb +175 -0
  67. data/lib/ri_cal/property_value/date_time.rb +335 -0
  68. data/lib/ri_cal/property_value/date_time/additive_methods.rb +44 -0
  69. data/lib/ri_cal/property_value/date_time/time_machine.rb +181 -0
  70. data/lib/ri_cal/property_value/date_time/timezone_support.rb +96 -0
  71. data/lib/ri_cal/property_value/duration.rb +110 -0
  72. data/lib/ri_cal/property_value/geo.rb +11 -0
  73. data/lib/ri_cal/property_value/integer.rb +12 -0
  74. data/lib/ri_cal/property_value/occurrence_list.rb +144 -0
  75. data/lib/ri_cal/property_value/period.rb +82 -0
  76. data/lib/ri_cal/property_value/recurrence_rule.rb +145 -0
  77. data/lib/ri_cal/property_value/recurrence_rule/enumeration_support_methods.rb +97 -0
  78. data/lib/ri_cal/property_value/recurrence_rule/enumerator.rb +79 -0
  79. data/lib/ri_cal/property_value/recurrence_rule/initialization_methods.rb +148 -0
  80. data/lib/ri_cal/property_value/recurrence_rule/negative_setpos_enumerator.rb +53 -0
  81. data/lib/ri_cal/property_value/recurrence_rule/numbered_span.rb +31 -0
  82. data/lib/ri_cal/property_value/recurrence_rule/occurence_incrementer.rb +793 -0
  83. data/lib/ri_cal/property_value/recurrence_rule/recurring_day.rb +131 -0
  84. data/lib/ri_cal/property_value/recurrence_rule/recurring_month_day.rb +60 -0
  85. data/lib/ri_cal/property_value/recurrence_rule/recurring_numbered_week.rb +33 -0
  86. data/lib/ri_cal/property_value/recurrence_rule/recurring_year_day.rb +49 -0
  87. data/lib/ri_cal/property_value/recurrence_rule/validations.rb +125 -0
  88. data/lib/ri_cal/property_value/text.rb +40 -0
  89. data/lib/ri_cal/property_value/uri.rb +11 -0
  90. data/lib/ri_cal/property_value/utc_offset.rb +33 -0
  91. data/lib/ri_cal/required_timezones.rb +55 -0
  92. data/ri_cal.gemspec +49 -0
  93. data/sample_ical_files/from_ical_dot_app/test1.ics +38 -0
  94. data/script/console +10 -0
  95. data/script/destroy +14 -0
  96. data/script/generate +14 -0
  97. data/script/txt2html +71 -0
  98. data/spec/ri_cal/component/alarm_spec.rb +12 -0
  99. data/spec/ri_cal/component/calendar_spec.rb +54 -0
  100. data/spec/ri_cal/component/event_spec.rb +601 -0
  101. data/spec/ri_cal/component/freebusy_spec.rb +12 -0
  102. data/spec/ri_cal/component/journal_spec.rb +37 -0
  103. data/spec/ri_cal/component/t_z_info_timezone_spec.rb +36 -0
  104. data/spec/ri_cal/component/timezone_spec.rb +218 -0
  105. data/spec/ri_cal/component/todo_spec.rb +112 -0
  106. data/spec/ri_cal/component_spec.rb +224 -0
  107. data/spec/ri_cal/core_extensions/string/conversions_spec.rb +78 -0
  108. data/spec/ri_cal/core_extensions/time/calculations_spec.rb +188 -0
  109. data/spec/ri_cal/core_extensions/time/week_day_predicates_spec.rb +45 -0
  110. data/spec/ri_cal/occurrence_enumerator_spec.rb +573 -0
  111. data/spec/ri_cal/parser_spec.rb +303 -0
  112. data/spec/ri_cal/property_value/date_spec.rb +53 -0
  113. data/spec/ri_cal/property_value/date_time_spec.rb +383 -0
  114. data/spec/ri_cal/property_value/duration_spec.rb +126 -0
  115. data/spec/ri_cal/property_value/occurrence_list_spec.rb +72 -0
  116. data/spec/ri_cal/property_value/period_spec.rb +49 -0
  117. data/spec/ri_cal/property_value/recurrence_rule/recurring_year_day_spec.rb +21 -0
  118. data/spec/ri_cal/property_value/recurrence_rule_spec.rb +1814 -0
  119. data/spec/ri_cal/property_value/text_spec.rb +25 -0
  120. data/spec/ri_cal/property_value/utc_offset_spec.rb +48 -0
  121. data/spec/ri_cal/property_value_spec.rb +125 -0
  122. data/spec/ri_cal/required_timezones_spec.rb +67 -0
  123. data/spec/ri_cal_spec.rb +53 -0
  124. data/spec/spec.opts +4 -0
  125. data/spec/spec_helper.rb +46 -0
  126. data/tasks/gem_loader/load_active_support.rb +3 -0
  127. data/tasks/gem_loader/load_tzinfo_gem.rb +2 -0
  128. data/tasks/ri_cal.rake +410 -0
  129. data/tasks/spec.rake +50 -0
  130. metadata +221 -0
@@ -0,0 +1,12 @@
1
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
2
+
3
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
4
+
5
+ describe RiCal::Component::Freebusy do
6
+
7
+ describe ".entity_name" do
8
+ it "should be VFREEBUSY" do
9
+ RiCal::Component::Freebusy.entity_name.should == "VFREEBUSY"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,37 @@
1
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
2
+
3
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
4
+
5
+ describe RiCal::Component::Journal do
6
+
7
+ describe ".entity_name" do
8
+ it "should be VJOURNAL" do
9
+ RiCal::Component::Journal.entity_name.should == "VJOURNAL"
10
+ end
11
+ end
12
+
13
+ context ".start_time" do
14
+ it "should be the same as dtstart for a date time" do
15
+ event = RiCal.Journal {|e| e.dtstart = "20090525T151900"}
16
+ event.start_time.should == DateTime.civil(2009,05,25,15,19,0,0)
17
+ end
18
+
19
+ it "should be the start of the day of dtstart for a date" do
20
+ event = RiCal.Journal {|e| e.dtstart = "20090525"}
21
+ event.start_time.should == DateTime.civil(2009,05,25,0,0,0,0)
22
+ end
23
+ end
24
+
25
+ context ".finish_time" do
26
+ it "should be the same as dtstart for a date time" do
27
+ event = RiCal.Journal {|e| e.dtstart = "20090525T151900"}
28
+ event.finish_time.should == DateTime.civil(2009,05,25,15,19,0,0)
29
+ end
30
+
31
+ it "should be the start of the day of dtstart for a date" do
32
+ event = RiCal.Journal {|e| e.dtstart = "20090525"}
33
+ event.finish_time.should == DateTime.civil(2009,05,25,0,0,0,0)
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,36 @@
1
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
2
+
3
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
4
+ require 'rubygems'
5
+ require 'tzinfo'
6
+
7
+ describe RiCal::Component::TZInfoTimezone do
8
+
9
+ it "should produce an rfc representation" do
10
+ tz = RiCal::Component::TZInfoTimezone.new(TZInfo::Timezone.get("America/New_York"))
11
+ local_first = DateTime.parse("Apr 10, 2007")
12
+ local_last = DateTime.parse("Apr 6, 2008")
13
+ utc_first = tz.local_to_utc(local_first)
14
+ utc_last = tz.local_to_utc(local_last)
15
+ rez = tz.to_rfc2445_string(utc_first, utc_last)
16
+ rez.should == <<-ENDDATA
17
+ BEGIN:VTIMEZONE
18
+ TZID;X-RICAL-TZSOURCE=TZINFO:America/New_York
19
+ BEGIN:DAYLIGHT
20
+ DTSTART:20070311T030000
21
+ RDATE:20070311T030000,20080309T030000
22
+ TZOFFSETFROM:-0500
23
+ TZOFFSETTO:-0400
24
+ TZNAME:EDT
25
+ END:DAYLIGHT
26
+ BEGIN:STANDARD
27
+ DTSTART:20071104T010000
28
+ RDATE:20071104T010000
29
+ TZOFFSETFROM:-0400
30
+ TZOFFSETTO:-0500
31
+ TZNAME:EST
32
+ END:STANDARD
33
+ END:VTIMEZONE
34
+ ENDDATA
35
+ end
36
+ end
@@ -0,0 +1,218 @@
1
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
2
+
3
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
4
+ require 'tzinfo'
5
+
6
+ describe RiCal::Component::Timezone do
7
+
8
+ context ".entity_name" do
9
+ it "should be VTIMEZONE" do
10
+ RiCal::Component::Timezone.entity_name.should == "VTIMEZONE"
11
+ end
12
+ end
13
+
14
+ context "from an iCal.app calendar for America/New_York starting March 11 2007" do
15
+ before(:each) do
16
+ @it = RiCal.parse_string <<TZEND
17
+ BEGIN:VTIMEZONE
18
+ TZID:US/Eastern
19
+ BEGIN:DAYLIGHT
20
+ TZOFFSETFROM:-0500
21
+ TZOFFSETTO:-0400
22
+ DTSTART:20070311T020000
23
+ RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
24
+ TZNAME:EDT
25
+ END:DAYLIGHT
26
+ BEGIN:STANDARD
27
+ TZOFFSETFROM:-0400
28
+ TZOFFSETTO:-0500
29
+ DTSTART:20071104T020000
30
+ RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
31
+ TZNAME:EST
32
+ END:STANDARD
33
+ END:VTIMEZONE
34
+ TZEND
35
+ @it = @it.first
36
+ end
37
+
38
+ it "should be a Timezone" do
39
+ @it.should be_kind_of(RiCal::Component::Timezone)
40
+ end
41
+
42
+ context ".local_to_utc" do
43
+ it "should produce 2/27/2009 18:00 UTC for 2/27/2009 13:00" do
44
+ expected = RiCal::PropertyValue::DateTime.new(nil, :value => "20090227T1800Z" )
45
+ @it.local_to_utc(DateTime.parse("Feb 27, 2009 13:00")).should == expected
46
+ end
47
+ end
48
+
49
+ context ".utc_to_local" do
50
+ it "should produce 2/27/2009 13:00 EST for 2/27/2009 18:00 UTC" do
51
+ expected = RiCal::PropertyValue::DateTime.new(nil, :params => {'TZID' => 'US/Eastern'}, :value => "20090227T1300" )
52
+ @it.utc_to_local(DateTime.parse("Feb 27, 2009 18:00")).should == expected
53
+ end
54
+ end
55
+
56
+ context ".period_for_local" do
57
+ it "should raise TZInfo::PeriodNotFound for an invalid local time, e.g. Mar 8, 2009 2:30" do
58
+ lambda {@it.period_for_local(DateTime.parse("Mar 8, 2009 2:30"))}.should raise_error(TZInfo::PeriodNotFound)
59
+ end
60
+
61
+ context "for an ambiguous local time , e.g. Nov 1, 2009 2:00" do
62
+ context "lacking a dst parameter or block" do
63
+ it "should raise TZInfo::AmbiguousTime" do
64
+ lambda {@it.period_for_local(DateTime.parse("Nov 1, 2009 2:00"))}.should raise_error(TZInfo::AmbiguousTime)
65
+ end
66
+ end
67
+
68
+ context "with a dst parameter" do
69
+ it "should return a dst period if the dst parameter is true" do
70
+ @it.period_for_local(DateTime.parse("Nov 1, 2009 2:00"), true).should be_dst
71
+ end
72
+
73
+ it "should return a std period if the dst parameter is false" do
74
+ @it.period_for_local(DateTime.parse("Nov 1, 2009 2:00"), false).should_not be_dst
75
+ end
76
+ end
77
+
78
+ context "with a block" do
79
+ it "should return a period if the block returns a TimezonePeriod" do
80
+ mock_period = ::RiCal::Component::Timezone::TimezonePeriod.new(nil)
81
+ @it.period_for_local(DateTime.parse("Nov 1, 2009 2:00")) { |results|
82
+ mock_period
83
+ }.should == mock_period
84
+ end
85
+
86
+ it "should return a period if the block returns a single element array" do
87
+ mock_period = :foo
88
+ @it.period_for_local(DateTime.parse("Nov 1, 2009 2:00")) { |results|
89
+ [ mock_period]
90
+ }.should == mock_period
91
+ end
92
+
93
+ it "should raise TZInfo::PeriodNotFound if the block returns a multi-element array" do
94
+ lambda {
95
+ @it.period_for_local(DateTime.parse("Mar 8, 2009 2:30")) {|results| [1,2]}
96
+ }.should raise_error(TZInfo::PeriodNotFound)
97
+ end
98
+
99
+ end
100
+ end
101
+ end
102
+
103
+ context ".periods_for_local" do
104
+ context "for the date on which DST begins springing ahead e.g. Mar 8, 2009" do
105
+ it "should return a 1 element array for 1 second before the transition time" do
106
+ @it.periods_for_local(DateTime.parse("Mar 8, 2009 1:59:59")).length.should == 1
107
+ end
108
+
109
+ it "should return an empty array for the transition time" do
110
+ @it.periods_for_local(DateTime.parse("Mar 8, 2009 2:00:00")).should == []
111
+ end
112
+
113
+ it "should return an empty array for 1 second after the transition time" do
114
+ @it.periods_for_local(DateTime.parse("Mar 8, 2009 2:00:01")).should == []
115
+ end
116
+
117
+ it "should return an empty array for 1 second before the spring ahead time" do
118
+ @it.periods_for_local(DateTime.parse("Mar 8, 2009 2:59:59")).should == []
119
+ end
120
+
121
+ it "should return a 1 element array for the spring ahead time" do
122
+ @it.periods_for_local(DateTime.parse("Mar 8, 2009 3:00:00")).length.should == 1
123
+ end
124
+ end
125
+
126
+ context "for the date on which DST ends falling back e.g. Nov 11, 2009" do
127
+ it "should return a 1 element array for 1 second before the transition time" do
128
+ @it.periods_for_local(DateTime.parse("Nov 1, 2009 1:59:59")).length.should == 1
129
+ end
130
+
131
+ it "should return a 2 element array for the transition time" do
132
+ @it.periods_for_local(DateTime.parse("Nov 1, 2009 2:00:00")).length.should == 2
133
+ end
134
+
135
+ it "should return a 2 element array for 1 second after the transition time" do
136
+ @it.periods_for_local(DateTime.parse("Nov 1, 2009 2:00:01")).length.should == 2
137
+ end
138
+
139
+ it "should return a 2 element array for 59 minutes and 59 seconds after the transition time" do
140
+ @it.periods_for_local(DateTime.parse("Nov 1, 2009 2:59:59")).length.should == 2
141
+ end
142
+
143
+ it "should return a 2 element array for 1 hour after the transition time" do
144
+ @it.periods_for_local(DateTime.parse("Nov 1, 2009 3:00:00")).length.should == 2
145
+ end
146
+
147
+ it "should return a 2 element array for 1 hour and 1 second after the transition time" do
148
+ @it.periods_for_local(DateTime.parse("Nov 1, 2009 3:00:01")).length.should == 2
149
+ end
150
+ end
151
+ end
152
+ end
153
+
154
+ context "Bug report from paulsm" do
155
+ before(:each) do
156
+ cals = RiCal.parse_string <<ENDCAL
157
+ BEGIN:VCALENDAR
158
+ X-WR-TIMEZONE:America/New_York
159
+ PRODID:-//Apple Inc.//iCal 3.0//EN
160
+ CALSCALE:GREGORIAN
161
+ X-WR-CALNAME:test
162
+ VERSION:2.0
163
+ X-WR-RELCALID:1884C7F8-BC8E-457F-94AC-297871967D5E
164
+ X-APPLE-CALENDAR-COLOR:#2CA10B
165
+ BEGIN:VTIMEZONE
166
+ TZID:US/Eastern
167
+ BEGIN:DAYLIGHT
168
+ TZOFFSETFROM:-0500
169
+ TZOFFSETTO:-0400
170
+ DTSTART:20070311T020000
171
+ RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
172
+ TZNAME:EDT
173
+ END:DAYLIGHT
174
+ BEGIN:STANDARD
175
+ TZOFFSETFROM:-0400
176
+ TZOFFSETTO:-0500
177
+ DTSTART:20071104T020000
178
+ RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
179
+ TZNAME:EST
180
+ END:STANDARD
181
+ END:VTIMEZONE
182
+ BEGIN:VEVENT
183
+ SEQUENCE:5
184
+ TRANSP:OPAQUE
185
+ UID:00481E53-9258-4EA7-9F8D-947D3041A3F2
186
+ DTSTART;TZID=US/Eastern:20090224T090000
187
+ DTSTAMP:20090225T000908Z
188
+ SUMMARY:Test Event
189
+ CREATED:20090225T000839Z
190
+ DTEND;TZID=US/Eastern:20090224T100000
191
+ RRULE:FREQ=DAILY;INTERVAL=1;UNTIL=20090228T045959Z
192
+ END:VEVENT
193
+ END:VCALENDAR
194
+ ENDCAL
195
+ @event = cals.first.events.first
196
+ end
197
+
198
+ context "the events dtstart" do
199
+ it "should be the right DateTime" do
200
+ @event.dtstart.should == DateTime.civil(2009, 2, 24, 9, 0, 0, Rational(-5, 24))
201
+ end
202
+
203
+ it "should have the right tzid" do
204
+ @event.dtstart.tzid.should == "US/Eastern"
205
+ end
206
+ end
207
+
208
+ context "the events dtend" do
209
+ it "should be the right DateTime" do
210
+ @event.dtend.should == DateTime.civil(2009, 2, 24, 10, 0, 0, Rational(-5, 24))
211
+ end
212
+
213
+ it "should have the right tzid" do
214
+ @event.dtend.tzid.should == "US/Eastern"
215
+ end
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,112 @@
1
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
2
+
3
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
4
+
5
+ describe RiCal::Component::Todo do
6
+
7
+ context ".start_time" do
8
+ it "should be the same as dtstart for a date time" do
9
+ todo = RiCal.Todo {|e| e.dtstart = "20090525T151900"}
10
+ todo.start_time.should == DateTime.civil(2009,05,25,15,19,0,0)
11
+ end
12
+
13
+ it "should be the start of the day of dtstart for a date" do
14
+ todo = RiCal.Todo {|e| e.dtstart = "20090525"}
15
+ todo.start_time.should == DateTime.civil(2009,05,25,0,0,0,0)
16
+ end
17
+
18
+ it "should be nil if the dtstart property is not set" do
19
+ RiCal.Todo.start_time.should be_nil
20
+ end
21
+ end
22
+
23
+ context ".finish_time" do
24
+ before(:each) do
25
+ @todo = RiCal.Todo {|t| t.dtstart = "20090525T151900"}
26
+ end
27
+
28
+ context "with a given due" do
29
+ it "should be the same as due for a date time" do
30
+ @todo.due = "20090525T161900"
31
+ @todo.finish_time.should == DateTime.civil(2009,05,25,16,19,0,0)
32
+ end
33
+ end
34
+
35
+ context "with no due" do
36
+ context "and a duration" do
37
+ before(:each) do
38
+ @todo.duration = "+P1H"
39
+ end
40
+
41
+ it "should be the dtstart plus the duration" do
42
+ @todo.finish_time.should == DateTime.civil(2009,5,25,16,19,0,0)
43
+ end
44
+
45
+ it "should be nil if the dtstart property is not set" do
46
+ @todo.dtstart_property = nil
47
+ @todo.finish_time.should be_nil
48
+ end
49
+ end
50
+
51
+ context "and no duration" do
52
+ it "should be nil" do
53
+ @todo.finish_time.should be_nil
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "with both due and duration specified" do
60
+ before(:each) do
61
+ @it = RiCal::Component::Todo.parse_string("BEGIN:VTODO\nDUE:19970903T190000Z\nDURATION:H1\nEND:VTODO").first
62
+ end
63
+
64
+ it "should be invalid" do
65
+ @it.should_not be_valid
66
+ end
67
+ end
68
+
69
+ describe "with a duration property" do
70
+ before(:each) do
71
+ @it = RiCal::Component::Todo.parse_string("BEGIN:VTODO\nDURATION:H1\nEND:VTODO").first
72
+ end
73
+
74
+ it "should have a duration property" do
75
+ @it.duration_property.should be
76
+ end
77
+
78
+ it "should have a duration of 1 Hour" do
79
+ @it.duration_property.value.should == "H1"
80
+ end
81
+
82
+ it "should reset the duration property if the due property is set" do
83
+ @it.due_property = "19970101T012345".to_ri_cal_date_time_value
84
+ @it.duration_property.should be_nil
85
+ end
86
+
87
+ it "should reset the duration property if the dtend ruby value is set" do
88
+ @it.due = "19970101"
89
+ @it.duration_property.should == nil
90
+ end
91
+ end
92
+
93
+ describe "with a due property" do
94
+ before(:each) do
95
+ @it = RiCal::Component::Todo.parse_string("BEGIN:VTODO\nDUE:19970903T190000Z\nEND:VTODO").first
96
+ end
97
+
98
+ it "should have a due property" do
99
+ @it.due_property.should be
100
+ end
101
+
102
+ it "should reset the due property if the duration property is set" do
103
+ @it.duration_property = "P1H".to_ri_cal_duration_value
104
+ @it.due_property.should be_nil
105
+ end
106
+
107
+ it "should reset the duration property if the dtend ruby value is set" do
108
+ @it.duration = "P1H"
109
+ @it.due_property.should == nil
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,224 @@
1
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
2
+
3
+ require File.join(File.dirname(__FILE__), %w[.. spec_helper])
4
+ require 'tzinfo'
5
+
6
+ describe RiCal::Component do
7
+
8
+ context "building blocks" do
9
+
10
+ context "building an empty calendar" do
11
+ before(:each) do
12
+ @it = RiCal.Calendar.to_s
13
+ end
14
+
15
+ it "should have the default prodid" do
16
+ @it.should match(%r{^PRODID;X-RICAL-TZSOURCE=TZINFO:-//com.denhaven2/NONSGML ri_cal gem//EN$})
17
+ end
18
+
19
+ it "should have the default calscale" do
20
+ @it.should match(%r{^CALSCALE:GREGORIAN$})
21
+ end
22
+
23
+ it "should have the default icalendar version" do
24
+ @it.should match(%r{^VERSION:2\.0$})
25
+ end
26
+ end
27
+
28
+ context "building a calendar with time zones" do
29
+ it 'should allow specifying the time zone identifier' do
30
+ event = RiCal.Event do
31
+ dtstart DateTime.parse("Feb 20, 1962 14:47:39").set_tzid('US/Pacific')
32
+ end
33
+ event.dtstart_property.should == dt_prop(DateTime.parse("Feb 20, 1962 14:47:39"), tzid = 'US/Pacific')
34
+ end
35
+
36
+ context "adding an exception date" do
37
+
38
+ before(:each) do
39
+ @cal = RiCal.Calendar do
40
+ event do
41
+ add_exdate 'US/Eastern', "19620220T144739"
42
+ end
43
+ end
44
+ @event = @cal.events.first
45
+ @prop = @event.exdate_property.first
46
+ end
47
+
48
+ it "should produce an OccurrenceList for the property" do
49
+ @prop.should be_instance_of(RiCal::PropertyValue::OccurrenceList)
50
+ end
51
+
52
+ it "should have a property with the right ical representation" do
53
+ @prop.to_s.should == ";TZID=US/Eastern:19620220T144739"
54
+ end
55
+
56
+ context "its ruby_value" do
57
+ it "should have the right value" do
58
+ @prop.ruby_value.should == [DateTime.civil(1962, 2, 20, 14, 47, 39, Rational(-5, 24))]
59
+ end
60
+
61
+ it "should have the right tzid" do
62
+ @prop.ruby_value.first.tzid.should == "US/Eastern"
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ context "with a block with 1 parameter" do
69
+ before(:each) do
70
+ @it = RiCal.Event do |event|
71
+ event.description = "MA-6 First US Manned Spaceflight"
72
+ event.dtstart = DateTime.parse("Feb 20, 1962 14:47:39")
73
+ event.dtend = DateTime.parse("Feb 20, 1962 19:43:02")
74
+ event.location = "Cape Canaveral"
75
+ event.add_attendee "john.glenn@nasa.gov"
76
+ event.alarm do
77
+ description "Segment 51"
78
+ end
79
+ event.alarm do |alarm|
80
+ alarm.description = "Second alarm"
81
+ end
82
+ end
83
+ end
84
+
85
+ it "should have the right description" do
86
+ @it.description.should == "MA-6 First US Manned Spaceflight"
87
+ end
88
+ it "should have the right dtstart" do
89
+ @it.dtstart.should == DateTime.parse("Feb 20, 1962 14:47:39")
90
+ end
91
+
92
+ it "should have a zulu time dtstart property" do
93
+ @it.dtstart_property.tzid.should == "UTC"
94
+ end
95
+
96
+ it "should have the right dtend" do
97
+ @it.dtend.should == DateTime.parse("Feb 20, 1962 19:43:02")
98
+ end
99
+
100
+ it "should have a zulu time dtend property" do
101
+ @it.dtend_property.tzid.should == "UTC"
102
+ end
103
+
104
+ it "should have the right location" do
105
+ @it.location.should == "Cape Canaveral"
106
+ end
107
+
108
+ it "should have the right attendee" do
109
+ @it.attendee.should include("john.glenn@nasa.gov")
110
+ end
111
+
112
+ it "should have 2 alarms" do
113
+ @it.alarms.length.should == 2
114
+ end
115
+
116
+ it ".the alarms should have the right description" do
117
+ @it.alarms.first.description.should == "Segment 51"
118
+ @it.alarms.last.description.should == "Second alarm"
119
+ end
120
+ end
121
+
122
+ context "building an event for MA-6" do
123
+ before(:each) do
124
+ @it = RiCal.Event do
125
+ description "MA-6 First US Manned Spaceflight"
126
+ dtstart DateTime.parse("Feb 20, 1962 14:47:39")
127
+ dtend DateTime.parse("Feb 20, 1962 19:43:02")
128
+ location "Cape Canaveral"
129
+ add_attendee "john.glenn@nasa.gov"
130
+ alarm do
131
+ description "Segment 51"
132
+ end
133
+ end
134
+ end
135
+
136
+ it "should have the right description" do
137
+ @it.description.should == "MA-6 First US Manned Spaceflight"
138
+ end
139
+
140
+ it "should have the right dtstart" do
141
+ @it.dtstart.should == DateTime.parse("Feb 20, 1962 14:47:39")
142
+ end
143
+
144
+ it "should have a zulu time dtstart property" do
145
+ @it.dtstart_property.tzid.should == "UTC"
146
+ end
147
+
148
+ it "should have the right dtend" do
149
+ @it.dtend.should == DateTime.parse("Feb 20, 1962 19:43:02")
150
+ end
151
+
152
+ it "should have a zulu time dtend property" do
153
+ @it.dtend_property.tzid.should == "UTC"
154
+ end
155
+
156
+ it "should have the right location" do
157
+ @it.location.should == "Cape Canaveral"
158
+ end
159
+
160
+ it "should have the right attendee" do
161
+ @it.attendee.should include("john.glenn@nasa.gov")
162
+ end
163
+
164
+ it "should have 1 alarm" do
165
+ @it.alarms.length.should == 1
166
+ end
167
+
168
+ it "should have an alarm with the right description" do
169
+ @it.alarms.first.description.should == "Segment 51"
170
+ end
171
+ end
172
+
173
+ context "building a complex calendar" do
174
+
175
+ before(:each) do
176
+ @it = RiCal.Calendar do
177
+ add_x_property 'x_wr_calname', 'My Personal Calendar'
178
+ event do
179
+ summary 'A Recurring Event'
180
+ description "This is some really long note content. It should be appropriately folded in the generated file.\nCarriage returns should work, too."
181
+ dtstart DateTime.parse('Feb 20, 2009 20:30:00')
182
+ dtend DateTime.parse('Feb 20, 2009 21:30:00')
183
+ location 'North Carolina'
184
+ dtstamp Time.now
185
+ rrule :freq => 'daily', :interval => 1
186
+ end
187
+ end
188
+ end
189
+
190
+ it 'should have an x_wr_calname property with the value "My Personal Calendar"' do
191
+ @it.x_wr_calname.should == "My Personal Calendar"
192
+ end
193
+
194
+ context "event with a long description and a dsl built recurence rule" do
195
+ before(:each) do
196
+ @cal = @it
197
+ @it = @cal.events.first
198
+ end
199
+
200
+ context "its description" do
201
+ it "should pass through correctly" do
202
+ @it.description.should == "This is some really long note content. It should be appropriately folded in the generated file.\nCarriage returns should work, too."
203
+ end
204
+ end
205
+
206
+ context "its rrule" do
207
+
208
+ it "should have a 1 rrule" do
209
+ @it.rrule.length.should == 1
210
+ end
211
+
212
+ it "should have the right rrule" do
213
+ @it.rrule.first.should == "FREQ=DAILY"
214
+ end
215
+
216
+ it "should have the right rrule hash" do
217
+ @it.rrule_property.first.to_options_hash.should == {:freq => 'DAILY', :interval => 1}
218
+ end
219
+ end
220
+ end
221
+ end
222
+
223
+ end
224
+ end