vpim2 0.0.1

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 (61) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +504 -0
  3. data/COPYING +58 -0
  4. data/README +182 -0
  5. data/lib/atom.rb +728 -0
  6. data/lib/plist.rb +22 -0
  7. data/lib/vpim.rb +13 -0
  8. data/lib/vpim/address.rb +219 -0
  9. data/lib/vpim/attachment.rb +102 -0
  10. data/lib/vpim/date.rb +222 -0
  11. data/lib/vpim/dirinfo.rb +277 -0
  12. data/lib/vpim/duration.rb +119 -0
  13. data/lib/vpim/enumerator.rb +32 -0
  14. data/lib/vpim/field.rb +614 -0
  15. data/lib/vpim/icalendar.rb +381 -0
  16. data/lib/vpim/maker/vcard.rb +16 -0
  17. data/lib/vpim/property/base.rb +193 -0
  18. data/lib/vpim/property/common.rb +315 -0
  19. data/lib/vpim/property/location.rb +38 -0
  20. data/lib/vpim/property/priority.rb +43 -0
  21. data/lib/vpim/property/recurrence.rb +69 -0
  22. data/lib/vpim/property/resources.rb +24 -0
  23. data/lib/vpim/repo.rb +181 -0
  24. data/lib/vpim/rfc2425.rb +367 -0
  25. data/lib/vpim/rrule.rb +591 -0
  26. data/lib/vpim/vcard.rb +1430 -0
  27. data/lib/vpim/version.rb +18 -0
  28. data/lib/vpim/vevent.rb +187 -0
  29. data/lib/vpim/view.rb +90 -0
  30. data/lib/vpim/vjournal.rb +58 -0
  31. data/lib/vpim/vpim.rb +65 -0
  32. data/lib/vpim/vtodo.rb +103 -0
  33. data/samples/README.mutt +93 -0
  34. data/samples/ab-query.rb +57 -0
  35. data/samples/cmd-itip.rb +156 -0
  36. data/samples/ex_cpvcard.rb +55 -0
  37. data/samples/ex_get_vcard_photo.rb +22 -0
  38. data/samples/ex_mkv21vcard.rb +34 -0
  39. data/samples/ex_mkvcard.rb +64 -0
  40. data/samples/ex_mkyourown.rb +29 -0
  41. data/samples/ics-dump.rb +210 -0
  42. data/samples/ics-to-rss.rb +84 -0
  43. data/samples/mutt-aliases-to-vcf.rb +45 -0
  44. data/samples/osx-wrappers.rb +86 -0
  45. data/samples/reminder.rb +203 -0
  46. data/samples/rrule.rb +71 -0
  47. data/samples/tabbed-file-to-vcf.rb +390 -0
  48. data/samples/vcf-dump.rb +86 -0
  49. data/samples/vcf-lines.rb +61 -0
  50. data/samples/vcf-to-ics.rb +22 -0
  51. data/samples/vcf-to-mutt.rb +121 -0
  52. data/test/test_all.rb +17 -0
  53. data/test/test_date.rb +120 -0
  54. data/test/test_dur.rb +41 -0
  55. data/test/test_field.rb +156 -0
  56. data/test/test_ical.rb +415 -0
  57. data/test/test_repo.rb +158 -0
  58. data/test/test_rrule.rb +1030 -0
  59. data/test/test_vcard.rb +973 -0
  60. data/test/test_view.rb +79 -0
  61. metadata +117 -0
