curzonj-icalendar 1.0.2

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 (44) hide show
  1. data/COPYING +56 -0
  2. data/GPL +340 -0
  3. data/README +266 -0
  4. data/Rakefile +110 -0
  5. data/docs/rfcs/itip_notes.txt +69 -0
  6. data/docs/rfcs/rfc2425.pdf +0 -0
  7. data/docs/rfcs/rfc2426.pdf +0 -0
  8. data/docs/rfcs/rfc2445.pdf +0 -0
  9. data/docs/rfcs/rfc2446.pdf +0 -0
  10. data/docs/rfcs/rfc2447.pdf +0 -0
  11. data/docs/rfcs/rfc3283.txt +738 -0
  12. data/examples/create_cal.rb +45 -0
  13. data/examples/parse_cal.rb +20 -0
  14. data/examples/single_event.ics +18 -0
  15. data/lib/hash_attrs.rb +34 -0
  16. data/lib/icalendar.rb +39 -0
  17. data/lib/icalendar/base.rb +43 -0
  18. data/lib/icalendar/calendar.rb +113 -0
  19. data/lib/icalendar/component.rb +442 -0
  20. data/lib/icalendar/component/alarm.rb +44 -0
  21. data/lib/icalendar/component/event.rb +129 -0
  22. data/lib/icalendar/component/freebusy.rb +38 -0
  23. data/lib/icalendar/component/journal.rb +61 -0
  24. data/lib/icalendar/component/timezone.rb +105 -0
  25. data/lib/icalendar/component/todo.rb +64 -0
  26. data/lib/icalendar/conversions.rb +150 -0
  27. data/lib/icalendar/helpers.rb +109 -0
  28. data/lib/icalendar/parameter.rb +33 -0
  29. data/lib/icalendar/parser.rb +396 -0
  30. data/lib/meta.rb +32 -0
  31. data/test/calendar_test.rb +71 -0
  32. data/test/component/event_test.rb +256 -0
  33. data/test/component/todo_test.rb +13 -0
  34. data/test/component_test.rb +76 -0
  35. data/test/conversions_test.rb +97 -0
  36. data/test/fixtures/folding.ics +23 -0
  37. data/test/fixtures/life.ics +46 -0
  38. data/test/fixtures/simplecal.ics +119 -0
  39. data/test/fixtures/single_event.ics +23 -0
  40. data/test/interactive.rb +17 -0
  41. data/test/parameter_test.rb +29 -0
  42. data/test/parser_test.rb +84 -0
  43. data/test/read_write.rb +23 -0
  44. metadata +105 -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,256 @@
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 TestAllDayEventWithoutTime < Test::Unit::TestCase
172
+
173
+ def setup
174
+ src = <<EOS
175
+ BEGIN:VCALENDAR
176
+ VERSION:2.0
177
+ X-WR-CALNAME:New Event
178
+ PRODID:-//Apple Computer\, Inc//iCal 2.0//EN
179
+ X-WR-RELCALID:3A016BE7-8932-4456-8ABD-C8F7EEC5963A
180
+ X-WR-TIMEZONE:Europe/London
181
+ CALSCALE:GREGORIAN
182
+ METHOD:PUBLISH
183
+ BEGIN:VEVENT
184
+ DTSTART;VALUE=DATE:20090110
185
+ DTEND;VALUE=DATE:20090111
186
+ SUMMARY:New Event
187
+ UID:3829F33C-F601-49AC-A3A5-C3AC4A6A3483
188
+ SEQUENCE:4
189
+ DTSTAMP:20090109T184719Z
190
+ END:VEVENT
191
+ END:VCALENDAR
192
+ EOS
193
+ @calendar = Icalendar.parse(src).first
194
+ @event = @calendar.events.first
195
+ end
196
+
197
+ def test_event_is_parsed
198
+ assert_not_nil(@event)
199
+ end
200
+
201
+ def test_dtstart_set_correctly
202
+ assert_equal("20090110", @event.dtstart.to_ical)
203
+ end
204
+
205
+ end
206
+
207
+ class TestRecurringEventWithCount < Test::Unit::TestCase
208
+ # DTSTART;TZID=US-Eastern:19970902T090000
209
+ # RRULE:FREQ=DAILY;COUNT=10
210
+ # ==> (1997 9:00 AM EDT)September 2-11
211
+
212
+ def setup
213
+ src = <<EOS
214
+ BEGIN:VCALENDAR
215
+ METHOD:PUBLISH
216
+ CALSCALE:GREGORIAN
217
+ VERSION:2.0
218
+ BEGIN:VEVENT
219
+ UID:19970901T130000Z-123401@host.com
220
+ DTSTAMP:19970901T1300Z
221
+ DTSTART:19970902T090000Z
222
+ DTEND:19970902T100000Z
223
+ RRULE:FREQ=DAILY;COUNT=10
224
+ SUMMARY:Annual Employee Review
225
+ CLASS:PRIVATE
226
+ CATEGORIES:BUSINESS,HUMAN RESOURCES
227
+ END:VEVENT
228
+ END:VCALENDAR
229
+ EOS
230
+ @calendar = Icalendar.parse(src).first
231
+ @event = @calendar.events.first
232
+ end
233
+
234
+ def test_event_is_parsed
235
+ assert_not_nil(@event)
236
+ end
237
+
238
+ def test_recurrence_rules_should_return_a_recurrence_rule_array
239
+ assert_equal 1, @event.recurrence_rules.length
240
+ assert_kind_of(Icalendar::RRule, @event.recurrence_rules.first)
241
+ end
242
+
243
+ def test_occurrences_after_with_start_before_start_at_should_return_count_occurrences
244
+ assert_equal 10, @event.occurrences_starting(Time.utc(1997, 9, 2, 8, 30, 0, 0)).length
245
+ end
246
+
247
+ # def test_occurrences_after_with_start_before_start_at_should_return_an_event_with_the_dtstart_as_the_first_event
248
+ # assert_equal @event.dtstart.to_s, @event.occurrences_starting(Time.utc(1997, 9, 2, 8, 30, 0, 0)).first.dtstart.to_s
249
+ # end
250
+ #
251
+ # def test_occurrences_after_with_start_before_start_at_should_return_events_with_the_correct_dtstart_values
252
+ # expected = (0..9).map {|delta| (@event.dtstart + delta).to_s}
253
+ # assert_equal expected, @event.occurrences_starting(Time.utc(1997, 9, 2, 8, 30, 0, 0)).map {|occurence| occurence.dtstart.to_s}
254
+ # end
255
+ end
256
+
@@ -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,76 @@
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
+
67
+ def test_respond_to_missing
68
+ component = Icalendar::Component.new('name')
69
+ assert !component.respond_to?(:there_is_no_such_method)
70
+ end
71
+
72
+ def test_respond_to_x_property
73
+ component = Icalendar::Component.new('name')
74
+ assert component.respond_to?(:x_foobar)
75
+ end
76
+ end