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,938 +0,0 @@
1
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'><head><title>/home/rosejn/projects/icalendar/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 Sun May 21 00:51:53 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='-home-rosejn-projects-icalendar-lib-icalendar-parser_rb.html'>/home/rosejn/projects/icalendar/lib/icalendar/parser.rb</a>
499
- </td>
500
- <td class='value'>
501
- <tt>398</tt>
502
- </td>
503
- <td class='value'>
504
- <tt>398</tt>
505
- </td>
506
- <td>
507
- <table cellspacing='0' cellpadding='0' align='right'>
508
- <tr>
509
- <td>
510
- <tt>67.8%</tt>&nbsp;</td>
511
- <td>
512
- <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
513
- <tr>
514
- <td class='covered' width='68' />
515
- <td class='uncovered' width='32' />
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>54.2%</tt>&nbsp;</td>
527
- <td>
528
- <table cellspacing='0' class='percent_graph' cellpadding='0' width='100'>
529
- <tr>
530
- <td class='covered' width='54' />
531
- <td class='uncovered' width='46' />
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
552
- 13 module Icalendar
553
- 14 class Parser &lt; Icalendar::Base
554
- 15 # date = date-fullyear [&quot;-&quot;] date-month [&quot;-&quot;] date-mday
555
- 16 # date-fullyear = 4 DIGIT
556
- 17 # date-month = 2 DIGIT
557
- 18 # date-mday = 2 DIGIT
558
- 19 DATE = '(\d\d\d\d)-?(\d\d)-?(\d\d)'
559
- 20
560
- 21 # time = time-hour [&quot;:&quot;] time-minute [&quot;:&quot;] time-second [time-secfrac] [time-zone]
561
- 22 # time-hour = 2 DIGIT
562
- 23 # time-minute = 2 DIGIT
563
- 24 # time-second = 2 DIGIT
564
- 25 # time-secfrac = &quot;,&quot; 1*DIGIT
565
- 26 # time-zone = &quot;Z&quot; / time-numzone
566
- 27 # time-numzome = sign time-hour [&quot;:&quot;] time-minute
567
- 28 TIME = '(\d\d):?(\d\d):?(\d\d)(\.\d+)?(Z|[-+]\d\d:?\d\d)?'
568
- 29
569
- 30 def initialize(src)
570
- 31 @@logger.debug(&quot;New Calendar Parser&quot;)
571
- 32
572
- 33 # Setup the parser method hash table
573
- 34 setup_parsers()
574
- 35
575
- 36 # Define the next line method different depending on whether
576
- 37 # this is a string or an IO object so we can be efficient about
577
- 38 # parsing large files...
578
- 39
579
- 40 # Just do the unfolding work in one shot if its a whole string
580
- 41 if src.respond_to?(:split)
581
- 42 unfolded = []
582
- 43
583
- 44 # Split into an array of lines, then unfold those into a new array
584
- 45 src.split(/\r?\n/).each do |line|
585
- 46
586
- 47 # If it's a continuation line, add it to the last.
587
- 48 # If it's an empty line, drop it from the input.
588
- 49 if( line =~ /^[ \t]/ )
589
- </span><span class="false"> 50 unfolded &lt;&lt; unfolded.pop + line[1, line.size-1]
590
- </span><span class="marked"> 51 elsif( line =~ /^$/ )
591
- 52 else
592
- 53 unfolded &lt;&lt; line
593
- 54 end
594
- 55 end
595
- 56
596
- 57 @lines = unfolded
597
- 58 @index = 0
598
- 59
599
- 60 # Now that we are unfolded we can just iterate through the array.
600
- 61 # Dynamically define next line for a string.
601
- 62 def next_line
602
- 63 if @index == @lines.size
603
- 64 return nil
604
- 65 else
605
- 66 line = @lines[@index]
606
- 67 @index += 1
607
- 68 return line
608
- 69 end
609
- 70 end
610
- 71
611
- 72 # If its a file we need to read and unfold on the go to save from reading
612
- 73 # large amounts of data into memory.
613
- 74 elsif src.respond_to?(:gets)
614
- </span><span class="false"> 75 @file = src
615
- 76 @prev_line = src.gets
616
- 77 if !@prev_line.nil?
617
- 78 @prev_line.chomp!
618
- 79 end
619
- 80
620
- 81 # Dynamically define next line for an IO object
621
- 82 def next_line
622
- 83 line = @prev_line
623
- 84
624
- 85 if line.nil?
625
- 86 return nil
626
- 87 end
627
- 88
628
- 89 # Loop through until we get to a non-continuation line...
629
- 90 loop do
630
- 91 nextLine = @file.gets
631
- 92 if !nextLine.nil?
632
- 93 nextLine.chomp!
633
- 94 end
634
- 95
635
- 96 # If it's a continuation line, add it to the last.
636
- 97 # If it's an empty line, drop it from the input.
637
- 98 if( nextLine =~ /^[ \t]/ )
638
- 99 line &lt;&lt; nextLine[1, nextLine.size]
639
- 100 elsif( nextLine =~ /^$/ )
640
- 101 else
641
- 102 @prev_line = nextLine
642
- 103 break
643
- 104 end
644
- 105 end
645
- 106 line
646
- 107 end
647
- </span><span class="marked">108 else
648
- 109 raise ArgumentError, &quot;CalendarParser.new cannot be called with a #{src.class} type!&quot;
649
- 110 end
650
- 111 end
651
- 112
652
- 113 # Parse the calendar into an object representation
653
- 114 def parse
654
- 115 calendars = []
655
- 116
656
- 117 # Outer loop for Calendar objects
657
- 118 while (line = next_line)
658
- 119 fields = parse_line(line)
659
- 120
660
- 121 # Just iterate through until we find the beginning of a calendar object
661
- 122 if fields[:name] == &quot;BEGIN&quot; and fields[:value] == &quot;VCALENDAR&quot;
662
- 123 cal = parse_component
663
- 124 calendars &lt;&lt; cal
664
- 125 end
665
- 126 end
666
- 127
667
- 128 calendars
668
- 129 end
669
- 130
670
- 131 private
671
- 132
672
- 133 # Parse a single VCALENDAR object
673
- 134 # -- This should consist of the PRODID, VERSION, option METHOD &amp; CALSCALE,
674
- 135 # and then one or more calendar components: VEVENT, VTODO, VJOURNAL,
675
- 136 # VFREEBUSY, VTIMEZONE
676
- 137 def parse_component(component = Calendar.new)
677
- 138 while (line = next_line)
678
- 139 fields = parse_line(line)
679
- 140
680
- 141 name = fields[:name].upcase
681
- 142
682
- 143 # Although properties are supposed to come before components, we should
683
- 144 # be able to handle them in any order...
684
- 145 if name == &quot;END&quot;
685
- 146 break
686
- 147 elsif name == &quot;BEGIN&quot; # New component
687
- 148 case(fields[:value])
688
- 149 when &quot;VEVENT&quot; # Event
689
- 150 component.add_component parse_component(Event.new)
690
- </span><span class="false">151 when &quot;VTODO&quot; # Todo entry
691
- 152 component.add_component parse_component(Todo.new)
692
- 153 when &quot;VALARM&quot; # Alarm sub-component for event and todo
693
- 154 component.add_component parse_component(Alarm.new)
694
- 155 when &quot;VJOURNAL&quot; # Journal entry
695
- 156 component.add_component parse_component(Journal.new)
696
- 157 when &quot;VFREEBUSY&quot; # Free/Busy section
697
- 158 component.add_component parse_component(Freebusy.new)
698
- 159 when &quot;VTIMEZONE&quot; # Timezone specification
699
- 160 component.add_component parse_component(Timezone.new)
700
- 161 when &quot;STANDARD&quot; # Standard time sub-component for timezone
701
- 162 component.add_component parse_component(Standard.new)
702
- 163 when &quot;DAYLIGHT&quot; # Daylight time sub-component for timezone
703
- 164 component.add_component parse_component(Daylight.new)
704
- 165 else # Uknown component type, skip to matching end
705
- 166 until ((line = next_line) == &quot;END:#{fields[:value]}&quot;); end
706
- 167 next
707
- 168 end
708
- </span><span class="marked">169 else # If its not a component then it should be a property
709
- 170
710
- 171 params = fields[:params]
711
- 172 value = fields[:value]
712
- 173
713
- 174 # Lookup the property name to see if we have a string to
714
- 175 # object parser for this property type.
715
- 176 if @parsers.has_key?(name)
716
- </span><span class="false">177 value = @parsers[name].call(name, params, value)
717
- 178 end
718
- </span><span class="marked">179
719
- 180 name = name.downcase
720
- 181
721
- 182 # TODO: check to see if there are any more conflicts.
722
- 183 if name == 'class' or name == 'method'
723
- </span><span class="false">184 name = &quot;ip_&quot; + name
724
- 185 end
725
- </span><span class="marked">186
726
- 187 # Replace dashes with underscores
727
- 188 name = name.gsub('-', '_')
728
- 189
729
- 190 if component.multi_property?(name)
730
- </span><span class="false">191 adder = &quot;add_&quot; + name
731
- 192 if component.respond_to?(adder)
732
- 193 component.send(adder, value, params)
733
- 194 else
734
- 195 raise(UnknownPropertyMethod, &quot;Unknown property type: #{adder}&quot;)
735
- 196 end
736
- </span><span class="marked">197 else
737
- 198 if component.respond_to?(name)
738
- 199 component.send(name, value, params)
739
- </span><span class="false">200 else
740
- 201 raise(UnknownPropertyMethod, &quot;Unknown property type: #{name}&quot;)
741
- 202 end
742
- 203 end
743
- 204 end
744
- 205 end
745
- </span><span class="marked">206
746
- 207 component
747
- 208 end
748
- 209
749
- 210 # 1*(ALPHA / DIGIT / &quot;=&quot;)
750
- 211 NAME = '[-a-z0-9]+'
751
- 212
752
- 213 # &lt;&quot;&gt; &lt;Any character except CTLs, DQUOTE&gt; &lt;&quot;&gt;
753
- 214 QSTR = '&quot;[^&quot;]*&quot;'
754
- 215
755
- 216 # Contentline
756
- 217 LINE = &quot;(#{NAME})(.*(?:#{QSTR})|(?:[^:]*))\:(.*)&quot;
757
- 218
758
- 219 # *&lt;Any character except CTLs, DQUOTE, &quot;;&quot;, &quot;:&quot;, &quot;,&quot;&gt;
759
- 220 PTEXT = '[^&quot;;:,]*'
760
- 221
761
- 222 # param-value = ptext / quoted-string
762
- 223 PVALUE = &quot;#{QSTR}|#{PTEXT}&quot;
763
- 224
764
- 225 # param = name &quot;=&quot; param-value *(&quot;,&quot; param-value)
765
- 226 PARAM = &quot;;(#{NAME})(=?)((?:#{PVALUE})(?:,#{PVALUE})*)&quot;
766
- 227
767
- 228 def parse_line(line)
768
- 229 unless line =~ %r{#{LINE}}i # Case insensitive match for a valid line
769
- 230 raise &quot;Invalid line in calendar string!&quot;
770
- 231 end
771
- 232
772
- 233 name = $1.upcase # The case insensitive part is upcased for easier comparison...
773
- 234 paramslist = $2
774
- 235 value = $3
775
- 236
776
- 237 # Parse the parameters
777
- 238 params = {}
778
- 239 if paramslist.size &gt; 1
779
- 240 paramslist.scan( %r{#{PARAM}}i ) do
780
- 241
781
- 242 # parameter names are case-insensitive, and multi-valued
782
- 243 pname = $1
783
- 244 pvals = $3
784
- 245
785
- 246 # If their isn't an '=' sign then we need to do some custom
786
- 247 # business. Defaults to 'type'
787
- 248 if $2 == &quot;&quot;
788
- </span><span class="false">249 pvals = $1
789
- 250 case $1
790
- 251 when /quoted-printable/i
791
- 252 pname = 'encoding'
792
- 253
793
- 254 when /base64/i
794
- 255 pname = 'encoding'
795
- 256
796
- 257 else
797
- 258 pname = 'type'
798
- 259 end
799
- 260 end
800
- </span><span class="marked">261
801
- 262 # Make entries into the params dictionary where the name
802
- 263 # is the key and the value is an array of values.
803
- 264 unless params.key? pname
804
- 265 params[pname] = []
805
- 266 end
806
- 267
807
- 268 # Save all the values into the array.
808
- 269 pvals.scan( %r{(#{PVALUE})} ) do
809
- 270 if $1.size &gt; 0
810
- 271 params[pname] &lt;&lt; $1
811
- 272 end
812
- 273 end
813
- 274 end
814
- 275 end
815
- 276
816
- 277 {:name =&gt; name, :value =&gt; value, :params =&gt; params}
817
- 278 end
818
- 279
819
- 280 ## Following is a collection of parsing functions for various
820
- 281 ## icalendar property value data types... First we setup
821
- 282 ## a hash with property names pointing to methods...
822
- 283 def setup_parsers
823
- 284 @parsers = {}
824
- 285
825
- 286 # Integer properties
826
- 287 m = self.method(:parse_integer)
827
- 288 @parsers[&quot;PERCENT-COMPLETE&quot;] = m
828
- 289 @parsers[&quot;PRIORITY&quot;] = m
829
- 290 @parsers[&quot;REPEAT&quot;] = m
830
- 291 @parsers[&quot;SEQUENCE&quot;] = m
831
- 292
832
- 293 # Dates and Times
833
- 294 m = self.method(:parse_datetime)
834
- 295 @parsers[&quot;COMPLETED&quot;] = m
835
- 296 @parsers[&quot;DTEND&quot;] = m
836
- 297 @parsers[&quot;DUE&quot;] = m
837
- 298 @parsers[&quot;DTSTART&quot;] = m
838
- 299 @parsers[&quot;RECURRENCE-ID&quot;] = m
839
- 300 @parsers[&quot;EXDATE&quot;] = m
840
- 301 @parsers[&quot;RDATE&quot;] = m
841
- 302 @parsers[&quot;CREATED&quot;] = m
842
- 303 @parsers[&quot;DTSTAMP&quot;] = m
843
- 304 @parsers[&quot;LAST-MODIFIED&quot;] = m
844
- 305
845
- 306 # URI's
846
- 307 m = self.method(:parse_uri)
847
- 308 @parsers[&quot;TZURL&quot;] = m
848
- 309 @parsers[&quot;ATTENDEE&quot;] = m
849
- 310 @parsers[&quot;ORGANIZER&quot;] = m
850
- 311 @parsers[&quot;URL&quot;] = m
851
- 312
852
- 313 # This is a URI by default, and if its not a valid URI
853
- 314 # it will be returned as a string which works for binary data
854
- 315 # the other possible type.
855
- 316 @parsers[&quot;ATTACH&quot;] = m
856
- 317
857
- 318 # GEO
858
- 319 m = self.method(:parse_geo)
859
- 320 @parsers[&quot;GEO&quot;] = m
860
- 321
861
- 322 end
862
- 323
863
- 324 # Booleans
864
- 325 # NOTE: It appears that although this is a valid data type
865
- 326 # there aren't any properties that use it... Maybe get
866
- 327 # rid of this in the future.
867
- 328 def parse_boolean(name, params, value)
868
- </span><span class="false">329 if value.upcase == &quot;FALSE&quot;
869
- 330 false
870
- 331 else
871
- 332 true
872
- 333 end
873
- 334 end
874
- </span><span class="marked">335
875
- 336 # Dates, Date-Times &amp; Times
876
- 337 # NOTE: invalid dates &amp; times will be returned as strings...
877
- 338 def parse_datetime(name, params, value)
878
- </span><span class="false">339 begin
879
- 340 DateTime.parse(value)
880
- 341 rescue Exception
881
- 342 value
882
- 343 end
883
- 344
884
- 345 end
885
- </span><span class="marked">346
886
- 347 # Durations
887
- 348 # TODO: Need to figure out the best way to represent durations
888
- 349 # so just returning string for now.
889
- 350 def parse_duration(name, params, value)
890
- </span><span class="false">351 value
891
- 352 end
892
- </span><span class="marked">353
893
- 354 # Floats
894
- 355 # NOTE: returns 0.0 if it can't parse the value
895
- 356 def parse_float(name, params, value)
896
- </span><span class="false">357 value.to_f
897
- 358 end
898
- </span><span class="marked">359
899
- 360 # Integers
900
- 361 # NOTE: returns 0 if it can't parse the value
901
- 362 def parse_integer(name, params, value)
902
- </span><span class="false">363 value.to_i
903
- 364 end
904
- </span><span class="marked">365
905
- 366 # Periods
906
- 367 # TODO: Got to figure out how to represent periods also...
907
- 368 def parse_period(name, params, value)
908
- </span><span class="false">369 value
909
- 370 end
910
- </span><span class="marked">371
911
- 372 # Calendar Address's &amp; URI's
912
- 373 # NOTE: invalid URI's will be returned as strings...
913
- 374 def parse_uri(name, params, value)
914
- </span><span class="false">375 begin
915
- 376 URI.parse(value)
916
- 377 rescue Exception
917
- 378 value
918
- 379 end
919
- 380 end
920
- </span><span class="marked">381
921
- 382 # Geographical location (GEO)
922
- 383 # NOTE: returns an array with two floats (long &amp; lat)
923
- 384 # if the parsing fails return the string
924
- 385 def parse_geo(name, params, value)
925
- </span><span class="false">386 strloc = value.split(';')
926
- 387 if strloc.size != 2
927
- 388 return value
928
- 389 end
929
- 390
930
- 391 val = []
931
- 392 val[0] = strloc[0].to_f
932
- 393 val[1] = strloc[1].to_f
933
- 394 val
934
- 395 end
935
- 396
936
- 397 end
937
- 398 end
938
- </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>