Vpim::Vcard

A vCard, a specialization of a directory info object.

The vCard format is specified by:

This implements vCard 3.0, but it is also capable of working with vCard 2.1 if used with care.

All line values can be accessed with Vcard#value, Vcard#values, or even by iterating through Vcard#lines. Line types that don't have specific support and non-standard line types ("X-MY-SPECIAL", for example) will be returned as a String, with any base64 or quoted-printable encoding removed.

Specific support exists to return more useful values for the standard vCard types, where appropriate.

The wrapper functions (birthday, nicknames, emails, etc.) exist partially as an API convenience, and partially as a place to document the values returned for the more complex types, like PHOTO and EMAIL.

For types that do not sensibly occur multiple times (like BDAY or GEO), sometimes a wrapper exists only to return a single line, using value. However, if you find the need, you can still call values to get all the lines, and both the singular and plural forms will eventually be implemented.

If there is sufficient demand, specific support for vCard 2.1 could be implemented.

For more information see:

vCards are usually transmitted in files with .vcf extensions.

Examples

Public Class Methods

create(fields = [] ) click to toggle source

Create a vCard 3.0 object with the minimum required fields, plus any fields you want in the card (they can also be added later).

# File lib/vpim/vcard.rb, line 635
def Vcard.create(fields = [] )
  fields.unshift Field.create('VERSION', "3.0")
  super(fields, 'VCARD')
end
decode(card) click to toggle source

Decode a collection of vCards into an array of Vcard objects.

card can be either a String or an IO object.

Since vCards are self-delimited (by a BEGIN:vCard and an END:vCard), multiple vCards can be concatenated into a single directory info object. They may or may not be related. For example, AddressBook.app (the OS X contact manager) will export multiple selected cards in this format.

Input data will be converted from unicode if it is detected. The heuristic is based on the first bytes in the string:

  • 0xEF 0xBB 0xBF: UTF-8 with a BOM, the BOM is stripped

  • 0xFE 0xFF: UTF-16 with a BOM (big-endian), the BOM is stripped and string is converted to UTF-8

  • 0xFF 0xFE: UTF-16 with a BOM (little-endian), the BOM is stripped and string is converted to UTF-8

  • 0x00 'B' or 0x00 'b': UTF-16 (big-endian), the string is converted to UTF-8

  • 'B' 0x00 or 'b' 0x00: UTF-16 (little-endian), the string is converted to UTF-8

If you know that you have only one vCard, then you can decode that single vCard by doing something like:

vcard = Vcard.decode(card_data).first

Note: Should the import encoding be remembered, so that it can be reencoded in the same format?

# File lib/vpim/vcard.rb, line 666
def Vcard.decode(card)
  if card.respond_to? :to_str
    string = card.to_str
  elsif card.respond_to? :read
    string = card.read(nil)
  else
    raise ArgumentError, "Vcard.decode cannot be called with a #{card.type}"
  end

  case string
    when /^\xEF\xBB\xBF/
      string = string.sub("\xEF\xBB\xBF", '')
    when /^\xFE\xFF/
      arr = string.unpack('n*')
      arr.shift
      string = arr.pack('U*')
    when /^\xFF\xFE/
      arr = string.unpack('v*')
      arr.shift
      string = arr.pack('U*')
    when /^\x00B/
      string = string.unpack('n*').pack('U*')
    when /^B\x00/
      string = string.unpack('v*').pack('U*')
  end

  entities = Vpim.expand(Vpim.decode(string))

  # Since all vCards must have a begin/end, the top-level should consist
  # entirely of entities/arrays, even if its a single vCard.
  if entities.detect { |e| ! e.kind_of? Array }
    raise "Not a valid vCard"
  end

  vcards = []

  for e in entities
    vcards.push(new(e.flatten, 'VCARD'))
  end

  vcards
end

Public Instance Methods

[](name, type=nil) click to toggle source

The value of the field named name, optionally limited to fields of type type. If no match is found, nil is returned, if multiple matches are found, the first match to have one of its type values be 'PREF' (preferred) is returned, otherwise the first match is returned.

FIXME - this will become an alias for value.

# File lib/vpim/vcard.rb, line 715
def [](name, type=nil)
  fields = enum_by_name(name).find_all { |f| type == nil || f.type?(type) }

  valued = fields.select { |f| f.value != '' }
  if valued.first
    fields = valued
  end

  # limit to preferred, if possible
  pref = fields.select { |f| f.pref? }

  if pref.first
    fields = pref
  end

  fields.first ? fields.first.value : nil
end
address(type=nil) click to toggle source

The first ADR value of type type, a Address. Any of the location or delivery attributes of Address can be used as type. A wrapper around value('ADR', type).

