icalendar 0.97 → 0.98

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 (72) hide show
  1. data/Rakefile +2 -2
  2. data/docs/api/classes/Icalendar/Component.src/M000029.html +1 -1
  3. data/docs/api/classes/Icalendar/Component.src/M000030.html +1 -1
  4. data/docs/api/classes/Icalendar/Component.src/M000035.html +1 -1
  5. data/docs/api/classes/Icalendar/Component.src/M000040.html +1 -1
  6. data/docs/api/classes/Icalendar/Component.src/M000041.html +1 -1
  7. data/docs/api/classes/Icalendar/Component.src/M000042.html +1 -1
  8. data/docs/api/classes/Icalendar/Component.src/M000043.html +9 -4
  9. data/docs/api/classes/Icalendar/Component.src/M000044.html +1 -1
  10. data/docs/api/classes/Icalendar/Component.src/M000045.html +1 -1
  11. data/docs/api/classes/Icalendar/Component.src/M000046.html +1 -1
  12. data/docs/api/classes/Icalendar/Component.src/M000047.html +1 -1
  13. data/docs/api/classes/Icalendar/Component.src/M000048.html +1 -1
  14. data/docs/api/classes/Icalendar/Component.src/M000049.html +1 -1
  15. data/docs/api/classes/Icalendar/Component.src/M000050.html +1 -1
  16. data/docs/api/classes/Icalendar/Geo.html +2 -2
  17. data/docs/api/classes/Icalendar/Geo.src/M000024.html +1 -1
  18. data/docs/api/classes/Icalendar/Geo.src/M000025.html +1 -1
  19. data/docs/api/classes/String.src/M000012.html +1 -1
  20. data/docs/api/created.rid +1 -1
  21. data/docs/api/files/lib/icalendar/component_rb.html +1 -1
  22. data/docs/api/files/lib/icalendar/conversions_rb.html +1 -1
  23. data/docs/api/files/lib/icalendar/parser_rb.html +1 -1
  24. data/lib/icalendar/component.rb +10 -3
  25. data/lib/icalendar/conversions.rb +1 -1
  26. data/lib/icalendar/parser.rb +1 -1
  27. data/test/conversions_test.rb +35 -4
  28. data/test/fixtures/folding.ics +23 -0
  29. data/test/{life.ics → fixtures/life.ics} +0 -0
  30. data/test/{simplecal.ics → fixtures/simplecal.ics} +0 -0
  31. data/test/{single_event.ics → fixtures/single_event.ics} +1 -1
  32. data/test/parser_test.rb +2 -2
  33. metadata +7 -44
  34. data/test/coverage/-home-rosejn-projects-icalendar-lib-hash_attrs_rb.html +0 -574
  35. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-base_rb.html +0 -575
  36. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-calendar_rb.html +0 -629
  37. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-component-alarm_rb.html +0 -581
  38. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-component-event_rb.html +0 -658
  39. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-component-freebusy_rb.html +0 -574
  40. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-component-journal_rb.html +0 -597
  41. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-component-timezone_rb.html +0 -625
  42. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-component-todo_rb.html +0 -600
  43. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-component_rb.html +0 -924
  44. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-conversions_rb.html +0 -667
  45. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-parser_rb.html +0 -938
  46. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar_rb.html +0 -576
  47. data/test/coverage/-home-rosejn-projects-icalendar-lib-meta_rb.html +0 -572
  48. data/test/coverage/calendar_test_rb.html +0 -590
  49. data/test/coverage/component_test_rb.html +0 -602
  50. data/test/coverage/index.html +0 -1009
  51. data/test/coverage/lib-hash_attrs_rb.html +0 -574
  52. data/test/coverage/lib-icalendar-base_rb.html +0 -583
  53. data/test/coverage/lib-icalendar-calendar_rb.html +0 -631
  54. data/test/coverage/lib-icalendar-component-alarm_rb.html +0 -581
  55. data/test/coverage/lib-icalendar-component-event_rb.html +0 -661
  56. data/test/coverage/lib-icalendar-component-freebusy_rb.html +0 -576
  57. data/test/coverage/lib-icalendar-component-journal_rb.html +0 -599
  58. data/test/coverage/lib-icalendar-component-timezone_rb.html +0 -625
  59. data/test/coverage/lib-icalendar-component-todo_rb.html +0 -602
  60. data/test/coverage/lib-icalendar-component_rb.html +0 -941
  61. data/test/coverage/lib-icalendar-conversions_rb.html +0 -673
  62. data/test/coverage/lib-icalendar-parser_rb.html +0 -916
  63. data/test/coverage/lib-icalendar_rb.html +0 -576
  64. data/test/coverage/lib-meta_rb.html +0 -572
  65. data/test/coverage/parameter_test_rb.html +0 -569
  66. data/test/coverage/parser_test_rb.html +0 -623
  67. data/test/coverage/test-calendar_test_rb.html +0 -590
  68. data/test/coverage/test-component-event_test_rb.html +0 -584
  69. data/test/coverage/test-component_test_rb.html +0 -606
  70. data/test/coverage/test-conversions_test_rb.html +0 -603
  71. data/test/coverage/test-parameter_test_rb.html +0 -569
  72. data/test/coverage/test-parser_test_rb.html +0 -624
