vpim 0.17 → 0.323

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.
data/lib/vpim/dirinfo.rb CHANGED
@@ -20,7 +20,7 @@ module Vpim
20
20
  #
21
21
  # A vCard, for example, is a specialization of a directory info object.
22
22
  #
23
- # [RFC2425] the directory information framework (ftp://ftp.ietf.org/rfc/rfc2425.txt)
23
+ # - [RFC2425] the directory information framework (ftp://ftp.ietf.org/rfc/rfc2425.txt)
24
24
  class DirectoryInfo
25
25
  include Enumerable
26
26
 
@@ -42,7 +42,7 @@ module Vpim
42
42
  # Decode +card+ into a DirectoryInfo object.
43
43
  #
44
44
  # +card+ may either be a something that is convertible to a string using
45
- # #to_str or an array of objects that can be joined into a string using
45
+ # #to_str or an Array of objects that can be joined into a string using
46
46
  # #join("\n"), or an IO object (which will be read to end-of-file).
47
47
  #
48
48
  # The lines in the string may be delimited using IETF (CRLF) or Unix (LF) conventions.
@@ -108,7 +108,13 @@ module Vpim
108
108
  #
109
109
  # TODO - call this #texts(), as in the plural?
110
110
  def text(name)
111
- enum_by_name(name).map { |f| f.to_text }
111
+ accum = []
112
+ each do |f|
113
+ if f.name? name
114
+ accum << f.to_text
115
+ end
116
+ end
117
+ accum
112
118
  end
113
119
 
114
120
  # Array of all the Field#group()s.
@@ -161,9 +167,9 @@ module Vpim
161
167
  # end
162
168
  # end
163
169
  #
164
- # or to get an array of all the fields in group 'agroup', you could do:
170
+ # or to get an array of all the fields in group 'AGROUP', you could do:
165
171
  #
166
- # card.enum_by_group('agroup').to_a
172
+ # card.enum_by_group('AGROUP').to_a
167
173
  def enum_by_group(group)
168
174
  Enumerator.new(self, Proc.new { |field| field.group?(group) })
169
175
  end
data/lib/vpim/field.rb CHANGED
@@ -67,7 +67,7 @@ module Vpim
67
67
  pvalues.each do |pvalue|
68
68
  # check if we need to do any encoding
69
69
  if Vpim::Methods.casecmp?(pname, 'ENCODING') && pvalue == :b64
70
- pvalue = 'b' # the RFC definition of the base64 param value
70
+ pvalue = 'B' # the RFC definition of the base64 param value
71
71
  value = [ value.to_str ].pack('m').gsub("\n", '')
72
72
  end
73
73
 
@@ -139,7 +139,7 @@ module Vpim
139
139
  params = $3
140
140
 
141
141
  # v2.1 params have no '=' sign, figure out what kind of param it
142
- # is (either its a known encoding, or we treat it as a 'type'
142
+ # is (either its a known encoding, or we treat it as a 'TYPE'
143
143
  # param).
144
144
 
145
145
  if $2 == ""
@@ -192,9 +192,9 @@ module Vpim
192
192
  # name (a String) to either a single string or symbol, or an array of
193
193
  # strings and symbols (parameters can be multi-valued).
194
194
  #
195
- # If 'encoding' => :b64 is specified as a parameter, the value will be
195
+ # If 'ENCODING' => :b64 is specified as a parameter, the value will be
196
196
  # base-64 encoded. If it's already base-64 encoded, then use String
197
- # values ('encoding' => 'b'), and no further encoding will be done by
197
+ # values ('ENCODING' => 'B'), and no further encoding will be done by
198
198
  # this routine.
199
199
  #
200
200
  # Currently handled value types are:
@@ -290,16 +290,21 @@ module Vpim
290
290
  # Note: Both the RFC 2425 encoding param ("b", meaning base-64) and the
291
291
  # vCard 2.1 encoding params ("base64", "quoted-printable", "8bit", and
292
292
  # "7bit") are supported.
293
+ #
294
+ # FIXME:
295
+ # - should use the VALUE parameter
296
+ # - should also take a default value type, so it can be converted
297
+ # if VALUE parameter is not present.
293
298
  def value
294
299
  case encoding
295
- when nil, '8bit', '7bit' then @value
300
+ when nil, '8BIT', '7BIT' then @value
296
301
 
