Parent

Vpim::DirectoryInfo::Field

A field in a directory info object.

Public Class Methods

create(name, value="", params={}) click to toggle source

Create a field with name name (a String), value value (see below), and optional parameters, params. params is a hash of the parameter name (a String) to either a single string or symbol, or an array of strings and symbols (parameters can be multi-valued).

If ‘ENCODING’ => :b64 is specified as a parameter, the value will be base-64 encoded. If it’s already base-64 encoded, then use String values (‘ENCODING’ => ‘B’), and no further encoding will be done by this routine.

Currently handled value types are:

  • Time, encoded as a date-time value

  • Date, encoded as a date value

  • String, encoded directly

  • Array of String, concatentated with ‘;’ between them.

TODO - need a way to encode String values as TEXT, at least optionally, so as to escape special chars, etc.

# File lib/vpim/field.rb, line 209
def Field.create(name, value="", params={})
  line = Field.encode0(nil, name, params, value)

  begin
    new(line)
  rescue Vpim::InvalidEncodingError => e
    raise ArgumentError, e.to_s
  end
end
create_array(fields) click to toggle source

TODO

  • Field should know which param values and field values are case-insensitive, configurably, so it can down case them

  • perhaps should have pvalue_set/del/add, perhaps case-insensitive, or pvalue_iset/idel/iadd, where set sets them all, add adds if not present, and del deletes any that are present

  • I really, really, need a case-insensitive string…

  • should allow nil as a field value, its not the same as ”, if there is more than one pvalue, the empty string will show up. This isn’t strictly disallowed, but its odd. Should also strip empty strings on decoding, if I don’t already.

# File lib/vpim/field.rb, line 33
def Field.create_array(fields)
  case fields
    when Hash
      fields.map do |name,value|
        DirectoryInfo::Field.create( name, value )
      end
    else
      fields.to_ary
  end
end
decode(line) click to toggle source

Create a field by decoding line, a String which must already be unfolded. Decoded fields are frozen, but see copy().

# File lib/vpim/field.rb, line 187
def Field.decode(line)
  new(line).freeze
end

Public Instance Methods

[](name) click to toggle source
Alias for: pvalues
[]=(pname,pvalue) click to toggle source

Set a the param pname‘s value to pvalue, replacing any value it currently has. See Field.create() for a description of pvalue.

Example:

if field['TYPE']
  field['TYPE'] << 'HOME'
else
  field['TYPE'] = [ 'HOME' ]
end

TODO - this could be an alias to pvalue_set

# File lib/vpim/field.rb, line 531
def []=(pname,pvalue)
  unless pvalue.respond_to?(:to_ary)
    pvalue = [ pvalue ]
  end

  h = @params.dup

  h[pname.upcase] = pvalue

  mutate(@group, @name, h, @value)
  pvalue
end
copy() click to toggle source

Create a copy of Field. If the original Field was frozen, this one won’t be.

# File lib/vpim/field.rb, line 221
def copy
  Marshal.load(Marshal.dump(self))
end
each_param() click to toggle source

Yield once for each param, name is the parameter name, value is an array of the parameter values.

# File lib/vpim/field.rb, line 294
def each_param(&block) #:yield: name, value
  if @params
    @params.each(&block)
  end
end
encode(width=nil) click to toggle source

The String encoding of the Field. The String will be wrapped to a maximum line width of width, where 0 means no wrapping, and nil is to accept the default wrapping (75, recommended by RFC2425).

Note: AddressBook.app 3.0.3 neither understands to unwrap lines when it imports vCards (it treats them as raw new-line characters), nor wraps long lines on export. This is mostly a cosmetic problem, but wrapping can be disabled by setting width to 0, if desired.

FIXME - breaks round-trip encoding, need to change this to not wrap fields that are already wrapped.

