icalendar 0.97 → 0.98

Sign up to get free protection for your applications and to get access to all the features.
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>