297
302
  # Hack - if the base64 lines started with 2 SPC chars, which is invalid,
298
303
  # there will be extra spaces in @value. Since no SPC chars show up in
299
304
  # b64 encodings, they can be safely stripped out before unpacking.
300
- when 'b', 'base64' then @value.gsub(' ', '').unpack('m*').first
305
+ when 'B', 'BASE64' then @value.gsub(' ', '').unpack('m*').first
301
306
 
302
- when 'quoted-printable' then @value.unpack('M*').first
307
+ when 'QUOTED-PRINTABLE' then @value.unpack('M*').first
303
308
 
304
309
  else
305
310
  raise Vpim::InvalidEncodingError, "unrecognized encoding (#{encoding})"
@@ -346,7 +351,7 @@ module Vpim
346
351
  def type?(type)
347
352
  type = type.to_str
348
353
 
349
- types = param('type')
354
+ types = param('TYPE')
350
355
 
351
356
  if types
352
357
  types = types.detect { |t| Vpim::Methods.casecmp?(t, type) }
@@ -354,18 +359,18 @@ module Vpim
354
359
  end
355
360
 
356
361
  # Is this field marked as preferred? A vCard field is preferred if
357
- # #type?('pref'). This method is not necessarily meaningful for
362
+ # #type?('PREF'). This method is not necessarily meaningful for
358
363
  # non-vCard profiles.
359
364
  def pref?
360
- type? 'pref'
365
+ type? 'PREF'
361
366
  end
362
367
 
363
368
  # Set whether a field is marked as preferred. See #pref?
364
369
  def pref=(ispref)
365
370
  if ispref
366
- pvalue_iadd('type', 'pref')
371
+ pvalue_iadd('TYPE', 'PREF')
367
372
  else
368
- pvalue_idel('type', 'pref')
373
+ pvalue_idel('TYPE', 'PREF')
369
374
  end
370
375
  end
371
376
 
@@ -378,13 +383,13 @@ module Vpim
378
383
  # The value of the ENCODING parameter, if present, or nil if not
379
384
  # present.
380
385
  def encoding
381
- e = param("encoding")
386
+ e = param('ENCODING')
382
387
 
383
388
  if e
384
389
  if e.length > 1
385
- raise Vpim::InvalidEncodingError, "multi-valued param 'encoding' (#{e})"
390
+ raise Vpim::InvalidEncodingError, "multi-valued param 'ENCODING' (#{e})"
386
391
  end
387
- e = e.first.downcase
392
+ e = e.first.upcase
388
393
  end
389
394
  e
390
395
  end
@@ -392,10 +397,10 @@ module Vpim
392
397
  # The type of the value, as specified by the VALUE parameter, nil if
393
398
  # unspecified.
394
399
  def kind
395
- v = param('value')
400
+ v = param('VALUE')
396
401
  if v
397
402
  if v.size > 1
398
- raise InvalidEncodingError, "multi-valued param 'value' (#{values})"
403
+ raise InvalidEncodingError, "multi-valued param 'VALUE' (#{values})"
399
404
  end
400
405
  v = v.first
401
406
  end
@@ -465,7 +470,7 @@ module Vpim
465
470
  # characters, this method will strip them, if present.
466
471
  #
467
472
  # In theory, #value could also do this, but it would need to know that
468
- # the value is of type 'text', and often for text values the 'type'
473
+ # the value is of type 'TEXT', and often for text values the 'VALUE'
469
474
  # parameter is not present, so knowledge of the expected type of the
470
475
  # field is required from the decoder.
471
476
  def to_text
@@ -502,10 +507,10 @@ module Vpim
502
507
  # currently has. See Field.create() for a description of +pvalue+.
503
508
  #
504
509
  # Example:
505
- # if field['type']
506
- # field['type'] << 'home'
510
+ # if field['TYPE']
511
+ # field['TYPE'] << 'HOME'
507
512
  # else
508
- # field['type'] = [ 'home'
513
+ # field['TYPE'] = [ 'HOME' ]
509
514
  # end
510
515
  #
511
516
  # TODO - this could be an alias to #pvalue_set
@@ -12,106 +12,6 @@ require 'vpim/rrule'
12
12
  require 'vpim/vevent'
13
13
  require 'vpim/vpim'
14
14
 
