icalendar 0.96 → 0.96.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/README +3 -3
  2. data/Rakefile +3 -4
  3. data/docs/api/classes/Array.html +148 -0
  4. data/docs/api/classes/Date.html +159 -0
  5. data/docs/api/classes/DateTime.html +180 -0
  6. data/docs/api/classes/Fixnum.html +148 -0
  7. data/docs/api/classes/Float.html +148 -0
  8. data/docs/api/classes/HashAttrs.html +199 -0
  9. data/docs/api/classes/Icalendar/Alarm.html +228 -0
  10. data/docs/api/classes/Icalendar/Base.html +120 -0
  11. data/docs/api/classes/Icalendar/Calendar.html +365 -0
  12. data/docs/api/classes/Icalendar/Component.html +689 -0
  13. data/docs/api/classes/Icalendar/DateProp.html +187 -0
  14. data/docs/api/classes/Icalendar/DateProp/ClassMethods.html +195 -0
  15. data/docs/api/classes/Icalendar/Daylight.html +156 -0
  16. data/docs/api/classes/Icalendar/Event.html +650 -0
  17. data/docs/api/classes/Icalendar/Freebusy.html +297 -0
  18. data/docs/api/classes/Icalendar/InvalidPropertyValue.html +117 -0
  19. data/docs/api/classes/Icalendar/Journal.html +459 -0
  20. data/docs/api/classes/Icalendar/Parameter.html +166 -0
  21. data/docs/api/classes/Icalendar/Parser.html +447 -0
  22. data/docs/api/classes/Icalendar/Standard.html +156 -0
  23. data/docs/api/classes/Icalendar/Timezone.html +351 -0
  24. data/docs/api/classes/Icalendar/Todo.html +496 -0
  25. data/docs/api/classes/Icalendar/UnknownComponentClass.html +117 -0
  26. data/docs/api/classes/Icalendar/UnknownPropertyMethod.html +117 -0
  27. data/docs/api/classes/Object.html +270 -0
  28. data/docs/api/classes/String.html +148 -0
  29. data/docs/api/classes/Time.html +163 -0
  30. data/docs/api/classes/URI.html +111 -0
  31. data/docs/api/classes/URI/Generic.html +148 -0
  32. data/docs/api/created.rid +1 -0
  33. data/docs/api/files/COPYING.html +163 -0
  34. data/docs/api/files/GPL.html +531 -0
  35. data/docs/api/files/README.html +254 -0
  36. data/docs/api/files/lib/hash_attrs_rb.html +107 -0
  37. data/docs/api/files/lib/icalendar/base_rb.html +108 -0
  38. data/docs/api/files/lib/icalendar/calendar_rb.html +101 -0
  39. data/docs/api/files/lib/icalendar/component/alarm_rb.html +101 -0
  40. data/docs/api/files/lib/icalendar/component/event_rb.html +101 -0
  41. data/docs/api/files/lib/icalendar/component/freebusy_rb.html +101 -0
  42. data/docs/api/files/lib/icalendar/component/journal_rb.html +101 -0
  43. data/docs/api/files/lib/icalendar/component/timezone_rb.html +101 -0
  44. data/docs/api/files/lib/icalendar/component/todo_rb.html +101 -0
  45. data/docs/api/files/lib/icalendar/component_rb.html +101 -0
  46. data/docs/api/files/lib/icalendar/conversions_rb.html +109 -0
  47. data/docs/api/files/lib/icalendar/helpers_rb.html +101 -0
  48. data/docs/api/files/lib/icalendar/parameter_rb.html +101 -0
  49. data/docs/api/files/lib/icalendar/parser_rb.html +109 -0
  50. data/docs/api/files/lib/icalendar_rb.html +120 -0
  51. data/docs/api/files/lib/meta_rb.html +107 -0
  52. data/docs/api/fr_class_index.html +55 -0
  53. data/docs/api/fr_file_index.html +45 -0
  54. data/docs/api/fr_method_index.html +79 -0
  55. data/docs/api/index.html +24 -0
  56. data/docs/api/rdoc-style.css +208 -0
  57. data/{docs/examples → examples}/create_cal.rb +6 -2
  58. data/{docs/examples → examples}/parse_cal.rb +3 -2
  59. data/{docs/examples → examples}/single_event.ics +0 -0
  60. data/lib/hash_attrs.rb +29 -0
  61. data/lib/icalendar.rb +11 -2
  62. data/lib/icalendar/base.rb +6 -2
  63. data/lib/icalendar/calendar.rb +1 -1
  64. data/lib/icalendar/component.rb +98 -71
  65. data/lib/icalendar/component/alarm.rb +5 -3
  66. data/lib/icalendar/component/event.rb +1 -1
  67. data/lib/icalendar/component/freebusy.rb +23 -23
  68. data/lib/icalendar/component/journal.rb +1 -5
  69. data/lib/icalendar/component/timezone.rb +7 -0
  70. data/lib/icalendar/component/todo.rb +1 -6
  71. data/lib/icalendar/conversions.rb +10 -0
  72. data/lib/icalendar/parser.rb +82 -85
  73. data/lib/meta.rb +32 -0
  74. data/test/component_test.rb +69 -64
  75. metadata +74 -12
  76. data/lib/icalendar/foo.rb +0 -394
  77. data/test/property_helpers.rb +0 -35