@@ -1,916 +0,0 @@
1
- <html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'><head><title>lib/icalendar/parser.rb - C0 code coverage information</title><style type='text/css'>body { background-color: rgb(240, 240, 245); }</style><style type='text/css'>span.marked {
2
- background-color: rgb(185, 200, 200);
3
- display: block;
4
- }
5
- span.inferred {
6
- background-color: rgb(170, 185, 185);
7
- display: block;
8
- }
9
- span.overview {
10
- border-bottom: 8px solid black;
11
- }
12
- div.overview {
13
- border-bottom: 8px solid black;
14
- }
15
- body {
16
- font-family: verdana, arial, helvetica;
17
- }
18
- div.footer {
19
- font-size: 68%;
20
- margin-top: 1.5em;
21
- }
22
- h1, h2, h3, h4, h5, h6 {
23
- margin-bottom: 0.5em;
24
- }
25
- h5 {
26
- margin-top: 0.5em;
27
- }
28
- .hidden {
29
- display: none;
30
- }
31
- div.separator {
32
- height: 10px;
33
- }
34
- table tr td, table tr th {
35
- font-size: 68%;
36
- }
37
- td.value table tr td {
38
- font-size: 11px;
39
- }
40
- table.percent_graph {
41
- height: 12px;
42
- border: #808080 1px solid;
43
- empty-cells: show;
44
- }
45
- table.percent_graph td.covered {
46
- height: 10px;
47
- background: #00f000;
48
- }
49
- table.percent_graph td.uncovered {
50
- height: 10px;
51
- background: #e00000;
52
- }
53
- table.percent_graph td.NA {
54
- height: 10px;
55
- background: #eaeaea;
56
- }
57
- table.report {
58
- border-collapse: collapse;
59
- width: 100%;
60
- }
61
- table.report td.heading {
62
- background: #dcecff;
63
- border: #d0d0d0 1px solid;
64
- font-weight: bold;
65
- text-align: center;
66
- }
67
- table.report td.heading:hover {
68
- background: #c0ffc0;
69
- }
70
- table.report td.text {
71
- border: #d0d0d0 1px solid;
72
- }
73
- table.report td.value {
74
- text-align: right;
75
- border: #d0d0d0 1px solid;
76
- }
77
- </style><style type='text/css'>span.run0 {
78
- background-color: rgb(178, 204, 255);
79
- display: block;
80
- }
81
- span.run1 {
82
- background-color: rgb(178, 206, 255);
83
- display: block;
84
- }
85
- span.run2 {
86
- background-color: rgb(178, 209, 255);
87
- display: block;
88
- }
89
- span.run3 {
90
- background-color: rgb(178, 211, 255);
91
- display: block;
92
- }
93
- span.run4 {
94
- background-color: rgb(178, 214, 255);
95
- display: block;
96
- }
97
- span.run5 {
98
- background-color: rgb(178, 218, 255);
99
- display: block;
100
- }
101
- span.run6 {
102
- background-color: rgb(178, 220, 255);
103
- display: block;
104
- }
105
- span.run7 {
106
- background-color: rgb(178, 223, 255);
107
- display: block;
108
- }
109
- span.run8 {
110
- background-color: rgb(178, 225, 255);
111
- display: block;
112
- }
113
- span.run9 {
114
- background-color: rgb(178, 228, 255);
115
- display: block;
116
- }
117
- span.run10 {
118
- background-color: rgb(178, 232, 255);
119
- display: block;
120
- }
121
- span.run11 {
122
- background-color: rgb(178, 234, 255);
123
- display: block;
124
- }
125
- span.run12 {
126
- background-color: rgb(178, 237, 255);
127
- display: block;
128
- }
129
- span.run13 {
130
- background-color: rgb(178, 239, 255);
131
- display: block;
132
- }
133
- span.run14 {
134
- background-color: rgb(178, 242, 255);
135
- display: block;
136
- }
137
- span.run15 {
138
- background-color: rgb(178, 246, 255);
139
- display: block;
140
- }
141
- span.run16 {
142
- background-color: rgb(178, 248, 255);
143
- display: block;
144
- }
145
- span.run17 {
146
- background-color: rgb(178, 251, 255);
147
- display: block;
148
- }
149
- span.run18 {
150
- background-color: rgb(178, 253, 255);
151
- display: block;
152
- }
153
- span.run19 {
154
- background-color: rgb(178, 255, 253);
155
- display: block;
156
- }
157
- span.run20 {
158
- background-color: rgb(178, 255, 249);
159
- display: block;
160
- }
161
- span.run21 {
162
- background-color: rgb(178, 255, 247);
163
- display: block;
164
- }
165
- span.run22 {
166
- background-color: rgb(178, 255, 244);
167
- display: block;
168
- }
169
- span.run23 {
170
- background-color: rgb(178, 255, 242);
171
- display: block;
172
- }
173
- span.run24 {
174
- background-color: rgb(178, 255, 239);
175
- display: block;
176
- }
177
- span.run25 {
178
- background-color: rgb(178, 255, 235);
179
- display: block;
180
- }
181
- span.run26 {
182
- background-color: rgb(178, 255, 233);
183
- display: block;
184
- }
185
- span.run27 {
186
- background-color: rgb(178, 255, 230);
187
- display: block;
188
- }
189
- span.run28 {
190
- background-color: rgb(178, 255, 228);
191
- display: block;
192
- }
193
- span.run29 {
194
- background-color: rgb(178, 255, 225);
195
- display: block;
196
- }
197
- span.run30 {
198
- background-color: rgb(178, 255, 221);
199
- display: block;
200
- }
201
- span.run31 {
202
- background-color: rgb(178, 255, 219);
203
- display: block;
204
- }
205
- span.run32 {
206
- background-color: rgb(178, 255, 216);
207
- display: block;
208
- }
209
- span.run33 {
210
- background-color: rgb(178, 255, 214);
211
- display: block;
212
- }
213
- span.run34 {
214
- background-color: rgb(178, 255, 211);
215
- display: block;
216
- }
217
- span.run35 {
218
- background-color: rgb(178, 255, 207);
219
- display: block;
220
- }
221
- span.run36 {
222
- background-color: rgb(178, 255, 205);
223
- display: block;
224
- }
225
- span.run37 {
226
- background-color: rgb(178, 255, 202);
227
- display: block;
228
- }
229
- span.run38 {
230
- background-color: rgb(178, 255, 200);
231
- display: block;
232
- }
233
- span.run39 {
234
- background-color: rgb(178, 255, 197);
235
- display: block;
236
- }
237
- span.run40 {
238
- background-color: rgb(178, 255, 193);
239
- display: block;
240
- }
241
- span.run41 {
242
- background-color: rgb(178, 255, 191);
243
- display: block;
244
- }
245
- span.run42 {
246
- background-color: rgb(178, 255, 188);
247
- display: block;
248
- }
249
- span.run43 {
250
- background-color: rgb(178, 255, 186);
251
- display: block;
252
- }
253
- span.run44 {
254
- background-color: rgb(178, 255, 183);
255
- display: block;
256
- }
257
- span.run45 {
258
- background-color: rgb(178, 255, 179);
259
- display: block;
260
- }
261
- span.run46 {
262
- background-color: rgb(179, 255, 178);
263
- display: block;
264
- }
265
- span.run47 {
266
- background-color: rgb(182, 255, 178);
267
- display: block;
268
- }
269
- span.run48 {
270
- background-color: rgb(184, 255, 178);
271
- display: block;
272
- }
273
- span.run49 {
274
- background-color: rgb(187, 255, 178);
275
- display: block;
276
- }
277
- span.run50 {
278
- background-color: rgb(191, 255, 178);
279
- display: block;
280
- }
281
- span.run51 {
282
- background-color: rgb(193, 255, 178);
283
- display: block;
284
- }
285
- span.run52 {
286
- background-color: rgb(196, 255, 178);
287
- display: block;
288
- }
289
- span.run53 {
290
- background-color: rgb(198, 255, 178);
291
- display: block;
292
- }
293
- span.run54 {
294
- background-color: rgb(201, 255, 178);
295
- display: block;
296
- }
297
- span.run55 {
298
- background-color: rgb(205, 255, 178);
299
- display: block;
300
- }
301
- span.run56 {
302
- background-color: rgb(207, 255, 178);
303
- display: block;
304
- }
305
- span.run57 {
306
- background-color: rgb(210, 255, 178);
307
- display: block;
308
- }
309
- span.run58 {
310
- background-color: rgb(212, 255, 178);
311
- display: block;
312
- }
313
- span.run59 {
314
- background-color: rgb(215, 255, 178);
315
- display: block;
316
- }
317
- span.run60 {
318
- background-color: rgb(219, 255, 178);
319
- display: block;
320
- }
321
- span.run61 {
322
- background-color: rgb(221, 255, 178);
323
- display: block;
324
- }
325
- span.run62 {
326
- background-color: rgb(224, 255, 178);
327
- display: block;
328
- }
329
- span.run63 {
330
- background-color: rgb(226, 255, 178);
331
- display: block;
332
- }
333
- span.run64 {
334
- background-color: rgb(229, 255, 178);
335
- display: block;
336
- }
337
- span.run65 {
338
- background-color: rgb(233, 255, 178);
339
- display: block;
340
- }
341
- span.run66 {
342
- background-color: rgb(235, 255, 178);
343
- display: block;
344
- }
345
- span.run67 {
346
- background-color: rgb(238, 255, 178);
347
- display: block;
348
- }
349
- span.run68 {
350
- background-color: rgb(240, 255, 178);
351
- display: block;
352
- }
353
- span.run69 {
354
- background-color: rgb(243, 255, 178);
355
- display: block;
356
- }
357
- span.run70 {
358
- background-color: rgb(247, 255, 178);
359
- display: block;
360
- }
361
- span.run71 {
362
- background-color: rgb(249, 255, 178);
363
- display: block;
364
- }
365
- span.run72 {
366
- background-color: rgb(252, 255, 178);
367
- display: block;
368
- }
369
- span.run73 {
370
- background-color: rgb(255, 255, 178);
371
- display: block;
372
- }
373
- span.run74 {
374
- background-color: rgb(255, 252, 178);
375
- display: block;
376
- }
377
- span.run75 {
378
- background-color: rgb(255, 248, 178);
379
- display: block;
380
- }
381
- span.run76 {
382
- background-color: rgb(255, 246, 178);
383
- display: block;
384
- }
385
- span.run77 {
386
- background-color: rgb(255, 243, 178);
387
- display: block;
388
- }
389
- span.run78 {
390
- background-color: rgb(255, 240, 178);
391
- display: block;
392
- }
393
- span.run79 {
394
- background-color: rgb(255, 238, 178);
395
- display: block;
396
- }
397
- span.run80 {
398
- background-color: rgb(255, 234, 178);
399
- display: block;
400
- }
401
- span.run81 {
402
- background-color: rgb(255, 232, 178);
403
- display: block;
404
- }
405
- span.run82 {
406
- background-color: rgb(255, 229, 178);
407
- display: block;
408
- }
409
- span.run83 {
410
- background-color: rgb(255, 226, 178);
411
- display: block;
412
- }
413
- span.run84 {
414
- background-color: rgb(255, 224, 178);
415
- display: block;
416
- }
417
- span.run85 {
418
- background-color: rgb(255, 220, 178);
419
- display: block;
420
- }
421
- span.run86 {
422
- background-color: rgb(255, 218, 178);
423
- display: block;
424
- }
425
- span.run87 {
426
- background-color: rgb(255, 215, 178);
427
- display: block;
428
- }
429
- span.run88 {
430
- background-color: rgb(255, 212, 178);
431
- display: block;
432
- }
433
- span.run89 {
434
- background-color: rgb(255, 210, 178);
435
- display: block;
436
- }
437
- span.run90 {
438
- background-color: rgb(255, 206, 178);
439
- display: block;
440
- }
441
- span.run91 {
442
- background-color: rgb(255, 204, 178);
443
- display: block;
444
- }
445
- span.run92 {
446
- background-color: rgb(255, 201, 178);
447
- display: block;
448
- }
449
- span.run93 {
450
- background-color: rgb(255, 198, 178);
451
- display: block;
452
- }
453
- span.run94 {
454
- background-color: rgb(255, 196, 178);
455
- display: block;
456
- }
457
- span.run95 {
458
- background-color: rgb(255, 192, 178);
459
- display: block;
460
- }
461
- span.run96 {
462
- background-color: rgb(255, 189, 178);
463
- display: block;
464
- }
465
- span.run97 {
466
- background-color: rgb(255, 187, 178);
467
- display: block;
468
- }
469
- span.run98 {
470
- background-color: rgb(255, 184, 178);
471
- display: block;
472
- }
473
- span.run99 {
474
- background-color: rgb(255, 182, 178);
475
- display: block;
476
- }
477
- span.run100 {
478
- background-color: rgb(255, 178, 178);
479
- display: block;
480
- }
481
- </style></head><body><h3>C0 code coverage information generated on Thu Jul 20 18:17:28 CEST 2006</h3><hr /><pre><span class='marked'>Marked code looks like this.
482
- This line is also marked as covered.
483
- </span><span class='inferred'>Lines considered as run by rcov, but not reported by Ruby, look like this.
484
- </span><span class='false'>Finally, here&apos;s a line marked as not executed.
485
- </span></pre> <table class='report'>
486
- <thead>
487
- <tr>
488
- <td class='heading'>Name</td>
489
- <td class='heading'>Total lines</td>
490
- <td class='heading'>Lines of code</td>
491
- <td class='heading'>Total coverage</td>
492
- <td class='heading'>Code coverage</td>
493
- </tr>
494
- </thead>
495
- <tbody>
496
- <tr>
497
- <td>
498
- <a href='lib-icalendar-parser_rb.html'>lib/icalendar/parser.rb</a>
499
- </td>
500
- <td class='value'>
501
- <tt>376</tt>
502
- </td>
503
- <td class='value'>
504
- <tt>376</tt>
505
- </td>
506
- <td>
507
- <table cellspacing='0' cellpadding='0' align='right'>
508
- <tr>
509
- <td>
510
- <tt>81.9%</tt>&nbsp;</td>
511
- <td>
512
- <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
513
- <tr>
514
- <td class='covered' width='82' />
515
- <td class='uncovered' width='18' />
516
- </tr>
517
- </table>
518
- </td>
519
- </tr>
520
- </table>
521
- </td>
522
- <td>
523
- <table cellspacing='0' cellpadding='0' align='right'>
524
- <tr>
525
- <td>
526
- <tt>72.7%</tt>&nbsp;</td>
527
- <td>
528
- <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
529
- <tr>
530
- <td class='covered' width='73' />
531
- <td class='uncovered' width='27' />
532
- </tr>
533
- </table>
534
- </td>
535
- </tr>
536
- </table>
537
- </td>
538
- </tr>
539
- </tbody>
540
- </table><pre><span class="false"> 1 =begin
541
- 2 Copyright (C) 2005 Jeff Rose
542
- 3 Copyright (C) 2005 Sam Roberts
543
- 4
544
- 5 This library is free software; you can redistribute it and/or modify it
545
- 6 under the same terms as the ruby language itself, see the file COPYING for
546
- 7 details.
547
- 8 =end
548
- </span><span class="marked"> 9
549
- 10 require 'date'
550
- 11 require 'uri'
551
- 12 require 'stringio'
552
- 13
553
- 14 module Icalendar
554
- 15 def Icalendar.parse(src, single = false)
555
- 16 cals = Icalendar::Parser.new(src).parse
556
- 17
557
- 18 if single
558
- </span><span class="false"> 19 cals.first
559
- </span><span class="marked"> 20 else
560
- 21 cals
561
- 22 end
562
- 23 end
563
- 24
564
- 25 class Parser &lt; Icalendar::Base
565
- 26 # date = date-fullyear [&quot;-&quot;] date-month [&quot;-&quot;] date-mday
566
- 27 # date-fullyear = 4 DIGIT
567
- 28 # date-month = 2 DIGIT
568
- 29 # date-mday = 2 DIGIT
569
- 30 DATE = '(\d\d\d\d)-?(\d\d)-?(\d\d)'
570
- 31
571
- 32 # time = time-hour [&quot;:&quot;] time-minute [&quot;:&quot;] time-second [time-secfrac] [time-zone]
572
- 33 # time-hour = 2 DIGIT
573
- 34 # time-minute = 2 DIGIT
574
- 35 # time-second = 2 DIGIT
575
- 36 # time-secfrac = &quot;,&quot; 1*DIGIT
576
- 37 # time-zone = &quot;Z&quot; / time-numzone
577
- 38 # time-numzome = sign time-hour [&quot;:&quot;] time-minute
578
- 39 TIME = '(\d\d):?(\d\d):?(\d\d)(\.\d+)?(Z|[-+]\d\d:?\d\d)?'
579
- 40
580
- 41 def initialize(src)
581
- 42 # Setup the parser method hash table
582
- 43 setup_parsers()
583
- 44
584
- 45 if src.respond_to?(:gets)
585
- 46 @file = src
586
- 47 elsif (not src.nil?) and src.respond_to?(:to_s)
587
- 48 @file = StringIO.new(src.to_s, 'r')
588
- 49 else
589
- 50 raise ArgumentError, &quot;CalendarParser.new cannot be called with a #{src.class} type!&quot;
590
- 51 end
591
- 52
592
- 53 @prev_line = @file.gets
593
- 54 @prev_line.chomp! unless @prev_line.nil?
594
- 55
595
- 56 @@logger.debug(&quot;New Calendar Parser: #{@file.inspect}&quot;)
596
- 57 end
597
- 58
598
- 59 # Define next line for an IO object.
599
- 60 # Works for strings now with StringIO
600
- 61 def next_line
601
- 62 line = @prev_line
602
- 63
603
- 64 if line.nil?
604
- 65 return nil
605
- 66 end
606
- 67
607
- 68 # Loop through until we get to a non-continuation line...
608
- 69 loop do
609
- 70 nextLine = @file.gets
610
- 71 @@logger.debug &quot;new_line: #{nextLine}&quot;
611
- 72
612
- 73 if !nextLine.nil?
613
- 74 nextLine.chomp!
614
- 75 end
615
- 76
616
- 77 # If it's a continuation line, add it to the last.
617
- 78 # If it's an empty line, drop it from the input.
618
- 79 if( nextLine =~ /^[ \t]/ )
619
- 80 line &lt;&lt; nextLine[1, nextLine.size]
620
- 81 elsif( nextLine =~ /^$/ )
621
- 82 else
622
- 83 @prev_line = nextLine
623
- 84 break
624
- 85 end
625
- 86 end
626
- 87 line
627
- 88 end
628
- 89
629
- 90 # Parse the calendar into an object representation
630
- 91 def parse
631
- 92 calendars = []
632
- 93
633
- 94 @@logger.debug &quot;parsing...&quot;
634
- 95 # Outer loop for Calendar objects
635
- 96 while (line = next_line)
636
- 97 fields = parse_line(line)
637
- 98
638
- 99 # Just iterate through until we find the beginning of a calendar object
639
- 100 if fields[:name] == &quot;BEGIN&quot; and fields[:value] == &quot;VCALENDAR&quot;
640
- 101 cal = parse_component
641
- 102 @@logger.debug &quot;Added parsed calendar...&quot;
642
- 103 calendars &lt;&lt; cal
643
- 104 end
644
- 105 end
645
- 106
646
- 107 calendars
647
- 108 end
648
- 109
649
- 110 private
650
- 111
651
- 112 # Parse a single VCALENDAR object
652
- 113 # -- This should consist of the PRODID, VERSION, option METHOD &amp; CALSCALE,
653
- 114 # and then one or more calendar components: VEVENT, VTODO, VJOURNAL,
654
- 115 # VFREEBUSY, VTIMEZONE
655
- 116 def parse_component(component = Calendar.new)
656
- 117 @@logger.debug &quot;parsing new component...&quot;
657
- 118
658
- 119 while (line = next_line)
659
- 120 fields = parse_line(line)
660
- 121
661
- 122 name = fields[:name].upcase
662
- 123
663
- 124 # Although properties are supposed to come before components, we should
664
- 125 # be able to handle them in any order...
665
- 126 if name == &quot;END&quot;
666
- 127 break
667
- 128 elsif name == &quot;BEGIN&quot; # New component
668
- 129 case(fields[:value])
669
- 130 when &quot;VEVENT&quot; # Event
670
- 131 component.add_component parse_component(Event.new)
671
- </span><span class="false">132 when &quot;VTODO&quot; # Todo entry
672
- 133 component.add_component parse_component(Todo.new)
673
- 134 when &quot;VALARM&quot; # Alarm sub-component for event and todo
674
- 135 component.add_component parse_component(Alarm.new)
675
- 136 when &quot;VJOURNAL&quot; # Journal entry
676
- 137 component.add_component parse_component(Journal.new)
677
- 138 when &quot;VFREEBUSY&quot; # Free/Busy section
678
- 139 component.add_component parse_component(Freebusy.new)
679
- 140 when &quot;VTIMEZONE&quot; # Timezone specification
680
- 141 component.add_component parse_component(Timezone.new)
681
- 142 when &quot;STANDARD&quot; # Standard time sub-component for timezone
682
- 143 component.add_component parse_component(Standard.new)
683
- 144 when &quot;DAYLIGHT&quot; # Daylight time sub-component for timezone
684
- 145 component.add_component parse_component(Daylight.new)
685
- 146 else # Uknown component type, skip to matching end
686
- 147 until ((line = next_line) == &quot;END:#{fields[:value]}&quot;); end
687
- 148 next
688
- 149 end
689
- </span><span class="marked">150 else # If its not a component then it should be a property
690
- 151
691
- 152 params = fields[:params]
692
- 153 value = fields[:value]
693
- 154
694
- 155 # Lookup the property name to see if we have a string to
695
- 156 # object parser for this property type.
696
- 157 if @parsers.has_key?(name)
697
- 158 value = @parsers[name].call(name, params, value)
698
- 159 end
699
- 160
700
- 161 name = name.downcase
701
- 162
702
- 163 # TODO: check to see if there are any more conflicts.
703
- 164 if name == 'class' or name == 'method'
704
- 165 name = &quot;ip_&quot; + name
705
- 166 end
706
- 167
707
- 168 # Replace dashes with underscores
708
- 169 name = name.gsub('-', '_')
709
- 170
710
- 171 if component.multi_property?(name)
711
- 172 adder = &quot;add_&quot; + name
712
- 173 if component.respond_to?(adder)
713
- 174 component.send(adder, value, params)
714
- </span><span class="false">175 else
715
- 176 raise(UnknownPropertyMethod, &quot;Unknown property type: #{adder}&quot;)
716
- 177 end
717
- </span><span class="marked">178 else
718
- 179 if component.respond_to?(name)
719
- 180 component.send(name, value, params)
720
- </span><span class="false">181 else
721
- 182 raise(UnknownPropertyMethod, &quot;Unknown property type: #{name}&quot;)
722
- 183 end
723
- 184 end
724
- 185 end
725
- 186 end
726
- </span><span class="marked">187
727
- 188 component
728
- 189 end
729
- 190
730
- 191 # 1*(ALPHA / DIGIT / &quot;=&quot;)
731
- 192 NAME = '[-a-z0-9]+'
732
- 193
733
- 194 # &lt;&quot;&gt; &lt;Any character except CTLs, DQUOTE&gt; &lt;&quot;&gt;
734
- 195 QSTR = '&quot;[^&quot;]*&quot;'
735
- 196
736
- 197 # Contentline
737
- 198 LINE = &quot;(#{NAME})(.*(?:#{QSTR})|(?:[^:]*))\:(.*)&quot;
738
- 199
739
- 200 # *&lt;Any character except CTLs, DQUOTE, &quot;;&quot;, &quot;:&quot;, &quot;,&quot;&gt;
740
- 201 PTEXT = '[^&quot;;:,]*'
741
- 202
742
- 203 # param-value = ptext / quoted-string
743
- 204 PVALUE = &quot;#{QSTR}|#{PTEXT}&quot;
744
- 205
745
- 206 # param = name &quot;=&quot; param-value *(&quot;,&quot; param-value)
746
- 207 PARAM = &quot;;(#{NAME})(=?)((?:#{PVALUE})(?:,#{PVALUE})*)&quot;
747
- 208
748
- 209 def parse_line(line)
749
- 210 unless line =~ %r{#{LINE}}i # Case insensitive match for a valid line
750
- 211 raise &quot;Invalid line in calendar string!&quot;
751
- 212 end
752
- 213
753
- 214 name = $1.upcase # The case insensitive part is upcased for easier comparison...
754
- 215 paramslist = $2
755
- 216 value = $3
756
- 217
757
- 218 # Parse the parameters
758
- 219 params = {}
759
- 220 if paramslist.size &gt; 1
760
- 221 paramslist.scan( %r{#{PARAM}}i ) do
761
- 222
762
- 223 # parameter names are case-insensitive, and multi-valued
763
- 224 pname = $1
764
- 225 pvals = $3
765
- 226
766
- 227 # If their isn't an '=' sign then we need to do some custom
767
- 228 # business. Defaults to 'type'
768
- 229 if $2 == &quot;&quot;
769
- </span><span class="false">230 pvals = $1
770
- 231 case $1
771
- 232 when /quoted-printable/i
772
- 233 pname = 'encoding'
773
- 234
774
- 235 when /base64/i
775
- 236 pname = 'encoding'
776
- 237
777
- 238 else
778
- 239 pname = 'type'
779
- 240 end
780
- 241 end
781
- </span><span class="marked">242
782
- 243 # Make entries into the params dictionary where the name
783
- 244 # is the key and the value is an array of values.
784
- 245 unless params.key? pname
785
- 246 params[pname] = []
786
- 247 end
787
- 248
788
- 249 # Save all the values into the array.
789
- 250 pvals.scan( %r{(#{PVALUE})} ) do
790
- 251 if $1.size &gt; 0
791
- 252 params[pname] &lt;&lt; $1
792
- 253 end
793
- 254 end
794
- 255 end
795
- 256 end
796
- 257
797
- 258 {:name =&gt; name, :value =&gt; value, :params =&gt; params}
798
- 259 end
799
- 260
800
- 261 ## Following is a collection of parsing functions for various
801
- 262 ## icalendar property value data types... First we setup
802
- 263 ## a hash with property names pointing to methods...
803
- 264 def setup_parsers
804
- 265 @parsers = {}
805
- 266
806
- 267 # Integer properties
807
- 268 m = self.method(:parse_integer)
808
- 269 @parsers[&quot;PERCENT-COMPLETE&quot;] = m
809
- 270 @parsers[&quot;PRIORITY&quot;] = m
810
- 271 @parsers[&quot;REPEAT&quot;] = m
811
- 272 @parsers[&quot;SEQUENCE&quot;] = m
812
- 273
813
- 274 # Dates and Times
814
- 275 m = self.method(:parse_datetime)
815
- 276 @parsers[&quot;COMPLETED&quot;] = m
816
- 277 @parsers[&quot;DTEND&quot;] = m
817
- 278 @parsers[&quot;DUE&quot;] = m
818
- 279 @parsers[&quot;DTSTART&quot;] = m
819
- 280 @parsers[&quot;RECURRENCE-ID&quot;] = m
820
- 281 @parsers[&quot;EXDATE&quot;] = m
821
- 282 @parsers[&quot;RDATE&quot;] = m
822
- 283 @parsers[&quot;CREATED&quot;] = m
823
- 284 @parsers[&quot;DTSTAMP&quot;] = m
824
- 285 @parsers[&quot;LAST-MODIFIED&quot;] = m
825
- 286
826
- 287 # URI's
827
- 288 m = self.method(:parse_uri)
828
- 289 @parsers[&quot;TZURL&quot;] = m
829
- 290 @parsers[&quot;ATTENDEE&quot;] = m
830
- 291 @parsers[&quot;ORGANIZER&quot;] = m
831
- 292 @parsers[&quot;URL&quot;] = m
832
- 293
833
- 294 # This is a URI by default, and if its not a valid URI
834
- 295 # it will be returned as a string which works for binary data
835
- 296 # the other possible type.
836
- 297 @parsers[&quot;ATTACH&quot;] = m
837
- 298
838
- 299 # GEO
839
- 300 m = self.method(:parse_geo)
840
- 301 @parsers[&quot;GEO&quot;] = m
841
- 302
842
- 303 end
843
- 304
844
- 305 # Booleans
845
- 306 # NOTE: It appears that although this is a valid data type
846
- 307 # there aren't any properties that use it... Maybe get
847
- 308 # rid of this in the future.
848
- 309 def parse_boolean(name, params, value)
849
- </span><span class="false">310 if value.upcase == &quot;FALSE&quot;
850
- 311 false
851
- 312 else
852
- 313 true
853
- 314 end
854
- 315 end
855
- </span><span class="marked">316
856
- 317 # Dates, Date-Times &amp; Times
857
- 318 # NOTE: invalid dates &amp; times will be returned as strings...
858
- 319 def parse_datetime(name, params, value)
859
- 320 begin
860
- 321 DateTime.parse(value)
861
- </span><span class="false">322 rescue Exception
862
- 323 value
863
- 324 end
864
- </span><span class="marked">325
865
- 326 end
866
- 327
867
- 328 # Durations
868
- 329 # TODO: Need to figure out the best way to represent durations
869
- 330 # so just returning string for now.
870
- 331 def parse_duration(name, params, value)
871
- </span><span class="false">332 value
872
- 333 end
873
- </span><span class="marked">334
874
- 335 # Floats
875
- 336 # NOTE: returns 0.0 if it can't parse the value
876
- 337 def parse_float(name, params, value)
877
- </span><span class="false">338 value.to_f
878
- 339 end
879
- </span><span class="marked">340
880
- 341 # Integers
881
- 342 # NOTE: returns 0 if it can't parse the value
882
- 343 def parse_integer(name, params, value)
883
- 344 value.to_i
884
- 345 end
885
- 346
886
- 347 # Periods
887
- 348 # TODO: Got to figure out how to represent periods also...
888
- 349 def parse_period(name, params, value)
889
- </span><span class="false">350 value
890
- 351 end
891
- </span><span class="marked">352
892
- 353 # Calendar Address's &amp; URI's
893
- 354 # NOTE: invalid URI's will be returned as strings...
894
- 355 def parse_uri(name, params, value)
895
- 356 begin
896
- 357 URI.parse(value)
897
- </span><span class="false">358 rescue Exception
898
- 359 value
899
- 360 end
900
- </span><span class="marked">361 end
901
- 362
902
- 363 # Geographical location (GEO)
903
- 364 # NOTE: returns an array with two floats (long &amp; lat)
904
- 365 # if the parsing fails return the string
905
- 366 def parse_geo(name, params, value)
906
- 367 strloc = value.split(';')
907
- 368 if strloc.size != 2
908
- </span><span class="false">369 return value
909
- 370 end
910
- </span><span class="marked">371
911
- 372 Geo.new(strloc[0].to_f, strloc[1].to_f)
912
- 373 end
913
- 374
914
- 375 end
915
- 376 end
916
- </span></pre><hr /><p><a href='http://validator.w3.org/check/referer'><img src='http://www.w3.org/Icons/valid-xhtml10' height='31' alt='Valid XHTML 1.0!' width='88' /></a><a href='http://jigsaw.w3.org/css-validator/check/referer'><img src='http://jigsaw.w3.org/css-validator/images/vcss' alt='Valid CSS!' style='border:0;width:88px;height:31px' /></a></p></body></html><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">