15
- =begin
16
-
17
- ... ; y/n (whether I've seen it in Apple's calendars)
18
- name
19
- section
20
- type/comments
21
-
22
-
23
- icalbody = icalprops component
24
-
25
- icalprops =
26
- prodid / ; y PRODID 4.7.3 required, TEXT
27
- version / ; y 4.7.4 required, TEXT, "2.0"
28
- calscal / ; y 4.7.1 only defined value is GREGORIAN
29
- method / ; n METHOD 4.7.2 used with transport protocols
30
-
31
- component =
32
- eventc / ; y VEVENT 4.6.1
33
- todoc / ; y VTODO 4.6.2
34
- journalc / ; n
35
- freebusyc / ; n
36
- timezonec / ; n
37
-
38
- alarmc ; y VALARM 4.6.6 occurs inside a VEVENT or a VTODO
39
-
40
- class ; y CLASS 4.8.1.3 private/public/confidentical/... (default=public)
41
-
42
- comment ; n 4.8.1.4 TEXT
43
- description ; y 4.8.1.5 TEXT
44
- summary ; y 4.8.1.12 TEXT
45
- location ; y 4.8.1.7 TEXT intended venue
46
-
47
- priority ; n why? 4.8.1.9 INTEGER, why isn't this seen for my TODO items?
48
-
49
- status ; y 4.8.1.11 TEXT, different values defined for event, todo, journal
50
-
51
- Event: TENTATIVE, CONFIRMED, CANCELLED
52
-
53
- Todo: NEEDS-ACTION, COMPLETED, IN-PROCESS, CANCELLED
54
-
55
- Journal: DRAFT, FINAL, CANCELLED
56
-
57
- dtstart ; y DTSTART 4.8.2.4 DATE-TIME is default, value=date can be set
58
- dtend ; y DTEND 4.8.2.2 Unless it has Z (UTC), or a tzid, then it is local-time.
59
-
60
- dtstamp ; y DTSTAMP 4.8.7.2 DATE-TIME, creation time, inclusion is mandatory, but what does
61
- it mean? It seems to be when the icalendar was actually created (as opposed to when the user entered
62
- the information into the calendar database, for example), but in that case my Apple icalendars should
63
- have all components having the same DTSTAMP, but they don't!
64
-
65
- duration ; y DURATION 4.8.2.5 dur-value
66
-
67
- dur-value = (["+"] / "-") "P" (dur-date / dur-time / dur-week)
68
-
69
- dur-date = dur-day [dur-time]
70
- = 1*DIGIT "D" [ dur-time ]
71
-
72
- dur-time = "T" (dur-hour / dur-minute / dur-second)
73
- = "T" (
74
- 1*DIGIT "H" [ 1*DIGIT "M" [ 1*DIGIT "S" ] ] /
75
- 1*DIGIT "M" [ 1*DIGIT "S" ] /
76
- 1*DIGIT "S"
77
- )
78
-
79
- dur-week = 1*DIGIT "W"
80
- dur-day = 1*DIGIT "D"
81
- dur-hour = 1*DIGIT "H" [dur-minute]
82
- dur-minute = 1*DIGIT "M" [dur-second]
83
- dur-second = 1*DIGIT "S"
84
-
85
- The EBNF is complicated, because they want to say that /some/ component
86
- must be present, and that if you have a "T", you need a time after it,
87
- and that you can't have an hour followed by seconds with no intervening
88
- minutes... but we don't care about that during decoding, so we rewrite
89
- the EBNF as:
90
-
91
- dur-value = ["+" / "-"] "P" [ 1*DIGIT "W" ] [ 1*DIGIT "D" ] [ "T" [ 1*DIGIT "H" ] [ 1*DIGIT "M" ] [ 1*DIGIT "S" ] ]
92
-
93
- dtdue ; n DTDUE 4.8.2.3
94
-
95
- uid ; y UID 4.8.4.7 TEXT, recommended to generate them in RFC822 form
96
-
97
- rrule ; y RRULE 4.8.5.4 RECUR, can occur multiple times!
98
-
99
-
100
-
101
- VEVENT Ifx:
102
-
103
- TEXT: summary, description, comment, location, uid
104
-
105
- think about: uid
106
-
107
- Vevent#status -> The status, upper-case.
108
- Vevent#status= -> set a new status, only allow the defined statuses!
109
- Vevent#status?(s) -> check if the status is s
110
-
111
- can contain alarms... should it include an alarms module?
112
-
113
- =end
114
-
115
15
  module Vpim