@@ -16,6 +16,8 @@ require 'date'
16
16
  # end
17
17
  # end
18
18
 
19
+ require 'uri/generic'
20
+
19
21
  class String
20
22
  def to_ical
21
23
  "#{self.dump[1...-1]}"
@@ -40,6 +42,14 @@ class Array
40
42
  end
41
43
  end
42
44
 
45
+ module URI
46
+ class Generic
47
+ def to_ical
48
+ "#{self}"
49
+ end
50
+ end
51
+ end
52
+
43
53
  class DateTime < Date
44
54
  def to_ical(utc = false)
45
55
  s = ""
@@ -1,7 +1,7 @@
1
1
  =begin
2
2
  Copyright (C) 2005 Jeff Rose
3
3
  Copyright (C) 2005 Sam Roberts
4
-
4
+
5
5
  This library is free software; you can redistribute it and/or modify it
6
6
  under the same terms as the ruby language itself, see the file COPYING for
7
7
  details.
@@ -14,7 +14,7 @@ module Icalendar
14
14
  class Parser < Icalendar::Base
15
15
  # 1*(ALPHA / DIGIT / "=")
16
16
  NAME = '[-a-z0-9]+'
17
-
17
+
18
18
  # <"> <Any character except CTLs, DQUOTE> <">
19
19
  QSTR = '"[^"]*"'
20
20
 
@@ -47,14 +47,14 @@ module Icalendar
47
47
 
48
48
  def initialize(src)
49
49
  @@logger.debug("New Calendar Parser")
50
-
50
+
51
51
  # Setup the parser method hash table
52
52
  setup_parsers()
53
53
 
54
54
  # Define the next line method different depending on whether
55
55
  # this is a string or an IO object so we can be efficient about
56
56
  # parsing large files...
57
-
57
+
58
58
  # Just do the unfolding work in one shot if its a whole string
59
59
  if src.respond_to?(:split)
60
60
  unfolded = []
@@ -95,11 +95,11 @@ module Icalendar
95
95
  if !@prev_line.nil?
96
96
  @prev_line.chomp!
97
97
  end
98
-
98
+
99
99
  # Dynamically define next line for an IO object
100
100
  def next_line
101
101
  line = @prev_line
102
-
102
+
103
103
  if line.nil?
104
104
  return nil
105
105
  end
@@ -110,7 +110,7 @@ module Icalendar
110
110
  if !nextLine.nil?
111
111
  nextLine.chomp!
112
112
  end
113
-
113
+
114
114
  # If it's a continuation line, add it to the last.
115
115
  # If it's an empty line, drop it from the input.
116
116
  if( nextLine =~ /^[ \t]/ )
@@ -127,27 +127,27 @@ module Icalendar
127
127
  raise ArgumentError, "CalendarParser.new cannot be called with a #{src.class} type!"
128
128
  end
129
129
  end
130
-
130
+
131
131
  # Parse the calendar into an object representation
132
132
  def parse
133
133
  calendars = []
134
-
134
+
135
135
  # Outer loop for Calendar objects
136
136
  while (line = next_line)
