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.
Files changed (167) hide show
  1. checksums.yaml +7 -0
  2. data/History.txt +402 -0
  3. data/Manifest.txt +161 -0
  4. data/README.txt +410 -0
  5. data/Rakefile +69 -0
  6. data/VERSION +1 -0
  7. data/bin/ri_cal +8 -0
  8. data/component_attributes/alarm.yml +10 -0
  9. data/component_attributes/calendar.yml +4 -0
  10. data/component_attributes/component_property_defs.yml +180 -0
  11. data/component_attributes/event.yml +45 -0
  12. data/component_attributes/freebusy.yml +16 -0
  13. data/component_attributes/journal.yml +35 -0
  14. data/component_attributes/timezone.yml +3 -0
  15. data/component_attributes/timezone_period.yml +11 -0
  16. data/component_attributes/todo.yml +46 -0
  17. data/copyrights.txt +1 -0
  18. data/docs/draft-ietf-calsify-2446bis-08.txt +7280 -0
  19. data/docs/draft-ietf-calsify-rfc2445bis-09.txt +10416 -0
  20. data/docs/incrementers.txt +7 -0
  21. data/docs/rfc2445.pdf +0 -0
  22. data/lib/ri_cal/component/alarm.rb +19 -0
  23. data/lib/ri_cal/component/calendar.rb +257 -0
  24. data/lib/ri_cal/component/event.rb +58 -0
  25. data/lib/ri_cal/component/freebusy.rb +16 -0
  26. data/lib/ri_cal/component/journal.rb +27 -0
  27. data/lib/ri_cal/component/non_standard.rb +33 -0
  28. data/lib/ri_cal/component/t_z_info_timezone.rb +153 -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 +76 -0
  32. data/lib/ri_cal/component/timezone.rb +197 -0
  33. data/lib/ri_cal/component/todo.rb +42 -0
  34. data/lib/ri_cal/component.rb +256 -0
  35. data/lib/ri_cal/core_extensions/array/conversions.rb +15 -0
  36. data/lib/ri_cal/core_extensions/array.rb +7 -0
  37. data/lib/ri_cal/core_extensions/date/conversions.rb +56 -0
  38. data/lib/ri_cal/core_extensions/date.rb +13 -0
  39. data/lib/ri_cal/core_extensions/date_time/conversions.rb +50 -0
  40. data/lib/ri_cal/core_extensions/date_time.rb +15 -0
  41. data/lib/ri_cal/core_extensions/object/conversions.rb +20 -0
  42. data/lib/ri_cal/core_extensions/object.rb +8 -0
  43. data/lib/ri_cal/core_extensions/string/conversions.rb +57 -0
  44. data/lib/ri_cal/core_extensions/string.rb +8 -0
  45. data/lib/ri_cal/core_extensions/time/calculations.rb +153 -0
  46. data/lib/ri_cal/core_extensions/time/conversions.rb +42 -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 +55 -0
  49. data/lib/ri_cal/core_extensions/time.rb +14 -0
  50. data/lib/ri_cal/core_extensions.rb +11 -0
  51. data/lib/ri_cal/fast_date_time.rb +234 -0
  52. data/lib/ri_cal/floating_timezone.rb +32 -0
  53. data/lib/ri_cal/invalid_property_value.rb +8 -0
  54. data/lib/ri_cal/invalid_timezone_identifier.rb +20 -0
  55. data/lib/ri_cal/occurrence_enumerator.rb +265 -0
  56. data/lib/ri_cal/occurrence_period.rb +17 -0
  57. data/lib/ri_cal/parser.rb +148 -0
  58. data/lib/ri_cal/properties/alarm.rb +390 -0
  59. data/lib/ri_cal/properties/calendar.rb +164 -0
  60. data/lib/ri_cal/properties/event.rb +1523 -0
  61. data/lib/ri_cal/properties/freebusy.rb +593 -0
  62. data/lib/ri_cal/properties/journal.rb +1237 -0
  63. data/lib/ri_cal/properties/timezone.rb +150 -0
  64. data/lib/ri_cal/properties/timezone_period.rb +416 -0
  65. data/lib/ri_cal/properties/todo.rb +1559 -0
  66. data/lib/ri_cal/properties.rb +12 -0
  67. data/lib/ri_cal/property_value/array.rb +27 -0
  68. data/lib/ri_cal/property_value/cal_address.rb +11 -0
  69. data/lib/ri_cal/property_value/date.rb +184 -0
  70. data/lib/ri_cal/property_value/date_time/additive_methods.rb +44 -0
  71. data/lib/ri_cal/property_value/date_time/time_machine.rb +159 -0
  72. data/lib/ri_cal/property_value/date_time/timezone_support.rb +100 -0
  73. data/lib/ri_cal/property_value/date_time.rb +359 -0
  74. data/lib/ri_cal/property_value/duration.rb +110 -0
  75. data/lib/ri_cal/property_value/geo.rb +11 -0
  76. data/lib/ri_cal/property_value/integer.rb +12 -0
  77. data/lib/ri_cal/property_value/occurrence_list.rb +144 -0
  78. data/lib/ri_cal/property_value/period.rb +86 -0
  79. data/lib/ri_cal/property_value/recurrence_rule/enumeration_support_methods.rb +100 -0
  80. data/lib/ri_cal/property_value/recurrence_rule/enumerator.rb +79 -0
  81. data/lib/ri_cal/property_value/recurrence_rule/initialization_methods.rb +148 -0
  82. data/lib/ri_cal/property_value/recurrence_rule/negative_setpos_enumerator.rb +53 -0
  83. data/lib/ri_cal/property_value/recurrence_rule/numbered_span.rb +31 -0
  84. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_day_incrementer.rb +86 -0
  85. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_hour_incrementer.rb +31 -0
  86. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_minute_incrementer.rb +32 -0
  87. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_month_incrementer.rb +52 -0
  88. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_monthday_incrementer.rb +31 -0
  89. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_numbered_day_incrementer.rb +38 -0
  90. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_second_incrementer.rb +32 -0
  91. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_weekno_incrementer.rb +69 -0
  92. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_yearday_incrementer.rb +31 -0
  93. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/daily_incrementer.rb +28 -0
  94. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/frequency_incrementer.rb +80 -0
  95. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/hourly_incrementer.rb +23 -0
  96. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/list_incrementer.rb +106 -0
  97. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/minutely_incrementer.rb +23 -0
  98. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/monthly_incrementer.rb +33 -0
  99. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/null_sub_cycle_incrementer.rb +43 -0
  100. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/secondly_incrementer.rb +28 -0
  101. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/weekly_incrementer.rb +37 -0
  102. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/yearly_incrementer.rb +57 -0
  103. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer.rb +135 -0
  104. data/lib/ri_cal/property_value/recurrence_rule/recurring_day.rb +131 -0
  105. data/lib/ri_cal/property_value/recurrence_rule/recurring_month_day.rb +64 -0
  106. data/lib/ri_cal/property_value/recurrence_rule/recurring_numbered_week.rb +33 -0
  107. data/lib/ri_cal/property_value/recurrence_rule/recurring_year_day.rb +53 -0
  108. data/lib/ri_cal/property_value/recurrence_rule/time_manipulation.rb +42 -0
  109. data/lib/ri_cal/property_value/recurrence_rule/validations.rb +125 -0
  110. data/lib/ri_cal/property_value/recurrence_rule.rb +154 -0
  111. data/lib/ri_cal/property_value/text.rb +44 -0
  112. data/lib/ri_cal/property_value/uri.rb +11 -0
  113. data/lib/ri_cal/property_value/utc_offset.rb +33 -0
  114. data/lib/ri_cal/property_value/zulu_date_time.rb +34 -0
  115. data/lib/ri_cal/property_value.rb +159 -0
  116. data/lib/ri_cal/required_timezones.rb +55 -0
  117. data/lib/ri_cal.rb +187 -0
  118. data/parked_specs/ri_cal/claudio_a_bug_spec.rb +100 -0
  119. data/performance/empty_propval/subject.rb +43 -0
  120. data/performance/paris_eastern/subject.rb +90 -0
  121. data/performance/penultimate_weekday/subject.rb +15 -0
  122. data/performance/psm_big_enum/ical.ics +3171 -0
  123. data/performance/psm_big_enum/subject.rb +16 -0
  124. data/performance/utah_cycling/subject.rb +55 -0
  125. data/ri_cal.gemspec +244 -0
  126. data/script/benchmark_subject +23 -0
  127. data/script/console +10 -0
  128. data/script/destroy +14 -0
  129. data/script/generate +14 -0
  130. data/script/profile_subject +29 -0
  131. data/script/txt2html +71 -0
  132. data/spec/ri_cal/bugreports_spec.rb +276 -0
  133. data/spec/ri_cal/component/alarm_spec.rb +12 -0
  134. data/spec/ri_cal/component/calendar_spec.rb +88 -0
  135. data/spec/ri_cal/component/event_spec.rb +735 -0
  136. data/spec/ri_cal/component/freebusy_spec.rb +12 -0
  137. data/spec/ri_cal/component/journal_spec.rb +37 -0
  138. data/spec/ri_cal/component/t_z_info_timezone_spec.rb +60 -0
  139. data/spec/ri_cal/component/timezone_spec.rb +236 -0
  140. data/spec/ri_cal/component/todo_spec.rb +112 -0
  141. data/spec/ri_cal/component_spec.rb +224 -0
  142. data/spec/ri_cal/core_extensions/string/conversions_spec.rb +78 -0
  143. data/spec/ri_cal/core_extensions/time/calculations_spec.rb +188 -0
  144. data/spec/ri_cal/core_extensions/time/week_day_predicates_spec.rb +45 -0
  145. data/spec/ri_cal/fast_date_time_spec.rb +77 -0
  146. data/spec/ri_cal/inf_loop_spec.rb +78 -0
  147. data/spec/ri_cal/occurrence_enumerator_spec.rb +611 -0
  148. data/spec/ri_cal/parser_spec.rb +337 -0
  149. data/spec/ri_cal/property_value/date_spec.rb +53 -0
  150. data/spec/ri_cal/property_value/date_time_spec.rb +383 -0
  151. data/spec/ri_cal/property_value/duration_spec.rb +126 -0
  152. data/spec/ri_cal/property_value/occurrence_list_spec.rb +72 -0
  153. data/spec/ri_cal/property_value/period_spec.rb +63 -0
  154. data/spec/ri_cal/property_value/recurrence_rule/recurring_year_day_spec.rb +21 -0
  155. data/spec/ri_cal/property_value/recurrence_rule_spec.rb +1814 -0
  156. data/spec/ri_cal/property_value/text_spec.rb +25 -0
  157. data/spec/ri_cal/property_value/utc_offset_spec.rb +48 -0
  158. data/spec/ri_cal/property_value_spec.rb +125 -0
  159. data/spec/ri_cal/required_timezones_spec.rb +67 -0
  160. data/spec/ri_cal_spec.rb +53 -0
  161. data/spec/spec.opts +4 -0
  162. data/spec/spec_helper.rb +50 -0
  163. data/tasks/gem_loader/load_active_support.rb +3 -0
  164. data/tasks/gem_loader/load_tzinfo_gem.rb +2 -0
  165. data/tasks/ri_cal.rake +412 -0
  166. data/tasks/spec.rake +102 -0
  167. metadata +246 -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,60 @@
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
+ # Uncomment the next two lines to run this spec in textmate
5
+ # require 'rubygems'
6
+ # require 'tzinfo'
7
+
8
+ describe RiCal::Component::TZInfoTimezone do
9
+
10
+ it "should produce an rfc representation" do
11
+ tz = RiCal::Component::TZInfoTimezone.new(TZInfo::Timezone.get("America/New_York"))
12
+ local_first = DateTime.parse("Apr 10, 2007")
13
+ local_last = DateTime.parse("Apr 6, 2008")
14
+ utc_first = tz.local_to_utc(local_first)
15
+ utc_last = tz.local_to_utc(local_last)
16
+ rez = tz.to_rfc2445_string(utc_first, utc_last)
17
+ rez.should == <<-ENDDATA
18
+ BEGIN:VTIMEZONE
19
+ TZID;X-RICAL-TZSOURCE=TZINFO:America/New_York
20
+ BEGIN:DAYLIGHT
21
+ DTSTART:20070311T020000
22
+ RDATE:20070311T020000
23
+ RDATE:20080309T020000
24
+ TZOFFSETFROM:-0500
25
+ TZOFFSETTO:-0400
26
+ TZNAME:EDT
27
+ END:DAYLIGHT
28
+ BEGIN:STANDARD
29
+ DTSTART:20071104T020000
30
+ RDATE:20071104T020000
31
+ TZOFFSETFROM:-0400
32
+ TZOFFSETTO:-0500
33
+ TZNAME:EST
34
+ END:STANDARD
35
+ END:VTIMEZONE
36
+ ENDDATA
37
+ end
38
+
39
+ TZInfo::Timezone.all_identifiers.each do |tz|
40
+ context "TZInfo timezone #{tz}" do
41
+ before(:each) do
42
+ @calendar = RiCal.Calendar do |cal|
43
+ cal.event do |event|
44
+ event.description = "test"
45
+ event.dtstart = "TZID=#{tz}:20090530T123000"
46
+ event.dtend = "TZID=#{tz}:20090530T123001"
47
+ end
48
+ end
49
+ end
50
+ it "should be allowed as a tzid" do
51
+ lambda {@calendar.export}.should_not raise_error
52
+ end
53
+ unless tz == "UTC"
54
+ it "should produce at least one period in the VTIMEZONE" do
55
+ @calendar.export.should match(/BEGIN:(STANDARD|DAYLIGHT)/)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,236 @@
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 "for a Timezone with no DST periods" do
15
+ before(:each) do
16
+ @it = RiCal.parse_string rectify_ical(<<-'ENDCAL')
17
+ BEGIN:VTIMEZONE
18
+ TZID:Australia/Brisbane
19
+ X-LIC-LOCATION:Australia/Brisbane
20
+ BEGIN:STANDARD
21
+ TZOFFSETFROM:+1000
22
+ TZOFFSETTO:+1000
23
+ TZNAME:EST
24
+ DTSTART:19700101T000000
25
+ END:STANDARD
26
+ END:VTIMEZONE
27
+ ENDCAL
28
+ @it = @it.first
29
+ end
30
+
31
+ context ".periods_for_local" do
32
+ it "should return a single period" do
33
+ @it.periods_for_local(DateTime.parse("20090530T100000")).length.should == 1
34
+ end
35
+ end
36
+ end
37
+
38
+ context "from an iCal.app calendar for America/New_York starting March 11 2007" do
39
+ before(:each) do
40
+ @it = RiCal.parse_string rectify_ical(<<-'ENDCAL')
41
+ BEGIN:VTIMEZONE
42
+ TZID:US/Eastern
43
+ BEGIN:DAYLIGHT
44
+ TZOFFSETFROM:-0500
45
+ TZOFFSETTO:-0400
46
+ DTSTART:20070311T020000
47
+ RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
48
+ TZNAME:EDT
49
+ END:DAYLIGHT
50
+ BEGIN:STANDARD
51
+ TZOFFSETFROM:-0400
52
+ TZOFFSETTO:-0500
53
+ DTSTART:20071104T020000
54
+ RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
55
+ TZNAME:EST
56
+ END:STANDARD
57
+ END:VTIMEZONE
58
+ ENDCAL
59
+ @it = @it.first
60
+ end
61
+
62
+ it "should be a Timezone" do
63
+ @it.should be_kind_of(RiCal::Component::Timezone)
64
+ end
65
+
66
+ context ".local_to_utc" do
67
+ it "should produce 2/27/2009 18:00 UTC for 2/27/2009 13:00" do
68
+ expected = RiCal::PropertyValue::DateTime.new(nil, :value => "20090227T1800Z" )
69
+ @it.local_to_utc(DateTime.parse("Feb 27, 2009 13:00")).should == expected
70
+ end
71
+ end
72
+
73
+ context ".utc_to_local" do
74
+ it "should produce 2/27/2009 13:00 EST for 2/27/2009 18:00 UTC" do
75
+ expected = RiCal::PropertyValue::DateTime.new(nil, :params => {'TZID' => 'US/Eastern'}, :value => "20090227T1300" )
76
+ @it.utc_to_local(DateTime.parse("Feb 27, 2009 18:00")).should == expected
77
+ end
78
+ end
79
+
80
+ context ".period_for_local" do
81
+ it "should raise TZInfo::PeriodNotFound for an invalid local time, e.g. Mar 8, 2009 2:30" do
82
+ lambda {@it.period_for_local(DateTime.parse("Mar 8, 2009 2:30"))}.should raise_error(TZInfo::PeriodNotFound)
83
+ end
84
+
85
+ context "for an ambiguous local time , e.g. Nov 1, 2009 2:00" do
86
+ context "lacking a dst parameter or block" do
87
+ it "should raise TZInfo::AmbiguousTime" do
88
+ lambda {@it.period_for_local(DateTime.parse("Nov 1, 2009 2:00"))}.should raise_error(TZInfo::AmbiguousTime)
89
+ end
90
+ end
91
+
92
+ context "with a dst parameter" do
93
+ it "should return a dst period if the dst parameter is true" do
94
+ @it.period_for_local(DateTime.parse("Nov 1, 2009 2:00"), true).should be_dst
95
+ end
96
+
97
+ it "should return a std period if the dst parameter is false" do
98
+ @it.period_for_local(DateTime.parse("Nov 1, 2009 2:00"), false).should_not be_dst
99
+ end
100
+ end
101
+
102
+ context "with a block" do
103
+ it "should return a period if the block returns a TimezonePeriod" do
104
+ mock_period = ::RiCal::Component::Timezone::TimezonePeriod.new(nil)
105
+ @it.period_for_local(DateTime.parse("Nov 1, 2009 2:00")) { |results| mock_period}.should == mock_period
106
+ end
107
+
108
+ it "should return a period if the block returns a single element array" do
109
+ mock_period = :foo
110
+ @it.period_for_local(DateTime.parse("Nov 1, 2009 2:00")) { |results| [ mock_period]}.should == mock_period
111
+ end
112
+
113
+ it "should raise TZInfo::PeriodNotFound if the block returns a multi-element array" do
114
+ lambda {
115
+ @it.period_for_local(DateTime.parse("Mar 8, 2009 2:30")) {|results| [1,2]}}.should raise_error(TZInfo::PeriodNotFound)
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ context ".periods_for_local" do
122
+ context "for the date on which DST begins springing ahead e.g. Mar 8, 2009" do
123
+ it "should return a 1 element array for 1 second before the transition time" do
124
+ @it.periods_for_local(DateTime.parse("Mar 8, 2009 1:59:59")).length.should == 1
125
+ end
126
+
127
+ it "should return an empty array for the transition time" do
128
+ @it.periods_for_local(DateTime.parse("Mar 8, 2009 2:00:00")).should == []
129
+ end
130
+
131
+ it "should return an empty array for 1 second after the transition time" do
132
+ @it.periods_for_local(DateTime.parse("Mar 8, 2009 2:00:01")).should == []
133
+ end
134
+
135
+ it "should return an empty array for 1 second before the spring ahead time" do
136
+ @it.periods_for_local(DateTime.parse("Mar 8, 2009 2:59:59")).should == []
137
+ end
138
+
139
+ it "should return a 1 element array for the spring ahead time" do
140
+ @it.periods_for_local(DateTime.parse("Mar 8, 2009 3:00:00")).length.should == 1
141
+ end
142
+ end
143
+
144
+ context "for the date on which DST ends falling back e.g. Nov 11, 2009" do
145
+ it "should return a 1 element array for 1 second before the transition time" do
146
+ @it.periods_for_local(DateTime.parse("Nov 1, 2009 1:59:59")).length.should == 1
147
+ end
148
+
149
+ it "should return a 2 element array for the transition time" do
150
+ @it.periods_for_local(DateTime.parse("Nov 1, 2009 2:00:00")).length.should == 2
151
+ end
152
+
153
+ it "should return a 2 element array for 1 second after the transition time" do
154
+ @it.periods_for_local(DateTime.parse("Nov 1, 2009 2:00:01")).length.should == 2
155
+ end
156
+
157
+ it "should return a 2 element array for 59 minutes and 59 seconds after the transition time" do
158
+ @it.periods_for_local(DateTime.parse("Nov 1, 2009 2:59:59")).length.should == 2
159
+ end
160
+
161
+ it "should return a 2 element array for 1 hour after the transition time" do
162
+ @it.periods_for_local(DateTime.parse("Nov 1, 2009 3:00:00")).length.should == 2
163
+ end
164
+
165
+ it "should return a 2 element array for 1 hour and 1 second after the transition time" do
166
+ @it.periods_for_local(DateTime.parse("Nov 1, 2009 3:00:01")).length.should == 2
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ context "Bug report from paulsm" do
173
+ before(:each) do
174
+ cals = RiCal.parse_string rectify_ical(<<-'ENDCAL')
175
+ BEGIN:VCALENDAR
176
+ X-WR-TIMEZONE:America/New_York
177
+ PRODID:-//Apple Inc.//iCal 3.0//EN
178
+ CALSCALE:GREGORIAN
179
+ X-WR-CALNAME:test
180
+ VERSION:2.0
181
+ X-WR-RELCALID:1884C7F8-BC8E-457F-94AC-297871967D5E
182
+ X-APPLE-CALENDAR-COLOR:#2CA10B
183
+ BEGIN:VTIMEZONE
184
+ TZID:US/Eastern
185
+ BEGIN:DAYLIGHT
186
+ TZOFFSETFROM:-0500
187
+ TZOFFSETTO:-0400
188
+ DTSTART:20070311T020000
189
+ RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
190
+ TZNAME:EDT
191
+ END:DAYLIGHT
192
+ BEGIN:STANDARD
193
+ TZOFFSETFROM:-0400
194
+ TZOFFSETTO:-0500
195
+ DTSTART:20071104T020000
196
+ RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
197
+ TZNAME:EST
198
+ END:STANDARD
199
+ END:VTIMEZONE
200
+ BEGIN:VEVENT
201
+ SEQUENCE:5
202
+ TRANSP:OPAQUE
203
+ UID:00481E53-9258-4EA7-9F8D-947D3041A3F2
204
+ DTSTART;TZID=US/Eastern:20090224T090000
205
+ DTSTAMP:20090225T000908Z
206
+ SUMMARY:Test Event
207
+ CREATED:20090225T000839Z
208
+ DTEND;TZID=US/Eastern:20090224T100000
209
+ RRULE:FREQ=DAILY;INTERVAL=1;UNTIL=20090228T045959Z
210
+ END:VEVENT
211
+ END:VCALENDAR
212
+ ENDCAL
213
+ @event = cals.first.events.first
214
+ end
215
+
216
+ context "the events dtstart" do
217
+ it "should be the right DateTime" do
218
+ @event.dtstart.should == DateTime.civil(2009, 2, 24, 9, 0, 0, Rational(-5, 24))
219
+ end
220
+
221
+ it "should have the right tzid" do
222
+ @event.dtstart.tzid.should == "US/Eastern"
223
+ end
224
+ end
225
+
226
+ context "the events dtend" do
227
+ it "should be the right DateTime" do
228
+ @event.dtend.should == DateTime.civil(2009, 2, 24, 10, 0, 0, Rational(-5, 24))
229
+ end
230
+
231
+ it "should have the right tzid" do
232
+ @event.dtend.tzid.should == "US/Eastern"
233
+ end
234
+ end
235
+ end
236
+ 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 = "+PT1H"
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 = "PT1H".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 = "PT1H"
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', true
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.first.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