116
16
  # An iCalendar.
117
17
  #
@@ -167,12 +67,13 @@ module Vpim
167
67
  # Categorize the components
168
68
  @vevents = []
169
69
  @vtodos = []
70
+ @vjournals = []
170
71
  @others = []
171
72
 
172
73
  inner.each do |component|
173
74
  # First field in every component should be a "BEGIN:".
174
75
  name = component.first
175
- if ! name.name? 'begin'
76
+ if ! name.name? 'BEGIN'
176
77
  raise InvalidEncodingError, "calendar component begins with #{name.name}, instead of BEGIN!"
177
78
  end
178
79
 
@@ -181,6 +82,7 @@ module Vpim
181
82
  case name
182
83
  when 'VEVENT' then @vevents << Vevent.new(component)
183
84
  when 'VTODO' then @vtodos << Vtodo.new(component)
85
+ when 'VJOURNAL' then @vjournals << Vjournal.new(component)
184
86
  else @others << component
185
87
  end
186
88
  end
@@ -255,6 +157,8 @@ module Vpim
255
157
  @vevents << component
256
158
  when Vtodo
257
159
  @vtodos << component
160
+ when Vjournal
161
+ @vjournals << component
258
162
  else
259
163
  raise ArgumentError, "can't add component type #{component.type} to a calendar"
260
164
  end
@@ -359,23 +263,29 @@ module Vpim
359
263
  # transport a snapshot of some calendar information; without the intention
360
264
  # of conveying a scheduling semantic.
361
265
  #
362
- # Note that this can't be called 'method', that name is reserved.
266
+ # Note that this method can't be called +method+, thats already a method of
267
+ # Object.
363
268
  def protocol
364
269
  m = @properties['METHOD']
365
270
  m ? m.upcase : m
366
271
  end
367
272
 
368
- # The array of all calendar events (each is a Vevent).
273
+ # The array of all calendar event components (each is a Vevent).
369
274
  #
370
275
  # TODO - should this take an interval: t0,t1?
371
276
  def events
372
277
  @vevents
373
278
  end
374
279
 
375
- # The array of all calendar todos (each is a Vtodo).
280
+ # The array of all calendar todo components (each is a Vtodo).
376
281
  def todos
377
282
  @vtodos
378
283
  end
284
+
285
+ # The array of all calendar journal components (each is a Vjournal).
286
+ def journals
287
+ @vjournals
288
+ end
379
289
  end
380
290
 
381
291
  end
@@ -488,6 +398,10 @@ module Vpim
488
398
  end
489
399
  end
490
400
 
401
+ def inspect
402
+ "#<Vpim::Icalendar::Address:cn=#{cn.inspect} status=#{partstat} rsvp?=#{rsvp} #{uri.inspect}>"
403
+ end
404
+
491
405
  # The participation role for the calendar user specified by the address.
492
406
  #
493
407
  # The standard roles are:
@@ -526,13 +440,15 @@ module Vpim
526
440
  #
527
441
  # See #partstat.
528
442
  def partstat=(status)
529
- @field['partstat'] = status.to_str
443
+ @field['PARTSTAT'] = status.to_str
530
444
  status
531
445
  end
532
446
 
533
447
  # The value of the RSVP field, either +true+ or +false+. It is used to
534
448
  # specify whether there is an expectation of a favor of a reply from the
535
449
  # calendar user specified by the property value.
450
+ #
451
+ # TODO - should be #rsvp?
536
452
  def rsvp
537
453
  return false unless r = @field.param('RSVP')
538
454
  r = r.first
@@ -16,6 +16,7 @@ module Vpim
16
16
  # - link:ex_mkvcard.txt: example of creating a vCard
17
17
  # - link:ex_cpvcard.txt: example of copying and them modifying a vCard
18
18
  # - link:ex_mkv21vcard.txt: example of creating version 2.1 vCard
19
+ # - link:ex_mkyourown.txt: example of adding support for new fields to Maker::Vcard
19
20
  class Vcard
20
21
  # Make a vCard.
21
22
  #
@@ -80,16 +81,13 @@ module Vpim
80
81
  #
81
82
  # All attributes are optional.
82
83
  #