137
137
  fields = parse_line(line)
138
-
138
+
139
139
  # Just iterate through until we find the beginning of a calendar object
140
140
  if fields[:name] == "BEGIN" and fields[:value] == "VCALENDAR"
141
141
  cal = parse_component
142
142
  calendars << cal
143
143
  end
144
144
  end
145
-
145
+
146
146
  calendars
147
147
  end
148
148
 
149
149
  private
150
-
150
+
151
151
  # Parse a single VCALENDAR object
152
152
  # -- This should consist of the PRODID, VERSION, option METHOD & CALSCALE,
153
153
  # and then one or more calendar components: VEVENT, VTODO, VJOURNAL,
@@ -156,8 +156,8 @@ module Icalendar
156
156
  while (line = next_line)
157
157
  fields = parse_line(line)
158
158
 
159
- name = fields[:name]
160
-
159
+ name = fields[:name].upcase
160
+
161
161
  # Although properties are supposed to come before components, we should
162
162
  # be able to handle them in any order...
163
163
  if name == "END"
@@ -185,48 +185,45 @@ module Icalendar
185
185
  next
186
186
  end
187
187
  else # If its not a component then it should be a property
188
-
189
- # Just set the properties so that the parser can still
190
- # parse invalid files...
191
- @@logger.debug("Setting #{name} => #{fields[:value]}")
192
-
188
+
189
+ params = fields[:params]
190
+ value = fields[:value]
191
+
193
192
  # Lookup the property name to see if we have a string to
194
193
  # object parser for this property type.
195
- if @parsers.has_key?(name.upcase)
196
- val = @parsers[name.upcase].call(name, fields[:params], fields[:value])
197
- else
198
- val = fields[:value]
194
+ if @parsers.has_key?(name)
195
+ value = @parsers[name].call(name, params, value)
199
196
  end
200
197
 
201
- if component.multi_property?(name.upcase)
202
- val = [val]
198
+ name = name.downcase
203
199
 
204
- if fields[:params].empty?
205
- params = []
206
- else
207
- params = fields[:params]
208
- end
209
-
210
- if component.properties.has_key?(name)
211
- component.properties[name] += val
212
- component.property_params[name] += params
200
+ # TODO: check to see if there are any more conflicts.
201
+ if name == 'class' or name == 'method'
202
+ name = "ip_" + name
203
+ end
204
+
205
+ # Replace dashes with underscores
206
+ name = name.gsub('-', '_')
207
+
208
+ if component.multi_property?(name)
209
+ adder = "add_" + name
210
+ if component.respond_to?(adder)
211
+ component.send(adder.to_sym, value, params)
213
212
  else
214
- component.properties[name] = val
215
- component.property_params[name] = params
213
+ raise(UnknownPropertyMethod, "Unknown property type: #{adder}")
216
214
  end
217
-
218
215
  else
219
- component.properties[name] = val
220
-
221
- unless fields[:params].empty?
222
- component.property_params[name] = fields[:params]
216
+ puts "Looking for: #{name}"
217
+ if component.respond_to?(name)
218
+ component.send(name, value, params)
219
+ else
220
+ raise(UnknownPropertyMethod, "Unknown property type: #{name}")
223
221
  end
224
222
  end
225
223
  end
226
224
  end
227
225
 
228
226
  component
229
-
230
227
  end
231
228
 
232
229
  def parse_line(line)
@@ -237,50 +234,50 @@ module Icalendar
237
234
  name = $1.upcase # The case insensitive part is upcased for easier comparison...
238
235
  paramslist = $2
239
236
  value = $3
240
-
237
+
241
238
  # Parse the parameters
242
239
  params = {}
243
240
  if paramslist.size > 1
