sdague-icalendar 1.0.2.1

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 (47) hide show
  1. data/COPYING +56 -0
  2. data/GPL +340 -0
  3. data/README +263 -0
  4. data/Rakefile +110 -0
  5. data/docs/api/STUB +0 -0
  6. data/docs/rfcs/itip_notes.txt +69 -0
  7. data/docs/rfcs/rfc2425.pdf +0 -0
  8. data/docs/rfcs/rfc2426.pdf +0 -0
  9. data/docs/rfcs/rfc2445.pdf +0 -0
  10. data/docs/rfcs/rfc2446.pdf +0 -0
  11. data/docs/rfcs/rfc2447.pdf +0 -0
  12. data/docs/rfcs/rfc3283.txt +738 -0
  13. data/examples/create_cal.rb +45 -0
  14. data/examples/parse_cal.rb +20 -0
  15. data/examples/single_event.ics +18 -0
  16. data/lib/hash_attrs.rb +34 -0
  17. data/lib/icalendar.rb +36 -0
  18. data/lib/icalendar/base.rb +43 -0
  19. data/lib/icalendar/calendar.rb +111 -0
  20. data/lib/icalendar/component.rb +438 -0
  21. data/lib/icalendar/component/alarm.rb +44 -0
  22. data/lib/icalendar/component/event.rb +129 -0
  23. data/lib/icalendar/component/freebusy.rb +37 -0
  24. data/lib/icalendar/component/journal.rb +61 -0
  25. data/lib/icalendar/component/timezone.rb +105 -0
  26. data/lib/icalendar/component/todo.rb +64 -0
  27. data/lib/icalendar/conversions.rb +144 -0
  28. data/lib/icalendar/helpers.rb +109 -0
  29. data/lib/icalendar/parameter.rb +33 -0
  30. data/lib/icalendar/parser.rb +485 -0
  31. data/lib/meta.rb +32 -0
  32. data/test/calendar_test.rb +71 -0
  33. data/test/component/event_test.rb +220 -0
  34. data/test/component/timezone_test.rb +67 -0
  35. data/test/component/todo_test.rb +13 -0
  36. data/test/component_test.rb +66 -0
  37. data/test/conversions_test.rb +97 -0
  38. data/test/coverage/STUB +0 -0
  39. data/test/fixtures/folding.ics +23 -0
  40. data/test/fixtures/life.ics +46 -0
  41. data/test/fixtures/simplecal.ics +119 -0
  42. data/test/fixtures/single_event.ics +23 -0
  43. data/test/interactive.rb +17 -0
  44. data/test/parameter_test.rb +29 -0
  45. data/test/parser_test.rb +84 -0
  46. data/test/read_write.rb +23 -0
  47. metadata +108 -0