83
- # Warning: This is the only mandatory field besides the full name, FN,
84
- # but FN: can be set in #make, and if not set will be constucted as the
85
- # string "#{prefix} #{given} #{additional} #{family}, #{suffix}".
86
- #
87
- # FIXME: is it possible to deduce given/family from the full_name?
88
- #
89
- # FIXME: Each attribute can currently only have a single String value.
90
- #
91
- # FIXME: Need to escape specials in the String.
84
+ # Warning: This is the only mandatory field besides the full name, FN.
85
+ # FN: can be set in #make, or by #fullname=, and if not set will be
86
+ # constucted as the string "#{prefix} #{given} #{additional} #{family},
87
+ # #{suffix}".
92
88
  def add_name # :yield: n
89
+ # FIXME: Each attribute can currently only have a single String value.
90
+ # FIXME: Need to escape specials in the String.
93
91
  x = Struct.new(:family, :given, :additional, :prefix, :suffix).new
94
92
  yield x
95
93
  @card << Vpim::DirectoryInfo::Field.create(
@@ -101,8 +99,8 @@ module Vpim
101
99
 
102
100
  # Add a full name field, FN.
103
101
  #
104
- # Normally the FN field value is derived from the N: field value, but
105
- # it can be explicitly set.
102
+ # Normally the FN field value is derived from the N: field value, see
103
+ # #add_name, but it can be explicitly set.
106
104
  def fullname=(fullname)
107
105
  if @card.field('FN')
108
106
  raise Vpim::InvalidEncodingError, "Not allowed to add more than one FN field to a vCard."
@@ -130,9 +128,8 @@ module Vpim
130
128
  # strings.
131
129
  #
132
130
  # TODO - Add #label to support LABEL.
133
- #
134
- # FIXME - Need to escape specials in the String.
135
131
  def add_addr # :yield: adr
132
+ # FIXME - Need to escape specials in the String.
136
133
  x = Struct.new(
137
134
  :location, :preferred, :delivery,
138
135
  :pobox, :extended, :street, :locality, :region, :postalcode, :country
@@ -143,12 +140,12 @@ module Vpim
143
140
 
144
141
  # All these attributes go into the TYPE parameter.
145
142
  params = [ x[:location], x[:delivery] ]
146
- params << 'pref' if x[:preferred]
143
+ params << 'PREF' if x[:preferred]
147
144
  params = params.flatten.uniq.compact.map { |s| s.to_str }
148
145
 
149
146
  paramshash = {}
150
147
 
151
- paramshash['type'] = params if params.first
148
+ paramshash['TYPE'] = params if params.first
152
149
 
153
150
  @card << Vpim::DirectoryInfo::Field.create( 'ADR', values, paramshash)
154
151
  self
@@ -172,11 +169,11 @@ module Vpim
172
169
 
173
170
  yield x
174
171
 
175
- x[:preferred] = 'pref' if x[:preferred]
172
+ x[:preferred] = 'PREF' if x[:preferred]
176
173
 
177
174
  types = x.to_a.flatten.uniq.compact.map { |s| s.to_str }
178
175
 
179
- params['type'] = types if types.first
176
+ params['TYPE'] = types if types.first
180
177
  end
181
178
 
182
179
  @card << Vpim::DirectoryInfo::Field.create( 'TEL', number, params)
@@ -198,11 +195,11 @@ module Vpim
198
195
 
199
196
  yield x
200
197
 
201
- x[:preferred] = 'pref' if x[:preferred]
198
+ x[:preferred] = 'PREF' if x[:preferred]
202
199
 
203
200
  types = x.to_a.flatten.uniq.compact.map { |s| s.to_str }
204
201
 
205
- params['type'] = types if types.first
202
+ params['TYPE'] = types if types.first
206
203
  end
207
204
 
208
205
  @card << Vpim::DirectoryInfo::Field.create( 'EMAIL', email, params)
@@ -226,6 +223,7 @@ module Vpim
226
223
  end
227
224
  @card << Vpim::DirectoryInfo::Field.create( 'BDAY', birthday );
228
225
  end
226
+
229
227
  =begin
230
228
  TODO - need text=() implemented in Field
231
229
 
@@ -269,11 +267,11 @@ TODO - need text=() implemented in Field
269
267
 
270
268
  yield x
271
269
 
272
- x[:preferred] = 'pref' if x[:preferred]
270
+ x[:preferred] = 'PREF' if x[:preferred]
273
271
 
274
- types = x.to_a.flatten.uniq.compact.map { |s| s.to_str }
272
+ types = x.to_a.flatten.uniq.compact.map { |s| s.upcase }
275
273
 
276
- params['type'] = types if types.first
274
+ params['TYPE'] = types if types.first
277
275
  end
278
276
 
279
277
  @card << Vpim::DirectoryInfo::Field.create( 'IMPP', url, params)
@@ -299,11 +297,11 @@ TODO - need text=() implemented in Field
299
297
 
300
298
  yield x
301
299
 
302
- x[:preferred] = 'pref' if x[:preferred]
300
+ x[:preferred] = 'PREF' if x[:preferred]
303
301
 
304
- types = x.to_a.flatten.uniq.compact.map { |s| s.to_str }
302
+ types = x.to_a.flatten.uniq.compact.map { |s| s.upcase }
305
303
 
306
- params['type'] = types if types.first
304
+ params['TYPE'] = types if types.first
307
305
  end
308
306
 
309
307
  @card << Vpim::DirectoryInfo::Field.create( 'X-AIM', xaim, params)
@@ -346,12 +344,12 @@ TODO - need text=() implemented in Field
346
344
  params = {}
347
345
 
348
346
  # Don't set type to the empty string.
349
- params['type'] = x[:type] if( x[:type] && x[:type].length > 0 )
347
+ params['TYPE'] = x[:type] if( x[:type] && x[:type].length > 0 )
350
348
 
351
349
  if x[:link]
352
- params['value'] = 'uri'
350
+ params['VALUE'] = 'URI'
353
351
  else # it's inline, base-64 encode it
354
- params['encoding'] = :b64
352
+ params['ENCODING'] = :b64
355
353
  if !x[:type]
356
354
  raise Vpim::InvalidEncodingError, 'Inline image data must have it\'s type set.'
357
355
  end
@@ -361,6 +359,11 @@ TODO - need text=() implemented in Field
361
359
  self
362
360
  end
363
361
 
362
+ # Add a URL field, URL:.
363
+ def add_url(url)
364
+ @card << Vpim::DirectoryInfo::Field.create( 'URL', url.to_str );
365
+ end
366
+
364
367
  # Add a Field, +field+.
365
368
  def add_field(field)
366
369
  fieldname = field.name.upcase
@@ -0,0 +1,63 @@
1
+ module Vpim
2
+ class Icalendar
3
+ module Property #:nodoc:
4
+
5
+ # FIXME - these should be part of Dirinfo
6
+ module Base
7
+ # Value of first property with name +name+
8
+ def propvalue(name) #:nodoc:
9
+ prop = @properties.detect { |f| f.name? name }
10
+ if prop
11
+ prop = prop.value
12
+ end
13
+ prop
14
+ end
15
+
16
+ def proptoken(name, allowed, default_token = nil) #:nodoc:
17
+ prop = propvalue name
18
+
19
+ if prop
20
+ prop = prop.to_str.upcase
21
+ unless allowed.include?(prop)
22
+ raise Vpim::InvalidEncodingError, "Invalid #{name} value '#{prop}'"
23
+ end
24
+ else
25
+ prop = default_token
26
+ end
27
+
28
+ prop
29
+ end
30
+
31
+ # Value as DATE-TIME or DATE of object of first property with name +name+
32
+ def proptime(name) #:nodoc:
33
+ prop = @properties.detect { |f| f.name? name }
34
+ if prop
35
+ prop = prop.to_time.first
36
+ end
37
+ prop
38
+ end
39
+
40
+ # Value as TEXT of first property with name +name+
41
+ def proptext(name) #:nodoc:
42
+ prop = @properties.detect { |f| f.name? name }
43
+ if prop
44
+ prop = prop.to_text
45
+ end
46
+ prop
47
+ end
48
+
49
+ # Array of values as TEXT of all properties with name +name+
50
+ def proptextarray(name) #:nodoc:
51
+ @properties.select{ |f| f.name? name }.map{ |p| p.to_text }
52
+ end
53
+
54
+ # Array of values as TEXT list of all properties with name +name+
55
+ def proptextlistarray(name) #:nodoc:
56
+ @properties.select{ |f| f.name? name }.map{ |p| Vpim.decode_text_list(p.value_raw) }.flatten
57
+ end
58
+
59
+ end
60
+ end
61
+ end
62
+ end
63
+