# File lib/vpim/field.rb, line 236
def encode(width=nil)
  width = 75 unless width
  l = @line
  # Wrap to width, unless width is zero.
  if width > 0
    l = l.gsub(/.{#{width},#{width}}/) { |m| m + "\n " }
  end
  # Make sure it's terminated with no more than a single NL.
  l.gsub(/\s*\z/, '') + "\n"
end
Also aliased as: to_s
encoding() click to toggle source

The value of the ENCODING parameter, if present, or nil if not present.

# File lib/vpim/field.rb, line 399
def encoding
  e = param('ENCODING')

  if e
    if e.length > 1
      raise Vpim::InvalidEncodingError, "multi-valued param 'ENCODING' (#{e})"
    end
    e = e.first.upcase
  end
  e
end
group() click to toggle source

The group, if present, or nil if not present.

# File lib/vpim/field.rb, line 255
def group
  @group
end
group=(group) click to toggle source

Set the group of this field to group.

# File lib/vpim/field.rb, line 502
def group=(group)
  mutate(group, @name, @params, @value)
  group
end
group?(group) click to toggle source

Is the group of this field group? Group names are case insensitive. A group of nil matches if the field has no group.

# File lib/vpim/field.rb, line 335
def group?(group)
  Vpim::Methods.casecmp?(@group, group)
end
kind() click to toggle source

The type of the value, as specified by the VALUE parameter, nil if unspecified.

# File lib/vpim/field.rb, line 413
def kind
  v = param('VALUE')
  if v
    if v.size > 1
      raise InvalidEncodingError, "multi-valued param 'VALUE' (#{values})"
    end
    v = v.first.downcase
  end
  v
end
kind?(kind) click to toggle source

Is the value of this field of type kind? RFC2425 allows the type of a fields value to be encoded in the VALUE parameter. Don’t rely on its presence, they aren’t required, and usually aren’t bothered with. In cases where the kind of value might vary (an iCalendar DTSTART can be either a date or a date-time, for example), you are more likely to see the kind of value specified explicitly.

The value types defined by RFC 2425 are:

  • uri:

  • text:

  • date: a list of 1 or more dates

  • time: a list of 1 or more times

  • date-time: a list of 1 or more date-times

  • integer:

  • boolean:

  • float:

# File lib/vpim/field.rb, line 355
def kind?(kind)
  Vpim::Methods.casecmp?(self.kind == kind)
end
name() click to toggle source

The name.

# File lib/vpim/field.rb, line 250
def name
  @name
end
name?(name) click to toggle source

Is the name of this Field name? Names are case insensitive.

# File lib/vpim/field.rb, line 329
def name?(name)
  Vpim::Methods.casecmp?(@name, name)
end
param(name) click to toggle source

FIXME - remove my own uses of param

Alias for: pvalues
params() click to toggle source

FIXME - remove my own uses of params

Alias for: pnames
pnames() click to toggle source

An Array of all the param names.

# File lib/vpim/field.rb, line 260
def pnames
  @params.keys
end
Also aliased as: params
pref=(ispref) click to toggle source

Set whether a field is marked as preferred. See pref?

# File lib/vpim/field.rb, line 383
def pref=(ispref)
  if ispref
    pvalue_iadd('TYPE', 'PREF')
  else
    pvalue_idel('TYPE', 'PREF')
  end
end
pref?() click to toggle source

Is this field marked as preferred? A vCard field is preferred if type?(‘PREF’). This method is not necessarily meaningful for non-vCard profiles.

# File lib/vpim/field.rb, line 378
def pref?
  type? 'PREF'
end
pvalue(name) click to toggle source

The first value of the param name, nil if there is no such param, the param has no value, or the first param value is zero-length.

# File lib/vpim/field.rb, line 269
def pvalue(name)
  v = pvalues( name )
  if v
    v = v.first
  end
  if v
    v = nil unless v.length > 0
  end
  v
end
pvalue_iadd(pname, pvalue) click to toggle source

Add pvalue to the param pname‘s value. The values are treated as a set so duplicate values won’t occur, and String values are case insensitive. See Field.create() for a description of pvalue.

# File lib/vpim/field.rb, line 547
def pvalue_iadd(pname, pvalue)
  pname = pname.upcase

  # Get a uniq set, where strings are compared case-insensitively.
  values = [ pvalue, @params[pname] ].flatten.compact
  values = values.collect do |v|
    if v.respond_to? :to_str
      v = v.to_str.upcase
    end
    v
  end
  values.uniq!

  h = @params.dup

  h[pname] = values

  mutate(@group, @name, h, @value)
  values
end
pvalue_idel(pname, pvalue) click to toggle source

Delete pvalue from the param pname‘s value. The values are treated as a set so duplicate values won’t occur, and String values are case insensitive. pvalue must be a single String or Symbol.

# File lib/vpim/field.rb, line 571
def pvalue_idel(pname, pvalue)
  pname = pname.upcase
  if pvalue.respond_to? :to_str
    pvalue = pvalue.to_str.downcase
  end

  # Get a uniq set, where strings are compared case-insensitively.
  values = [ nil, @params[pname] ].flatten.compact
  values = values.collect do |v|
    if v.respond_to? :to_str
      v = v.to_str.downcase
    end
    v
  end
  values.uniq!
  values.delete pvalue

  h = @params.dup

  h[pname] = values

  mutate(@group, @name, h, @value)
  values
end
pvalues(name) click to toggle source

The Array of all values of the param name, nil if there is no such param, [] if the param has no values. If the Field isn’t frozen, the Array is mutable.

# File lib/vpim/field.rb, line 283
def pvalues(name)
  @params[name.upcase]
end
Also aliased as: param, []
text=(text) click to toggle source

Convert value to text, then assign.

TODO - unimplemented

# File lib/vpim/field.rb, line 517
def text=(text)
end
to_date() click to toggle source

The value as an array of Date objects (all times and dates in RFC2425 are lists, even where it might not make sense, such as a birthday).

The field value may be a list of either DATE or DATE-TIME values, decoding is tried first as a DATE-TIME, then as a DATE, if neither works an InvalidEncodingError will be raised.

# File lib/vpim/field.rb, line 469
def to_date
  begin
    Vpim.decode_date_time_list(value).collect do |d|
      # We get [ year, month, day, hour, min, sec, usec, tz ]
      Date.new(d[0], d[1], d[2])
    end
  rescue Vpim::InvalidEncodingError
    Vpim.decode_date_list(value).collect do |d|
      # We get [ year, month, day ]
      Date.new(*d)
    end
  end
end
to_s(width=nil) click to toggle source
Alias for: encode
to_text() click to toggle source

The value as text. Text can have escaped newlines, commas, and escape characters, this method will strip them, if present.

In theory, value could also do this, but it would need to know that the value is of type ‘TEXT’, and often for text values the ‘VALUE’ parameter is not present, so knowledge of the expected type of the field is required from the decoder.

# File lib/vpim/field.rb, line 490
def to_text
  Vpim.decode_text(value)
end
to_time() click to toggle source

The value as an array of Time objects (all times and dates in RFC2425 are lists, even where it might not make sense, such as a birthday). The time will be UTC if marked as so (with a timezone of “Z”), and in localtime otherwise.

TODO - support timezone offsets

TODO - if year is before 1970, this won’t work… but some people are generating calendars saying Canada Day started in 1753! That’s just wrong! So, what to do? I add a message saying what the year is that breaks, so they at least know that its ridiculous! I think I need my own DateTime variant.

# File lib/vpim/field.rb, line 436
def to_time
  begin
    Vpim.decode_date_time_list(value).collect do |d|
      # We get [ year, month, day, hour, min, sec, usec, tz ]
      begin
        if(d.pop == "Z")
          Time.gm(*d)
        else
          Time.local(*d)
        end
      rescue ArgumentError => e
        raise Vpim::InvalidEncodingError, "Time.gm(#{d.join(', ')}) failed with #{e.message}"
      end
    end
  rescue Vpim::InvalidEncodingError
    Vpim.decode_date_list(value).collect do |d|
      # We get [ year, month, day ]
      begin
        Time.gm(*d)
      rescue ArgumentError => e
        raise Vpim::InvalidEncodingError, "Time.gm(#{d.join(', ')}) failed with #{e.message}"
      end
    end
  end
end
type?(type) click to toggle source

Is one of the values of the TYPE parameter of this field type? The type parameter values are case insensitive. False if there is no TYPE parameter.

TYPE parameters are used for general categories, such as distinguishing between an email address used at home or at work.

# File lib/vpim/field.rb, line 365
def type?(type)
  type = type.to_str

  types = param('TYPE')

  if types
    types = types.detect { |t| Vpim::Methods.casecmp?(t, type) }
  end
end
value() click to toggle source

The decoded value.

The encoding specified by the encoding, if any, is stripped.

Note: Both the RFC 2425 encoding param (“b”, meaning base-64) and the vCard 2.1 encoding params (“base64”, “quoted-printable”, “8bit”, and “7bit”) are supported.

FIXME:

  • should use the VALUE parameter

  • should also take a default value type, so it can be converted if VALUE parameter is not present.

# File lib/vpim/field.rb, line 312
def value
  case encoding
    when nil, '8BIT', '7BIT' then @value

    # Hack - if the base64 lines started with 2 SPC chars, which is invalid,
    # there will be extra spaces in @value. Since no SPC chars show up in
    # b64 encodings, they can be safely stripped out before unpacking.
    when 'B', 'BASE64'       then @value.gsub(' ', '').unpack('m*').first

    when 'QUOTED-PRINTABLE'  then @value.unpack('M*').first

    else
      raise Vpim::InvalidEncodingError, "unrecognized encoding (#{encoding})"
  end
end
value=(value) click to toggle source

Set the value of this field to value. Valid values are as in Field.create().

# File lib/vpim/field.rb, line 509
def value=(value)
  mutate(@group, @name, @params, value)
  value
end
value?(value) click to toggle source

Is the value of this field value? The check is case insensitive. FIXME - it shouldn’t be insensitive, make a casevalue? method.

# File lib/vpim/field.rb, line 393
def value?(value)
   Vpim::Methods.casecmp?(@value, value.to_str)
end
value_raw() click to toggle source

The undecoded value, see value.

# File lib/vpim/field.rb, line 495
def value_raw
  @value
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.