data/lib/meta.rb ADDED
@@ -0,0 +1,32 @@
1
+ # A set of methods to help create meta-programming gizmos.
2
+ class Object
3
+ # The metaclass is the singleton behind every object.
4
+ def metaclass
5
+ class << self
6
+ self
7
+ end
8
+ end
9
+
10
+ # Evaluates the block in the context of the metaclass
11
+ def meta_eval &blk
12
+ metaclass.instance_eval &blk
13
+ end
14
+
15
+ # Acts like an include except it adds the module's methods
16
+ # to the metaclass so they act like class methods.
17
+ def meta_include mod
18
+ meta_eval do
19
+ include mod
20
+ end
21
+ end
22
+
23
+ # Adds methods to a metaclass
24
+ def meta_def name, &blk
25
+ meta_eval { define_method name, &blk }
26
+ end
27
+
28
+ # Defines an instance method within a class
29
+ def class_def name, &blk
30
+ class_eval { define_method name, &blk }
31
+ end
32
+ end
@@ -0,0 +1,71 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'test/unit'
4
+ require 'icalendar'
5
+
6
+ require 'date'
7
+
8
+ class TestCalendar < Test::Unit::TestCase
9
+ include Icalendar
10
+ # Generate a calendar using the raw api, and then spit it out
11
+ # as a string. Parse the string and make sure everything matches up.
12
+ def test_raw_generation
13
+ # Create a fresh calendar
14
+ cal = Calendar.new
15
+
16
+ cal.calscale = "GREGORIAN"
17
+ cal.version = "3.2"
18
+ cal.prodid = "test-prodid"
19
+
20
+ # Now generate the string and then parse it so we can verify
21
+ # that everything was set, generated and parsed correctly.
22
+ calString = cal.to_ical
23
+
24
+ cals = Parser.new(calString).parse
25
+
26
+ cal2 = cals.first
27
+ assert_equal("GREGORIAN", cal2.calscale)
28
+ assert_equal("3.2", cal2.version)
29
+ assert_equal("test-prodid", cal2.prodid)
30
+ end
31
+
32
+ def test_block_creation
33
+ cal = Calendar.new
34
+ cal.event do
35
+ self.dtend = "19970903T190000Z"
36
+ self.summary = "This is my summary"
37
+ end
38
+
39
+ event = cal.event
40
+ event.dtend "19970903T190000Z", {:TZID => "Europe/Copenhagen"}
41
+ event.summary "This is my summary"
42
+
43
+ ev = cal.events.each do |ev|
44
+ assert_equal("19970903T190000Z", ev.dtend)
45
+ assert_equal("This is my summary", ev.summary)
46
+ end
47
+ end
48
+
49
+ def test_find
50
+ cal = Calendar.new
51
+
52
+ # add some events so we actually have to search
53
+ 10.times do
54
+ cal.event
55
+ cal.todo
56
+ cal.journal
57
+ cal.freebusy
58
+ end
59
+ event = cal.events[5]
60
+ assert_equal(event, cal.find_event(event.uid))
61
+
62
+ todo = cal.todos[5]
63
+ assert_equal(todo, cal.find_todo(todo.uid))
64
+
65
+ journal = cal.journals[5]
66
+ assert_equal(journal, cal.find_journal(journal.uid))
67
+
68
+ freebusy = cal.freebusys[5]
69
+ assert_equal(freebusy, cal.find_freebusy(freebusy.uid))
70
+ end
71
+ end
@@ -0,0 +1,220 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
2
+
3
+ require 'test/unit'
4
+ require 'icalendar'
5
+
6
+ unless defined? 1.days
7
+ class Integer
8
+ def days
9
+ self * 60 * 60 * 24
10
+ end
11
+ end
12
+ end
13
+
14
+ # Define a test event
15
+ testEvent = <<EOS
16
+ BEGIN:VEVENT
17
+ UID:19970901T130000Z-123401@host.com
18
+ DTSTAMP:19970901T1300Z
19
+ DTSTART:19970903T163000Z
20
+ DTEND:19970903T190000Z
21
+ SUMMARY:Annual Employee Review
22
+ CLASS:PRIVATE
23
+ CATEGORIES:BUSINESS,HUMAN RESOURCES
24
+ END:VEVENT
25
+ EOS
26
+
27
+ class TestEvent < Test::Unit::TestCase
28
+
29
+ # Create a calendar with an event for each test.
30
+ def setup
31
+ @cal = Icalendar::Calendar.new
32
+ @event = Icalendar::Event.new
33
+ end
34
+
35
+ def test_new
36
+ assert(@event)
37
+ end
38
+
39
+ # Properties that can only occur once per event
40
+ def test_single_properties
41
+ @event.ip_class = "PRIVATE"
42
+
43
+ @cal.add_event(@event)
44
+
45
+ cals = Icalendar::Parser.new(@cal.to_ical).parse
46
+ cal2 = cals.first
47
+ event2 = cal2.events.first
48
+
49
+ assert_equal("PRIVATE", event2.ip_class)
50
+ end
51
+ end
52
+
53
+ class TestEventWithSpecifiedTimezone < Test::Unit::TestCase
54
+
55
+ def setup
56
+ src = <<EOS
57
+ BEGIN:VCALENDAR
58
+ METHOD:PUBLISH
59
+ CALSCALE:GREGORIAN
60
+ VERSION:2.0
61
+ BEGIN:VEVENT
62
+ UID:19970901T130000Z-123401@host.com
63
+ DTSTAMP:19970901T1300Z
64
+ DTSTART;TZID=America/Chicago:19970903T163000
65
+ DTEND;TZID=America/Chicago:19970903T190000
66
+ SUMMARY:Annual Employee Review
67
+ CLASS:PRIVATE
68
+ CATEGORIES:BUSINESS,HUMAN RESOURCES
69
+ END:VEVENT
70
+ END:VCALENDAR
71
+ EOS
72
+ @calendar = Icalendar.parse(src).first
73
+ @event = @calendar.events.first
74
+ end
75
+
76
+ def test_event_is_parsed
77
+ assert_not_nil(@event)
78
+ end
79
+
80
+ def test_dtstart_should_understand_icalendar_tzid
81
+ assert_respond_to(@event.dtstart, :icalendar_tzid)
82
+ end
83
+
84
+ def test_dtstart_tzid_should_be_correct
85
+ puts "#{@event.dtstart.icalendar_tzid} #{@event.dtstart}"
86
+ assert_equal("America/Chicago",@event.dtstart.icalendar_tzid)
87
+ end
88
+
89
+ def test_dtend_tzid_should_be_correct
90
+ assert_equal("America/Chicago",@event.dtend.icalendar_tzid)
91
+ end
92
+
93
+ end
94
+
95
+ class TestEventWithZuluTimezone < Test::Unit::TestCase
96
+
97
+ def setup
98
+ src = <<EOS
99
+ BEGIN:VCALENDAR
100
+ METHOD:PUBLISH
101
+ CALSCALE:GREGORIAN
102
+ VERSION:2.0
103
+ BEGIN:VEVENT
104
+ UID:19970901T130000Z-123401@host.com
105
+ DTSTAMP:19970901T1300Z
106
+ DTSTART:19970903T163000Z
107
+ DTEND:19970903T190000Z
108
+ SUMMARY:Annual Employee Review
109
+ CLASS:PRIVATE
110
+ CATEGORIES:BUSINESS,HUMAN RESOURCES
111
+ END:VEVENT
112
+ END:VCALENDAR
113
+ EOS
114
+ @calendar = Icalendar.parse(src).first
115
+ @event = @calendar.events.first
116
+ end
117
+
118
+ def test_event_is_parsed
119
+ assert_not_nil(@event)
120
+ end
121
+
122
+ def test_dtstart_tzid_should_be_correct
123
+ puts "#{@event.dtstart.icalendar_tzid} #{@event.dtstart}"
124
+ assert_equal("UTC",@event.dtstart.icalendar_tzid)
125
+ end
126
+
127
+ def test_dtend_tzid_should_be_correct
128
+ assert_equal("UTC",@event.dtend.icalendar_tzid)
129
+ end
130
+
131
+ end
132
+
133
+ class TestEventWithFloatingTimezone < Test::Unit::TestCase
134
+
135
+ def setup
136
+ src = <<EOS
137
+ BEGIN:VCALENDAR
138
+ METHOD:PUBLISH
139
+ CALSCALE:GREGORIAN
140
+ VERSION:2.0
141
+ BEGIN:VEVENT
142
+ UID:19970901T130000Z-123401@host.com
143
+ DTSTAMP:19970901T1300Z
144
+ DTSTART:19970903T163000
145
+ DTEND:19970903T190000
146
+ SUMMARY:Annual Employee Review
147
+ CLASS:PRIVATE
148
+ CATEGORIES:BUSINESS,HUMAN RESOURCES
149
+ END:VEVENT
150
+ END:VCALENDAR
151
+ EOS
152
+ @calendar = Icalendar.parse(src).first
153
+ @event = @calendar.events.first
154
+ end
155
+
156
+ def test_event_is_parsed
157
+ assert_not_nil(@event)
158
+ end
159
+
160
+ def test_dtstart_tzid_should_be_nil
161
+ puts "#{@event.dtstart.icalendar_tzid.inspect} #{@event.dtstart}"
162
+ assert_nil(@event.dtstart.icalendar_tzid)
163
+ end
164
+
165
+ def test_dtend_tzid_should_be_nil
166
+ assert_nil(@event.dtend.icalendar_tzid)
167
+ end
168
+
169
+ end
170
+
171
+ class TestRecurringEventWithCount < Test::Unit::TestCase
172
+ # DTSTART;TZID=US-Eastern:19970902T090000
173
+ # RRULE:FREQ=DAILY;COUNT=10
174
+ # ==> (1997 9:00 AM EDT)September 2-11
175
+
176
+ def setup
177
+ src = <<EOS
178
+ BEGIN:VCALENDAR
179
+ METHOD:PUBLISH
180
+ CALSCALE:GREGORIAN
181
+ VERSION:2.0
182
+ BEGIN:VEVENT
183
+ UID:19970901T130000Z-123401@host.com
184
+ DTSTAMP:19970901T1300Z
185
+ DTSTART:19970902T090000Z
186
+ DTEND:19970902T100000Z
187
+ RRULE:FREQ=DAILY;COUNT=10
188
+ SUMMARY:Annual Employee Review
189
+ CLASS:PRIVATE
190
+ CATEGORIES:BUSINESS,HUMAN RESOURCES
191
+ END:VEVENT
192
+ END:VCALENDAR
193
+ EOS
194
+ @calendar = Icalendar.parse(src).first
195
+ @event = @calendar.events.first
196
+ end
197
+
198
+ def test_event_is_parsed
199
+ assert_not_nil(@event)
200
+ end
201
+
202
+ def test_recurrence_rules_should_return_a_recurrence_rule_array
203
+ assert_equal 1, @event.recurrence_rules.length
204
+ assert_kind_of(Icalendar::RRule, @event.recurrence_rules.first)
205
+ end
206
+
207
+ def test_occurrences_after_with_start_before_start_at_should_return_count_occurrences
208
+ assert_equal 10, @event.occurrences_starting(Time.utc(1997, 9, 2, 8, 30, 0, 0)).length
209
+ end
210
+
211
+ def test_occurrences_after_with_start_before_start_at_should_return_an_event_with_the_dtstart_as_the_first_event
212
+ assert_equal @event.dtstart.to_s, @event.occurrences_starting(Time.utc(1997, 9, 2, 8, 30, 0, 0)).first.dtstart.to_s
213
+ end
214
+
215
+ def test_occurrences_after_with_start_before_start_at_should_return_events_with_the_correct_dtstart_values
216
+ expected = (0..9).map {|delta| (@event.dtstart + delta).to_s}
217
+ assert_equal expected, @event.occurrences_starting(Time.utc(1997, 9, 2, 8, 30, 0, 0)).map {|occurence| occurence.dtstart.to_s}
218
+ end
219
+ end
220
+
@@ -0,0 +1,67 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
2
+
3
+ require 'test/unit'
4
+ require 'icalendar'
5
+
6
+ class TestTimezone < Test::Unit::TestCase
7
+
8
+ # Create a calendar with an event for each test.
9
+ def setup
10
+ @cal = Icalendar::Calendar.new
11
+ # Define a test timezone
12
+ @testTimezone = %Q(BEGIN:VTIMEZONE\r\nTZID:America/Chicago\r\nBEGIN:STANDARD\r\nTZOFFSETTO:-0600\r\nRRULE:YEARLY\\;BYMONTH=11\\;BYDAY=1SU\r\nTZOFFSETFROM:-0500\r\nDTSTART:19701101T020000\r\nTZNAME:CST\r\nEND:STANDARD\r\nBEGIN:DAYLIGHT\r\nTZOFFSETTO:-0500\r\nRRULE:FREQ=YEARLY\\;BYMONTH=3\\;BYDAY=2SU\r\nTZOFFSETFROM:-0600\r\nDTSTART:19700308TO20000\r\nTZNAME:CDT\r\nEND:DAYLIGHT\r\nEND:VTIMEZONE\r\n)
13
+ end
14
+
15
+ def test_new
16
+ @tz = Icalendar::Timezone.new
17
+ assert(@tz)
18
+ end
19
+
20
+ def test_raw_generation
21
+ timezone = Icalendar::Timezone.new
22
+ daylight = Icalendar::Daylight.new
23
+ standard = Icalendar::Standard.new
24
+
25
+ timezone.timezone_id = "America/Chicago"
26
+
27
+ daylight.timezone_offset_from = "-0600"
28
+ daylight.timezone_offset_to = "-0500"
29
+ daylight.timezone_name = "CDT"
30
+ daylight.dtstart = "19700308TO20000"
31
+ daylight.recurrence_rules = ["FREQ=YEARLY;BYMONTH=3;BYDAY=2SU"]
32
+
33
+ standard.timezone_offset_from = "-0500"
34
+ standard.timezone_offset_to = "-0600"
35
+ standard.timezone_name = "CST"
36
+ standard.dtstart = "19701101T020000"
37
+ standard.recurrence_rules = ["YEARLY;BYMONTH=11;BYDAY=1SU"]
38
+
39
+ timezone.add(daylight)
40
+ timezone.add(standard)
41
+ @cal.add(timezone)
42
+ assert_equal(@testTimezone, @cal.timezones.first.to_ical)
43
+ end
44
+
45
+ def test_block_creation
46
+ @cal.timezone do
47
+ timezone_id "America/Chicago"
48
+
49
+ daylight do
50
+ timezone_offset_from "-0600"
51
+ timezone_offset_to "-0500"
52
+ timezone_name "CDT"
53
+ dtstart "19700308TO20000"
54
+ add_recurrence_rule "FREQ=YEARLY;BYMONTH=3;BYDAY=2SU"
55
+ end
56
+
57
+ standard do
58
+ timezone_offset_from "-0500"
59
+ timezone_offset_to "-0600"
60
+ timezone_name "CST"
61
+ dtstart "19701101T020000"
62
+ add_recurrence_rule "YEARLY;BYMONTH=11;BYDAY=1SU"
63
+ end
64
+ end
65
+ assert_equal(@testTimezone, @cal.timezones.first.to_ical)
66
+ end
67
+ end
@@ -0,0 +1,13 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+
3
+ class TestTodo < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @cal = Icalendar::Calendar.new
7
+ @todo = Icalendar::Todo.new
8
+ end
9
+
10
+ def test_new
11
+ assert(@todo)
12
+ end
13
+ end
@@ -0,0 +1,66 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+
3
+ require 'date'
4
+ require 'test/unit'
5
+ require 'icalendar'
6
+
7
+ class TestComponent < Test::Unit::TestCase
8
+
9
+ # Create a calendar with an event for each test.
10
+ def setup
11
+ @cal = Icalendar::Calendar.new
12
+ @event = Icalendar::Event.new
13
+ end
14
+
15
+ def test_add_remove_component
16
+ @cal.add_component(@event)
17
+ assert_equal(1, @cal.events.size)
18
+ @cal.remove_component(@event)
19
+ assert_equal(0, @cal.events.size)
20
+ end
21
+
22
+ def test_ical_property
23
+ # No alias but it does have a prop_name
24
+ assert_equal(false, @event.ip_class?)
25
+ @event.ip_class = "PRIVATE"
26
+ assert_equal(true, @event.ip_class?)
27
+ assert_equal("PRIVATE", @event.ip_class)
28
+
29
+ # Check that both dtend and its alias start work correctly
30
+ date = DateTime.new(2005, 02, 05, 23, 24, 25)
31
+ @event.dtend = date
32
+ assert_equal(date.year, @event.dtend.year)
33
+
34
+ date2 = DateTime.new(2005, 02, 05, 23, 24, 26)
35
+ @event.end = date2
36
+ assert_equal(date2.year, @event.end.year)
37
+ end
38
+
39
+ def test_ical_multi_property
40
+ # Query
41
+ assert_equal(false, @event.comments?)
42
+ @event.comments = []
43
+ assert_equal(true, @event.comments?)
44
+
45
+ # Should return an empty array, rather than nil
46
+ assert_equal(0, @event.comments.size)
47
+
48
+ # Add and remove
49
+ @event.add_comment "c1"
50
+ @event.add_comment "c2"
51
+ assert_equal(2, @event.comments.size)
52
+ assert_equal(["c1","c2"], @event.comments)
53
+ @event.remove_comment "c1"
54
+ assert_equal(["c2"], @event.comments)
55
+
56
+ # Set & get whole array
57
+ foo = ["as", "df"]
58
+ @event.comments = foo
59
+ assert_equal(foo, @event.comments)
60
+ end
61
+
62
+ def test_x_property
63
+ @event.x_foobar = "my-custom-property"
64
+ assert_equal("my-custom-property", @event.x_foobar)
65
+ end
66
+ end