# File lib/vpim/vcard.rb, line 802
def address(type=nil)
  value('ADR', type)
end
addresses() click to toggle source

The ADR values, an array of Address. If a block is given, the values are yielded. A wrapper around values('ADR').

# File lib/vpim/vcard.rb, line 808
def addresses #:yield:address
  values('ADR')
end
agents() click to toggle source

The AGENT values. Each AGENT value is either a String, a Uri, or a Vcard. If a block is given, the values are yielded. A wrapper around values('AGENT').

# File lib/vpim/vcard.rb, line 815
def agents #:yield:agent
  values('AGENT')
end
birthday() click to toggle source

The BDAY value as either a Date or a DateTime, or nil if there is none.

If the BDAY value is invalidly formatted, a feeble heuristic is applied to find the month and year, and return a Date in the current year.

# File lib/vpim/vcard.rb, line 823
def birthday
  value('BDAY')
end
categories() click to toggle source

The CATEGORIES values, an array of String. A wrapper around value('CATEGORIES').

# File lib/vpim/vcard.rb, line 829
def categories
  value('CATEGORIES')
end
email(type=nil) click to toggle source

The first EMAIL value of type type, a Email. Any of the location attributes of Email can be used as type. A wrapper around value('EMAIL', type).

# File lib/vpim/vcard.rb, line 836
def email(type=nil)
  value('EMAIL', type)
end
emails() click to toggle source

The EMAIL values, an array of Email. If a block is given, the values are yielded. A wrapper around values('EMAIL').

# File lib/vpim/vcard.rb, line 842
def emails #:yield:email
  values('EMAIL')
end
geo() click to toggle source

The GEO value, an Array of two Floats, +[ latitude, longitude]+. North of the equator is positive latitude, east of the meridian is positive longitude. See RFC2445 for more info, there are lots of special cases and RFC2445's description is more complete thant RFC2426.

# File lib/vpim/vcard.rb, line 850
def geo
  value('GEO')
end
keys() click to toggle source

Return an Array of KEY Line#value, or yield each Line#value if a block is given. A wrapper around values('KEY').

KEY is a public key or authentication certificate associated with the object that the vCard represents. It is not commonly used, but could contain a X.509 or PGP certificate.

See Attachment for a description of the value.

# File lib/vpim/vcard.rb, line 862
def keys(&proc) #:yield: Line.value
  values('KEY', &proc)
end
lines(name=nil) click to toggle source

With no block, returns an Array of Line. If name is specified, the Array will only contain the +Line+s with that name. The Array may be empty.

If a block is given, each Line will be yielded instead of being returned in an Array.

# File lib/vpim/vcard.rb, line 602
def lines(name=nil) #:yield: Line
  # FIXME - this would be much easier if #lines was #each, and there was a
  # different #lines that returned an Enumerator that used #each
  unless block_given?
    map do |f|
      if( !name || f.name?(name) )
       f2l(f)
      else
        nil
      end
    end.compact
  else
    each do |f|
      if( !name || f.name?(name) )
        line = f2l(f)
        if line
          yield line
        end
      end
    end
    self
  end
end
logos() click to toggle source

Return an Array of LOGO Line#value, or yield each Line#value if a block is given. A wrapper around values('LOGO').

LOGO is a graphic image of a logo associated with the object the vCard represents. Its not common, but would probably be equivalent to the logo on a printed card.

See Attachment for a description of the value.

# File lib/vpim/vcard.rb, line 874
def logos(&proc) #:yield: Line.value
  values('LOGO', &proc)
end
make() click to toggle source

Make changes to a vCard.

Yields a Vpim::Vcard::Maker that can be used to modify this vCard.

# File lib/vpim/vcard.rb, line 997
def make #:yield: maker
  Vpim::Vcard::Maker.make2(self) do |maker|
    yield maker
  end
end
name() click to toggle source

The N and FN as a Name object.

N is required for a vCards, this raises InvalidEncodingError if there is no N so it cannot return nil.

# File lib/vpim/vcard.rb, line 884
def name
  value('N') || raise(Vpim::InvalidEncodingError, "Missing mandatory N field")
end
nickname() click to toggle source

The first NICKNAME value, nil if there are none.

# File lib/vpim/vcard.rb, line 889
def nickname
  v = value('NICKNAME')
  v = v.first if v
  v
end
nicknames() click to toggle source

The NICKNAME values, an array of String. The array may be empty.

# File lib/vpim/vcard.rb, line 896
def nicknames
  values('NICKNAME').flatten.uniq
end
note() click to toggle source

The NOTE value, a String. A wrapper around value('NOTE').

# File lib/vpim/vcard.rb, line 901
def note
  value('NOTE')