244
241
  paramslist.scan( %r{#{PARAM}}i ) do
245
-
246
- # parameter names are case-insensitive, and multi-valued
247
- pname = $1
248
- pvals = $3
249
-
250
- # If their isn't an '=' sign then we need to do some custom
251
- # business. Defaults to 'type'
252
- if $2 == ""
253
- pvals = $1
254
- case $1
255
- when /quoted-printable/i
256
- pname = 'encoding'
257
-
258
- when /base64/i
259
- pname = 'encoding'
260
-
261
- else
262
- pname = 'type'
263
- end
264
- end
265
-
266
- # Make entries into the params dictionary where the name
267
- # is the key and the value is an array of values.
268
- unless params.key? pname
269
- params[pname] = []
242
+
243
+ # parameter names are case-insensitive, and multi-valued
244
+ pname = $1
245
+ pvals = $3
246
+
247
+ # If their isn't an '=' sign then we need to do some custom
248
+ # business. Defaults to 'type'
249
+ if $2 == ""
250
+ pvals = $1
251
+ case $1
252
+ when /quoted-printable/i
253
+ pname = 'encoding'
254
+
255
+ when /base64/i
256
+ pname = 'encoding'
257
+
258
+ else
259
+ pname = 'type'
270
260
  end
261
+ end
271
262
 
272
- # Save all the values into the array.
273
- pvals.scan( %r{(#{PVALUE})} ) do
274
- if $1.size > 0
275
- params[pname] << $1
276
- end
263
+ # Make entries into the params dictionary where the name
264
+ # is the key and the value is an array of values.
265
+ unless params.key? pname
266
+ params[pname] = []
267
+ end
268
+
269
+ # Save all the values into the array.
270
+ pvals.scan( %r{(#{PVALUE})} ) do
271
+ if $1.size > 0
272
+ params[pname] << $1
277
273
  end
278
274
  end
275
+ end
279
276
  end
280
-
277
+
281
278
  {:name => name, :params => params, :value => value}
282
279
  end
283
-
280
+
284
281
  ## Following is a collection of parsing functions for various
285
282
  ## icalendar property value data types... First we setup
286
283
  ## a hash with property names pointing to methods...
@@ -313,7 +310,7 @@ module Icalendar
313
310
  @parsers["ATTENDEE"] = m
314
311
  @parsers["ORGANIZER"] = m
315
312
  @parsers["URL"] = m
316
-
313
+
317
314
  # This is a URI by default, and if its not a valid URI
318
315
  # it will be returned as a string which works for binary data
319
316
  # the other possible type.
@@ -324,7 +321,7 @@ module Icalendar
324
321
  @parsers["GEO"] = m
325
322
 
326
323
  end
327
-
324
+
328
325
  # Booleans
329
326
  # NOTE: It appears that although this is a valid data type
330
327
  # there aren't any properties that use it... Maybe get
@@ -336,7 +333,7 @@ module Icalendar
336
333
  true
337
334
  end
338
335
  end
339
-
336
+
340
337
  # Dates, Date-Times & Times
341
338
  # NOTE: invalid dates & times will be returned as strings...
342
339
  def parse_datetime(name, params, value)
@@ -345,34 +342,34 @@ module Icalendar
345
342
  rescue Exception
346
343
  value
347
344
  end
348
-
345
+
349
346
  end
350
-
347
+
351
348
  # Durations
352
349
  # TODO: Need to figure out the best way to represent durations
353
350
  # so just returning string for now.
354
351
  def parse_duration(name, params, value)
355
352
  value
356
353
  end
357
-
354
+
358
355
  # Floats
359
356
  # NOTE: returns 0.0 if it can't parse the value
360
357
  def parse_float(name, params, value)
361
358
  value.to_f
362
359
  end
363
-
360
+
364
361
  # Integers
365
362
  # NOTE: returns 0 if it can't parse the value
366
363
  def parse_integer(name, params, value)
367
364
  value.to_i
368
365
  end
369
-
366
+
370
367
  # Periods
371
368
  # TODO: Got to figure out how to represent periods also...
372
369
  def parse_period(name, params, value)
373
370
  value
374
371
  end
375
-
372
+
376
373
  # Calendar Address's & URI's
377
374
  # NOTE: invalid URI's will be returned as strings...
378
375
  def parse_uri(name, params, value)
@@ -397,6 +394,6 @@ module Icalendar
397
394
  val[1] = strloc[1].to_f
398
395
  val
399
396
  end
400
-
397
+
401
398
  end
402
399
  end
@@ -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
@@ -6,69 +6,74 @@ require 'icalendar'
6
6
 
7
7
  class TestComponent < Test::Unit::TestCase
8
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_ical_property
16
- # No alias but it does have a prop_name
17
- assert_equal(@event.klass?, false)
18
- @event.klass = "PRIVATE"
19
- assert_equal(@event.klass?, true)
20
- assert_equal(@event.klass, "PRIVATE")
21
-
22
- # Check that both dtstart and its alias start work correctly
23
- date = DateTime.new(2005, 02, 05, 23, 24, 25)
24
- @event.dtend = date
25
- assert_equal(@event.dtend.year, date.year)
26
-
27
- date2 = DateTime.new(2005, 02, 05, 23, 24, 26)
28
- @event.end = date2
29
- assert_equal(@event.end.year, date2.year)
30
- end
31
-
32
- def test_ical_multi_property
33
- # Query
34
- assert_equal(@event.comments?, false)
35
- @event.comments = []
36
- assert_equal(@event.comments?, true)
37
-
38
- # Should return an empty array, rather than nil
39
- assert_equal(@event.comments.size, 0)
40
-
41
- # Add and remove
42
- @event.add_comment "c1"
43
- @event.add_comment "c2"
44
- assert_equal(@event.comments.size, 2)
45
- assert_equal(@event.comments, ["c1", "c2"])
46
- @event.remove_comment "c1"
47
- assert_equal(@event.comments, ["c2"])
48
-
49
- # Set & get whole array
50
- foo = ["as", "df"]
51
- @event.comments = foo
52
- assert_equal(@event.comments, foo)
53
-
54
- foo = ["asdf", "qwer"]
55
- @event.comments(foo)
56
- assert_equal(@event.comments, foo)
57
-
58
- # Error cases
59
- assert_raise(ArgumentError) { @event.comments("asdf") }
60
- end
61
-
62
- def test_bad_args
63
- # Single property
64
- assert_raise(NotImplementedError) do
65
- @event.klass = {}
66
- end
67
-
68
- # Multi property
69
- assert_raise(NotImplementedError) do
70
- @event.comments = [{}]
71
- end
72
- end
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_component
16
+ @cal.add_component @event
17
+ assert_equal(@cal.events.size, 1)
18
+ end
19
+
20
+ def test_ical_property
21
+ # No alias but it does have a prop_name
22
+ assert_equal(@event.klass?, false)
23
+ @event.klass = "PRIVATE"
24
+ assert_equal(@event.klass?, true)
25
+ assert_equal(@event.klass, "PRIVATE")
26
+
27
+ # Check that both dtstart and its alias start work correctly
28
+ date = DateTime.new(2005, 02, 05, 23, 24, 25)
29
+ @event.dtend = date
30
+ assert_equal(@event.dtend.year, date.year)
31
+
32
+ date2 = DateTime.new(2005, 02, 05, 23, 24, 26)
33
+ @event.end = date2
34
+ assert_equal(@event.end.year, date2.year)
35
+ end
36
+
37
+ def test_ical_multi_property
38
+ # Query
39
+ assert_equal(@event.comments?, false)
40
+ @event.comments = []
41
+ assert_equal(@event.comments?, true)
42
+
43
+ # Should return an empty array, rather than nil
44
+ assert_equal(@event.comments.size, 0)
45
+
46
+ # Add and remove
47
+ @event.add_comment "c1"
48
+ @event.add_comment "c2"
49
+ assert_equal(@event.comments.size, 2)
50
+ assert_equal(@event.comments, ["c1", "c2"])
51
+ @event.remove_comment "c1"
52
+ assert_equal(@event.comments, ["c2"])
53
+
54
+ # Set & get whole array
55
+ foo = ["as", "df"]
56
+ @event.comments = foo
57
+ assert_equal(@event.comments, foo)
58
+
59
+ foo = ["asdf", "qwer"]
60
+ @event.comments(foo)
61
+ assert_equal(@event.comments, foo)
62
+
63
+ # Error cases
64
+ assert_raise(ArgumentError) { @event.comments("asdf") }
65
+ end
66
+
67
+ def test_bad_args
68
+ # Single property
69
+ assert_raise(NotImplementedError) do
70
+ @event.klass = {}
71
+ end
72
+
73
+ # Multi property
74
+ assert_raise(NotImplementedError) do
75
+ @event.comments = [{}]
76
+ end
77
+ end
73
78
 
74
79
  end