Class: Vcard::DirectoryInfo

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/vcard/dirinfo.rb,
lib/vcard/field.rb

Overview

An RFC 2425 directory info object.

A directory information object is a sequence of fields. The basic structure of the object, and the way in which it is broken into fields is common to all profiles of the directory info type.

A vCard, for example, is a specialization of a directory info object.

Here’s an example of encoding a simple vCard using the low-level APIs:

card = Vcard::Vcard.create
card << Vcard::DirectoryInfo::Field.create("EMAIL", "[email protected]", "TYPE" => "INTERNET" )
card << Vcard::DirectoryInfo::Field.create("URL", "http://www.example.com/user" )
card << Vcard::DirectoryInfo::Field.create("FN", "User Name" )
puts card.to_s

Don’t do it like that, use Vcard::Vcard::Maker.

Direct Known Subclasses

Vcard

Defined Under Namespace

Classes: Field

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(fields, profile = nil) ⇒ DirectoryInfo

Initialize a DirectoryInfo object from fields. If profile is specified, check the BEGIN/END fields.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/vcard/dirinfo.rb', line 33

def initialize(fields, profile = nil) #:nodoc:
  @valid = true
  @fields = []

  fields.each do |f|
    raise ArgumentError, "fields must be an array of DirectoryInfo::Field objects" unless f.kind_of? DirectoryInfo::Field
    if f.valid?
      @fields << f
    else
      @valid = false
    end
  end

  @string = nil # this is used as a flag to indicate that recoding will be necessary

  check_begin_end(profile) if profile
end

Class Method Details

.create(fields = [], profile = nil) ⇒ Object

Create a new DirectoryInfo object. The fields are an optional array of DirectoryInfo::Field objects to add to the new object, between the BEGIN/END. If the profile string is not nil, then it is the name of the directory info profile, and the BEGIN:profile/END:profile fields will be added.

A DirectoryInfo is mutable, you can add new fields to it using #push(), and see Field#create().



91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/vcard/dirinfo.rb', line 91

def DirectoryInfo.create(fields = [], profile = nil)

  if profile
    p = profile.to_str
    f = [ Field.create("BEGIN", p) ]
    f.concat fields
    f.push Field.create("END", p)
    fields = f
  end

  new(fields, profile)
end

.decode(card) ⇒ Object

Decode card into a DirectoryInfo object.

card may either be a something that is convertible to a string using #to_str or an Array of objects that can be joined into a string using #join(“n”), or an IO object (which will be read to end-of-file).

The lines in the string may be delimited using IETF (CRLF) or Unix (LF) conventions.

A DirectoryInfo is mutable, you can add new fields to it, see Vcard::DirectoryInfo::Field#create() for how to create a new Field.

TODO: I don’t believe this is ever used, maybe I can remove it.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/vcard/dirinfo.rb', line 67

def DirectoryInfo.decode(card) #:nodoc:
  if card.respond_to? :to_str
    string = card.to_str
  elsif card.kind_of? Array
    string = card.join("\n")
  elsif card.kind_of? IO
    string = card.read(nil)
  else
    raise ArgumentError, "DirectoryInfo cannot be created from a #{card.type}"
  end

  fields = ::Vcard.decode(string)

  new(fields)
end

Instance Method Details

#[](name) ⇒ Object

The value of the first field named name, or nil if no match is found.



113
114
115
116
117
# File 'lib/vcard/dirinfo.rb', line 113

def [](name)
  enum_by_name(name).each { |f| return f.value if f.value != ""}
  enum_by_name(name).each { |f| return f.value }
  nil
end

#check_begin_end(profile = nil) ⇒ Object

Check that the DirectoryInfo object is correctly delimited by a BEGIN and END, that their profile values match, and if profile is specified, that they are the specified profile.



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/vcard/dirinfo.rb', line 258

def check_begin_end(profile=nil) #:nodoc:
  unless @fields.first
    raise "No fields to check"
  end
  unless @fields.first.name? "BEGIN"
    raise "Needs BEGIN, found: #{@fields.first.encode nil}"
  end
  unless @fields.last.name? "END"
    raise "Needs END, found: #{@fields.last.encode nil}"
  end
  unless @fields.last.value? @fields.first.value
    raise "BEGIN/END mismatch: (#{@fields.first.value} != #{@fields.last.value}"
  end
  if profile
    if ! @fields.first.value? profile
      raise "Mismatched profile"
    end
  end
  true
end

#delete(field) ⇒ Object

Delete field.

Warning: You can’t delete BEGIN: or END: fields, but other profile-specific fields can be deleted, including mandatory ones. For vCards in particular, in order to avoid destroying them, I suggest creating a new Vcard, and copying over all the fields that you still want, rather than using #delete. This is easy with Vcard::Maker#copy, see the Vcard::Maker examples.