end
org() click to toggle source

The ORG value, an Array of String. The first string is the organization, subsequent strings are departments within the organization. A wrapper around value('ORG').

# File lib/vpim/vcard.rb, line 908
def org
  value('ORG')
end
photos() click to toggle source

Return an Array of PHOTO Line#value, or yield each Line#value if a block is given. A wrapper around values('PHOTO').

PHOTO is an image or photograph information that annotates some aspect of the object the vCard represents. Commonly there is one PHOTO, and it is a photo of the person identified by the vCard.

See Attachment for a description of the value.

# File lib/vpim/vcard.rb, line 920
def photos(&proc) #:yield: Line.value
  values('PHOTO', &proc)
end
sounds() click to toggle source

Return an Array of SOUND Line#value, or yield each Line#value if a block is given. A wrapper around values('SOUND').

SOUND is digital sound content information that annotates some aspect of the vCard. By default this type is used to specify the proper pronunciation of the name associated with the vCard. It is not commonly used. Also, note that there is no mechanism available to specify that the SOUND is being used for anything other than the default.

See Attachment for a description of the value.

# File lib/vpim/vcard.rb, line 942
def sounds(&proc) #:yield: Line.value
  values('SOUND', &proc)
end
telephone(type=nil) click to toggle source

The first TEL value of type type, a Telephone. Any of the location or capability attributes of Telephone can be used as type. A wrapper around value('TEL', type).

# File lib/vpim/vcard.rb, line 951
def telephone(type=nil)
  value('TEL', type)
end
telephones() click to toggle source

The TEL values, an array of Telephone. If a block is given, the values are yielded. A wrapper around values('TEL').

# File lib/vpim/vcard.rb, line 957
def telephones #:yield:tel
  values('TEL')
end
title() click to toggle source

The TITLE value, a text string specifying the job title, functional position, or function of the object the card represents. A wrapper around value('TITLE').

# File lib/vpim/vcard.rb, line 964
def title
  value('TITLE')
end
url() click to toggle source

The URL value, a Attachment::Uri. A wrapper around value('URL').

# File lib/vpim/vcard.rb, line 971
def url
  value('URL')
end
urls() click to toggle source

The URL values, an Attachment::Uri. A wrapper around values('URL').

# File lib/vpim/vcard.rb, line 976
def urls
  values('URL')
end
value(name, type = nil) click to toggle source

Return the Line#value for a specific name, and optionally for a specific type.

If no line with the name (and, optionally, type) exists, nil is returned.

If multiple lines exist, the order of preference is:

  • lines with values over lines without

  • lines with a type of 'pref' over lines without

If multiple lines are equally preferred, then the first line will be returned.

This is most useful when looking for a line that can not occur multiple times, or when the line can occur multiple times, and you want to pick the first preferred line of a specific type. See values if you need to access all the lines.

Note that the type field parameter is used for different purposes by the various kinds of vCard lines, but for the addressing lines (ADR, LABEL, TEL, EMAIL) it is has a reasonably consistent usage. Each addressing line can occur multiple times, and a type of 'pref' indicates that a particular line is the preferred line. Other type values tend to indicate some information about the location ('home', 'work', ...) or some detail about the address ('cell', 'fax', 'voice', ...). See the methods for the specific types of line for information about supported types and their meaning.

# File lib/vpim/vcard.rb, line 759
def value(name, type = nil)
  v = nil

  fields = enum_by_name(name).find_all { |f| type == nil || f.type?(type) }

  valued = fields.select { |f| f.value != '' }
  if valued.first
    fields = valued
  end

  pref = fields.select { |f| f.pref? }

  if pref.first
    fields = pref
  end

  if fields.first
    line = begin
             Line.decode(@@decode, self, fields.first)
           rescue Vpim::InvalidEncodingError
           end

    if line
      return line.value
    end
  end

  nil
end
values(name) click to toggle source

A variant of lines that only iterates over specific Line names. Since the name is known, only the Line#value is returned or yielded.

# File lib/vpim/vcard.rb, line 791
def values(name)
  unless block_given?
    lines(name).map { |line| line.value }
  else
    lines(name) { |line| yield line.value }
  end
end
version() click to toggle source

The VERSION multiplied by 10 as an Integer. For example, a VERSION:2.1 vCard would have a version of 21, and a VERSION:3.0 vCard would have a version of 30.

VERSION is required for a vCard, this raises InvalidEncodingError if there is no VERSION so it cannot return nil.

# File lib/vpim/vcard.rb, line 986
def version
  v = value('VERSION')
  unless v
    raise Vpim::InvalidEncodingError, 'Invalid vCard - it has no version field!'
  end
  v
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.