@@ -0,0 +1,315 @@
1
+ =begin
2
+ Copyright (C) 2008 Sam Roberts
3
+
4
+ This library is free software; you can redistribute it and/or modify it
5
+ under the same terms as the ruby language itself, see the file COPYING for
6
+ details.
7
+ =end
8
+
9
+ require 'vpim/address'
10
+ require 'vpim/attachment'
11
+
12
+ module Vpim
13
+ class Icalendar
14
+ module Property
15
+
16
+ # Properties common to Vevent, Vtodo, and Vjournal.
17
+ module Common
18
+
19
+ # This property defines the access classification for a calendar
20
+ # component.
21
+ #
22
+ # An access classification is only one component of the general
23
+ # security system within a calendar application. It provides a method
24
+ # of capturing the scope of the access the calendar owner intends for
25
+ # information within an individual calendar entry. The access
26
+ # classification of an individual iCalendar component is useful when
27
+ # measured along with the other security components of a calendar
28
+ # system (e.g., calendar user authentication, authorization, access
29
+ # rights, access role, etc.). Hence, the semantics of the individual
30
+ # access classifications cannot be completely defined by this memo
31
+ # alone. Additionally, due to the "blind" nature of most exchange
32
+ # processes using this memo, these access classifications cannot serve
33
+ # as an enforcement statement for a system receiving an iCalendar
34
+ # object. Rather, they provide a method for capturing the intention of
35
+ # the calendar owner for the access to the calendar component.
36
+ #
37
+ # Property Name: CLASS
38
+ #
39
+ # Property Value: one of "PUBLIC", "PRIVATE", "CONFIDENTIAL", default
40
+ # is "PUBLIC" if no CLASS property is found.
41
+ def access_class
42
+ proptoken 'CLASS', ["PUBLIC", "PRIVATE", "CONFIDENTIAL"], "PUBLIC"
43
+ end
44
+
45
+ def created
46
+ proptime 'CREATED'
47
+ end
48
+
49
+ # Description of the calendar component, or nil if there is no
50
+ # description.
51
+ def description
52
+ proptext 'DESCRIPTION'
53
+ end
54
+
55
+ # Revision sequence number of the calendar component, or nil if there
56
+ # is no SEQUENCE; property.
57
+ def sequence
58
+ propinteger 'SEQUENCE'
59
+ end
60
+
61
+ # The time stamp for this calendar component.
62
+ def dtstamp
63
+ proptime 'DTSTAMP'
64
+ end
65
+
66
+ # The start time for this calendar component.
67
+ def dtstart
68
+ proptime 'DTSTART'
69
+ end
70
+
71
+ def lastmod
72
+ proptime 'LAST-MODIFIED'
73
+ end
74
+
75
+ # Return the event organizer, an object of Icalendar::Address (or nil if
76
+ # there is no ORGANIZER field).
77
+ def organizer
78
+ organizer = @properties.field('ORGANIZER')
79
+
80
+ if organizer
81
+ organizer = Icalendar::Address.decode(organizer)
82
+ end
83
+
84
+ organizer.freeze
85
+ end
86
+
87
+ =begin
88
+ recurid
89
+ seq
90
+ =end
91
+
92
+ # Status values are not rejected during decoding. However, if the
93
+ # status is requested, and it's value is not one of the defined
94
+ # allowable values, an exception is raised.
95
+ def status
96
+ case self
97
+ when Vpim::Icalendar::Vevent
98
+ proptoken 'STATUS', ['TENTATIVE', 'CONFIRMED', 'CANCELLED']
99
+
100
+ when Vpim::Icalendar::Vtodo
101
+ proptoken 'STATUS', ['NEEDS-ACTION', 'COMPLETED', 'IN-PROCESS', 'CANCELLED']
102
+
103
+ when Vpim::Icalendar::Vevent
104
+ proptoken 'STATUS', ['DRAFT', 'FINAL', 'CANCELLED']
105
+ end
106
+ end
107
+
108
+ # TODO - def status? ...
109
+
110
+ # TODO - def status= ...
111
+
112
+ # Summary description of the calendar component, or nil if there is no
113
+ # SUMMARY property.
114
+ def summary
115
+ proptext 'SUMMARY'
116
+ end
117
+
118
+ # The unique identifier of this calendar component, a string.
119
+ def uid
120
+ proptext 'UID'
121
+ end
122
+
123
+ def url
124
+ propvalue 'URL'
125
+ end
126
+
127
+ # Return an array of attendees, an empty array if there are none. The
128
+ # attendees are objects of Icalendar::Address. If +uri+ is specified
129
+ # only the return the attendees with this +uri+.
130
+ def attendees(uri = nil)
131
+ attendees = @properties.enum_by_name('ATTENDEE').map { |a| Icalendar::Address.decode(a) }
132
+ attendees.freeze
133
+ if uri
134
+ attendees.select { |a| a == uri }
135
+ else
136
+ attendees
137
+ end
138
+ end
139
+
140
+ # Return true if the +uri+, usually a mailto: URI, is an attendee.
141
+ def attendee?(uri)
142
+ attendees.include? uri
143
+ end
144
+
145
+ # This property defines the categories for a calendar component.
146
+ #
147
+ # Property Name: CATEGORIES
148
+ #
149
+ # Value Type: TEXT
150
+ #
151
+ # Ruby Type: Array of String
152
+ #
153
+ # This property is used to specify categories or subtypes of the
154
+ # calendar component. The categories are useful in searching for a
155
+ # calendar component of a particular type and category.
156
+ def categories
157
+ proptextlistarray 'CATEGORIES'
158
+ end
159
+
160
+ def comments
161
+ proptextarray 'COMMENT'
162
+ end
163
+
164
+ def contacts
165
+ proptextarray 'CONTACT'
166
+ end
167
+
168
+ # An Array of attachments, see Attachment for more information.
169
+ def attachments
170
+ @properties.enum_by_name('ATTACH').map do |f|
171
+ attachment = Attachment.decode(f, 'uri', 'FMTTYPE')
172
+ end
173
+ end
174
+ end
175
+
176
+ end
177
+
178
+ module Set
179
+
180
+ # Properties common to Vevent, Vtodo, and Vjournal.
181
+ module Common
182
+
183
+ # Set the access class of the component, see Icalendar::Property::Common#access_class.
184
+ def access_class(token)
185
+ set_token 'CLASS', ["PUBLIC", "PRIVATE", "CONFIDENTIAL"], "PUBLIC", token
186
+ end
187
+
188
+ # Set the creation time, see Icalendar::Property::Common#created
189
+ def created(time)
190
+ set_datetime 'CREATED', time
191
+ end
192
+
193
+ # Set the description, see Icalendar::Property::Common#description.
194
+ def description(text)
195
+ set_text 'DESCRIPTION', text
196
+ end
197
+
198
+ # Set the sequence number, see Icalendar::Property::Common#sequence.
199
+ # is no SEQUENCE; property.
200
+ def sequence(int)
201
+ set_integer 'SEQUENCE', int
202
+ end
203
+
204
+ # Set the timestamp, see Icalendar::Property::Common#timestamp.
205
+ def dtstamp(time)
206
+ set_datetime 'DTSTAMP', time
207
+ self
208
+ end
209
+
210
+ # The start time or date, see Icalendar::Property::Common#dtstart.
211
+ def dtstart(start)
212
+ set_date_or_datetime 'DTSTART', 'DATE-TIME', start
213
+ self
214
+ end
215
+
216
+ # Set the last modification time, see Icalendar::Property::Common#lastmod.
217
+ def lastmod(time)
218
+ set_datetime 'LAST-MODIFIED', time
219
+ self
220
+ end
221
+
222
+ # Set the event organizer, an Icalendar::Address, see Icalendar::Property::Common#organizer.
223
+ #
224
+ # Without an +adr+ it yields an Icalendar::Address that is a copy of
225
+ # the current organizer (if any), allowing it to be modified.
226
+ def organizer(adr=nil) #:yield: organizer
227
+ unless adr
228
+ adr = @comp.organizer
229
+ if adr
230
+ adr = adr.copy
231
+ else
232
+ adr = Icalendar::Address.create
233
+ end
234
+ yield adr
235
+ end
236
+ set_address('ORGANIZER', adr)
237
+ self
238
+ end
239
+
240
+ =begin
241
+ # Status values are not rejected during decoding. However, if the
242
+ # status is requested, and it's value is not one of the defined
243
+ # allowable values, an exception is raised.
244
+ def status
245
+ case self
246
+ when Vpim::Icalendar::Vevent
247
+ proptoken 'STATUS', ['TENTATIVE', 'CONFIRMED', 'CANCELLED']
248
+
249
+ when Vpim::Icalendar::Vtodo
250
+ proptoken 'STATUS', ['NEEDS-ACTION', 'COMPLETED', 'IN-PROCESS', 'CANCELLED']
251
+
252
+ when Vpim::Icalendar::Vevent
253
+ proptoken 'STATUS', ['DRAFT', 'FINAL', 'CANCELLED']
254
+ end
255
+ end
256
+ =end
257
+
258
+ # Set summary description of component, see Icalendar::Property::Common#summary.
259
+ def summary(text)
260
+ set_text 'SUMMARY', text
261
+ end
262
+
263
+ # Set the unique identifier of this calendar component, see Icalendar::Property::Common#uid.
264
+ def uid(uid)
265
+ set_text 'UID', uid
266
+ end
267
+
268
+ def url(url)
269
+ set_text 'URL', url
270
+ end
271
+
272
+ # Add an attendee Address, see Icalendar::Property::Common#attendees.
273
+ def add_attendee(adr)
274
+ add_address('ATTENDEE', adr)
275
+ end
276
+
277
+ # Set the categories, see Icalendar::Property::Common#attendees.
278
+ #
279
+ # If +cats+ is provided, the categories are set to cats, either a
280
+ # String or an Array of String. Otherwise, and array of the existing
281
+ # category strings is yielded, and it can be modified.
282
+ def categories(cats = nil) #:yield: categories
283
+ unless cats
284
+ cats = @comp.categories
285
+ yield cats
286
+ end
287
+ # TODO - strip the strings
288
+ set_text_list('CATEGORIES', cats)
289
+ end
290
+
291
+ # Set the comment, see Icalendar::Property::Common#comments.
292
+ def comment(value)
293
+ set_text 'COMMENT', value
294
+ end
295
+
296
+ =begin
297
+ def contacts
298
+ proptextarray 'CONTACT'
299
+ end
300
+
301
+ # An Array of attachments, see Attachment for more information.
302
+ def attachments
303
+ @properties.enum_by_name('ATTACH').map do |f|
304
+ attachment = Attachment.decode(f, 'uri', 'FMTTYPE')
305
+ end
306
+ end
307
+ =end
308
+
309
+ end
310
+
311
+ end
312
+ end
313
+ end
314
+
315
+
@@ -0,0 +1,38 @@
1
+ =begin
2
+ Copyright (C) 2008 Sam Roberts
3
+
4
+ This library is free software; you can redistribute it and/or modify it
5
+ under the same terms as the ruby language itself, see the file COPYING for
6
+ details.
7
+ =end
8
+
9
+ module Vpim
10
+ class Icalendar
11
+ module Property
12
+ module Location
13
+ # Physical location information relevant to the component, or nil if
14
+ # there is no LOCATION property.
15
+ def location
16
+ proptext 'LOCATION'
17
+ end
18
+
19
+ # Array of Float, +[ latitude, longitude]+.
20
+ #
21
+ # North of the equator is positive latitude, east of the meridian is
22
+ # positive longitude.
23
+ #
24
+ # See RFC2445 for more info... there are lots of special cases.
25
+ def geo
26
+ prop = @properties.detect { |f| f.name? 'GEO' }
27
+ if prop
28
+ prop = Vpim.decode_list(prop.value_raw, ';') do |item| item.to_f end
29
+ end
30
+ prop
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+
@@ -0,0 +1,43 @@
1
+ =begin
2
+ Copyright (C) 2008 Sam Roberts
3
+
4
+ This library is free software; you can redistribute it and/or modify it
5
+ under the same terms as the ruby language itself, see the file COPYING for
6
+ details.
7
+ =end
8
+
9
+ module Vpim
10
+ class Icalendar
11
+ module Property
12
+ module Priority
13
+
14
+ # +priority+ is a number from 1 to 9, with 1 being the highest
15
+ # priority, 9 being the lowest. 0 means "no priority", equivalent to
16
+ # not specifying the PRIORITY field.
17
+ #
18
+ # The other integer values are reserved by RFC2445.
19
+ #
20
+ # TODO
21
+ # - methods to compare priorities?
22
+ # - return as class Priority, with #to_i, and #to_s, and appropriate
23
+ # comparison operators?
24
+ def priority
25
+ p = @properties.detect { |f| f.name? 'PRIORITY' }
26
+
27
+ if !p
28
+ p = 0
29
+ else
30
+ p = p.value.to_i
31
+
32
+ if( p < 0 || p > 9 )
33
+ raise Vpim::InvalidEncodingError, 'Invalid priority #{@priority} - it must be 0-9!'
34
+ end
35
+ end
36
+ p
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+
@@ -0,0 +1,69 @@
1
+ =begin
2
+ Copyright (C) 2008 Sam Roberts
3
+
4
+ This library is free software; you can redistribute it and/or modify it
5
+ under the same terms as the ruby language itself, see the file COPYING for
6
+ details.
7
+ =end
8
+
9
+ require "enumerator"
10
+
11
+ module Vpim
12
+ class Icalendar
13
+ module Property
14
+
15
+ # Occurrences are calculated from DTSTART and RRULE. If there is no
16
+ # RRULE, the component occurs only once, at the start time.
17
+ #
18
+ # Limitations:
19
+ #
20
+ # Only a single RRULE: is currently supported, this is the most common
21
+ # case.
22
+ module Recurrence
23
+ def rrule #:nodoc:
24
+ start = dtstart
25
+ unless start
26
+ raise ArgumentError, "Components without a DTSTART don't have occurrences!"
27
+ end
28
+ Vpim::Rrule.new(start, propvalue('RRULE'))
29
+ end
30
+
31
+ # The times this components occurs. If a block is not provided, returns
32
+ # an enumerator.
33
+ #
34
+ # Occurrences may be infinite, +dountil+ can be provided to limit the
35
+ # iterations, see Rrule#each.
36
+ def occurrences(dountil = nil, &block) #:yield: occurrence time
37
+ rr = rrule
38
+ unless block_given?
39
+ return Enumerable::Enumerator.new(self, :occurrences, dountil)
40
+ end
41
+
42
+ rr.each(dountil, &block)
43
+ end
44
+
45
+ alias occurences occurrences #:nodoc: backwards compatibility
46
+
47
+ # True if this components occurs in a time period later than +t0+, but
48
+ # earlier than +t1+.
49
+ def occurs_in?(t0, t1)
50
+ # TODO - deprecate this, its a hack
51
+ occurrences(t1).detect do |tend|
52
+ if respond_to? :duration
53
+ tend += duration || 0
54
+ end
55
+ tend >= t0
56
+ end
57
+ end
58
+
59
+ def rdates #:nodoc:
60
+ # TODO - this is a hack, remove it
61
+ Vpim.decode_date_time_list(propvalue('RDATE'))
62
+ end
63
+
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+