233
234
235
236
237
238
239
240
241
242
# File 'lib/vcard/dirinfo.rb', line 233

def delete(field)
  case
  when field.name?("BEGIN"), field.name?("END")
    raise ArgumentError, "Cannot delete BEGIN or END fields."
  else
    @fields.delete field
  end

  self
end

#dirtyObject

Force card to be reencoded from the fields.



196
197
198
# File 'lib/vcard/dirinfo.rb', line 196

def dirty #:nodoc:
  #string = nil
end

#each(cond = nil) ⇒ Object

Yields for each Field for which cond.call(field) is true. The (default) cond of nil is considered true for all fields, so this acts like a normal #each() when called with no arguments.



146
147
148
149
150
151
152
153
# File 'lib/vcard/dirinfo.rb', line 146

def each(cond = nil) # :yields: Field
  @fields.each do |field|
     if(cond == nil || cond.call(field))
       yield field
     end
  end
  self
end

#encode(width = nil) ⇒ Object Also known as: to_s

The string encoding of the DirectoryInfo. See Field#encode for information about the width parameter.



246
247
248
249
250
251
# File 'lib/vcard/dirinfo.rb', line 246

def encode(width=nil)
  unless @string
    @string = @fields.collect { |f| f.encode(width) } . join ""
  end
  @string
end

#enum_by_cond(cond) ⇒ Object

Returns an Enumerator for each Field for which cond.call(field) is true.



191
192
193
# File 'lib/vcard/dirinfo.rb', line 191

def enum_by_cond(cond)
  Enumerator.new(self, cond )
end

#enum_by_group(group) ⇒ Object

Returns an Enumerator for each Field for which #group?(group) is true.

For example, to print all the fields, sorted by group, you could do:

card.groups.sort.each do |group|
  card.enum_by_group(group).each do |field|
    puts "#{group} -> #{field.name}"
  end
end

or to get an array of all the fields in group “AGROUP”, you could do:

card.enum_by_group("AGROUP").to_a


186
187
188
# File 'lib/vcard/dirinfo.rb', line 186

def enum_by_group(group)
  Enumerator.new(self, Proc.new { |field| field.group?(group) })
end

#enum_by_name(name) ⇒ Object

Returns an Enumerator for each Field for which #name?(name) is true.

An Enumerator supports all the methods of Enumerable, so it allows iteration, collection, mapping, etc.

Examples:

Print all the nicknames in a card:

card.enum_by_name("NICKNAME") { |f| puts f.value }

Print an Array of the preferred email addresses in the card:

pref_emails = card.enum_by_name("EMAIL").select { |f| f.pref? }


169
170
171
# File 'lib/vcard/dirinfo.rb', line 169

def enum_by_name(name)
  Enumerator.new(self, Proc.new { |field| field.name?(name) })
end

#field(name) ⇒ Object

The first field named name, or nil if no match is found.



106
107
108
109
# File 'lib/vcard/dirinfo.rb', line 106

def field(name)
  enum_by_name(name).each { |f| return f }
  nil
end

#fieldsObject

All fields, frozen.



139
140
141
# File 'lib/vcard/dirinfo.rb', line 139

def fields #:nodoc:
  @fields.dup.freeze
end

#groupsObject

Array of all the Field#group()s.



134
135
136
# File 'lib/vcard/dirinfo.rb', line 134

def groups
  @fields.collect { |f| f.group } .compact.uniq
end

#push(field) ⇒ Object Also known as: <<

Append field to the fields. Note that it won’t be literally appended to the fields, it will be inserted before the closing END field.



202
203
204
205
206
# File 'lib/vcard/dirinfo.rb', line 202

def push(field)
  dirty
  @fields[-1,0] = field
  self
end

#push_end(field) ⇒ Object

Append field to the end of all the fields. This isn’t usually what you want to do, usually a DirectoryInfo’s first and last fields are a BEGIN/END pair, see #push().



220
221
222
223
# File 'lib/vcard/dirinfo.rb', line 220

def push_end(field)
  @fields << field
  self
end

#push_unique(field) ⇒ Object

Push field onto the fields, unless there is already a field with this name.



212
213
214
215
# File 'lib/vcard/dirinfo.rb', line 212

def push_unique(field)
  push(field) unless @fields.detect { |f| f.name? field.name }
  self
end

#text(name) ⇒ Object

An array of all the values of fields named name, converted to text (using Field#to_text()).

TODO - call this #texts(), as in the plural?



123
124
125
126
127
128
129
130
131
# File 'lib/vcard/dirinfo.rb', line 123

def text(name)
  accum = []
  each do |f|
    if f.name? name
      accum << f.to_text
    end
  end
  accum
end

#valid?Boolean

Returns:

  • (Boolean)


51
52
53
# File 'lib/vcard/dirinfo.rb', line 51

def valid?
  @valid
end