Class: Tilia::VObject::Property

Inherits:
Node
  • Object
show all
Defined in:
lib/tilia/v_object/property.rb,
lib/tilia/v_object/property/uri.rb,
lib/tilia/v_object/property/text.rb,
lib/tilia/v_object/property/time.rb,
lib/tilia/v_object/property/binary.rb,
lib/tilia/v_object/property/v_card.rb,
lib/tilia/v_object/property/boolean.rb,
lib/tilia/v_object/property/unknown.rb,
lib/tilia/v_object/property/flat_text.rb,
lib/tilia/v_object/property/i_calendar.rb,
lib/tilia/v_object/property/utc_offset.rb,
lib/tilia/v_object/property/float_value.rb,
lib/tilia/v_object/property/v_card/date.rb,
lib/tilia/v_object/property/integer_value.rb,
lib/tilia/v_object/property/i_calendar/date.rb,
lib/tilia/v_object/property/i_calendar/recur.rb,
lib/tilia/v_object/property/v_card/date_time.rb,
lib/tilia/v_object/property/i_calendar/period.rb,
lib/tilia/v_object/property/v_card/time_stamp.rb,
lib/tilia/v_object/property/i_calendar/duration.rb,
lib/tilia/v_object/property/v_card/language_tag.rb,
lib/tilia/v_object/property/i_calendar/date_time.rb,
lib/tilia/v_object/property/i_calendar/cal_address.rb,
lib/tilia/v_object/property/v_card/date_and_or_time.rb

Overview

Property.

A property is always in a KEY:VALUE structure, and may optionally contain parameters.

Defined Under Namespace

Modules: ICalendar, VCard Classes: Binary, Boolean, FlatText, FloatValue, IntegerValue, Text, Time, Unknown, Uri, UtcOffset

Constant Summary

Constants inherited from Node

Node::PROFILE_CALDAV, Node::PROFILE_CARDDAV, Node::REPAIR

Instance Attribute Summary collapse

Attributes inherited from Node

#iterator, #parent

Instance Method Summary collapse

Methods inherited from Node

#each, #size

Constructor Details

#initialize(root, name, value = nil, parameters = {}, group = nil) ⇒ void

Creates the generic property.

Parameters must be specified in key=>value syntax.

Parameters:

  • root (Component)

    The root document

  • name (String)
  • value (String|array, nil) (defaults to: nil)
  • parameters (array) (defaults to: {})

    List of parameters

  • group (String) (defaults to: nil)

    The vcard property group



62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/tilia/v_object/property.rb', line 62

def initialize(root, name, value = nil, parameters = {}, group = nil)
  @parameters = {}
  @delimiter = ';'
  @name = name
  @group = group
  @root = root

  parameters.each do |k, v|
    add(k, v)
  end

  self.value = value unless value.nil?
end

Instance Attribute Details

#delimiterString?

In case this is a multi-value property. This string will be used as a delimiter.

Returns:

  • (String, nil)


49
50
51
# File 'lib/tilia/v_object/property.rb', line 49

def delimiter
  @delimiter
end

#groupString

Property group.

This is only used in vcards

Returns:

  • (String)


33
34
35
# File 'lib/tilia/v_object/property.rb', line 33

def group
  @group
end

#nameString

Property name.

This will contain a string such as DTSTART, SUMMARY, FN.

Returns:

  • (String)


26
27
28
# File 'lib/tilia/v_object/property.rb', line 26

def name
  @name
end

#parametersarray

Returns an iterable list of children.

Returns:

  • (array)


38
39
40
# File 'lib/tilia/v_object/property.rb', line 38

def parameters
  @parameters
end

#valueString

Returns the current value.

This method will always return a singular value. If this was a multi-value object, some decision will be made first on how to represent it as a string.

To get the correct multi-value version, use getParts.

Returns:

  • (String)


94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/tilia/v_object/property.rb', line 94

def value
  if @value.is_a?(Array)
    if @value.empty?
      nil
    elsif @value.size == 1
      @value[0]
    else
      raw_mime_dir_value
    end
  else
    @value
  end
end

Instance Method Details

#==(other) ⇒ Object

TODO: document



539
540
541
542
543
544
545
# File 'lib/tilia/v_object/property.rb', line 539

def ==(other)
  if other.is_a?(String)
    to_s == other
  else
    super(other)
  end
end

#[](name) ⇒ Node

Returns a parameter.

If the parameter does not exist, null is returned.

Parameters:

  • name (String)

Returns:



363
364
365
366
367
# File 'lib/tilia/v_object/property.rb', line 363

def [](name)
  return super(name) if name.is_a?(Fixnum)

  @parameters[name.upcase]
end

#[]=(name, value) ⇒ void

This method returns an undefined value.

Creates a new parameter.

Parameters:

  • name (String)
  • value


375
376
377
378
379
380
381
382
383
384
385
386
387
# File 'lib/tilia/v_object/property.rb', line 375

def []=(name, value)
  if name.is_a?(Fixnum)
    super(name, value)
    # @codeCoverageIgnoreStart
    # This will never be reached, because an exception is always
    # thrown.
    return nil
    # @codeCoverageIgnoreEnd
  end

  param = Parameter.new(@root, name, value)
  @parameters[param.name] = param
end

#add(name, value = nil) ⇒ Object

Adds a new parameter.

If a parameter with same name already existed, the values will be combined. If nameless parameter is added, we try to guess it’s name.

Parameters:

  • name (String)
  • value (String, nil|array) (defaults to: nil)


141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/tilia/v_object/property.rb', line 141

def add(name, value = nil)
  no_name = false
  if name.nil?
    name = Parameter.guess_parameter_name_by_value(value)
    no_name = true
  end

  if @parameters.key?(name.upcase)
    @parameters[name.upcase].add_value(value)
  else
    param = Parameter.new(@root, name, value)
    param.no_name = no_name
    @parameters[param.name] = param
  end
end

#delete(name) ⇒ void

This method returns an undefined value.

Removes one or more parameters with the specified name.

Parameters:

  • name (String)


394
395
396
397
398
399
400
401
402
403
404
405
# File 'lib/tilia/v_object/property.rb', line 394

def delete(name)
  if name.is_a?(Fixnum)
    super(name)
    # @codeCoverageIgnoreStart
    # This will never be reached, because an exception is always
    # thrown.
    return nil
    # @codeCoverageIgnoreEnd
  end

  @parameters.delete(name.upcase)
end

#destroyvoid

This method returns an undefined value.

Call this method on a document if you’re done using it.

It’s intended to remove all circular references, so PHP can easily clean it up.



528
529
530
531
532
533
534
535
536
# File 'lib/tilia/v_object/property.rb', line 528

def destroy
  super

  @parameters.each do |_name, param|
    param.destroy
  end

  @parameters = {}
end

#initialize_copy(_original) ⇒ void

This method returns an undefined value.

This method is automatically called when the object is cloned. Specifically, this will ensure all child elements are also cloned.



411
412
413
414
415
416
417
418
# File 'lib/tilia/v_object/property.rb', line 411

def initialize_copy(_original)
  new_params = {}
  @parameters.each do |key, child|
    new_params[key] = child.clone
    new_params[key].parent = self
  end
  @parameters = new_params
end

#json_serializearray

This method returns an array, with the representation as it should be encoded in JSON. This is used to create jCard or jCal documents.

Returns:

  • (array)


246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/tilia/v_object/property.rb', line 246

def json_serialize
  parameters = {}

  @parameters.each do |_, parameter|
    next if parameter.name == 'VALUE'

    parameters[parameter.name.downcase] = parameter.json_serialize
  end

  # In jCard, we need to encode the property-group as a separate 'group'
  # parameter.
  parameters['group'] = @group if @group

  result = [
    @name.downcase,
    parameters,
    value_type.downcase
  ]
  result.concat json_value
end

#json_valuearray

Returns the value, in the format it should be encoded for JSON.

This method must always return an array.

Returns:

  • (array)


222
223
224
# File 'lib/tilia/v_object/property.rb', line 222

def json_value
  parts
end

#json_value=(value) ⇒ void

This method returns an undefined value.

Sets the JSON value, as it would appear in a jCard or jCal object.

The value must always be an array.

Parameters:

  • value (array)


233
234
235
236
237
238
239
240
# File 'lib/tilia/v_object/property.rb', line 233

def json_value=(value)
  value = value.values if value.is_a?(Hash)
  if value.size == 1
    self.value = value[0]
  else
    self.value = value
  end
end

#key?(name) ⇒ Boolean

Checks if an array element exists.

Parameters:

  • name

Returns:



347
348
349
350
351
352
353
354
# File 'lib/tilia/v_object/property.rb', line 347

def key?(name)
  name = name.upcase

  @parameters.each do |_name, parameter|
    return true if parameter.name == name
  end
  false
end

#partsarray

Returns a multi-valued property.

This method always returns an array, if there was only a single value, it will still be wrapped in an array.

Returns:

  • (array)


123
124
125
126
127
128
129
130
131
# File 'lib/tilia/v_object/property.rb', line 123

def parts
  if @value.nil?
    []
  elsif @value.is_a?(Array)
    @value.clone
  else
    [@value]
  end
end

#parts=(parts) ⇒ void

This method returns an undefined value.

Sets a multi-valued property.

Parameters:

  • parts (array)


113
114
115
# File 'lib/tilia/v_object/property.rb', line 113

def parts=(parts)
  @value = parts
end

#raw_mime_dir_valueString

Returns a raw mime-dir representation of the value.

Returns:

  • (String)


185
186
# File 'lib/tilia/v_object/property.rb', line 185

def raw_mime_dir_value
end

#raw_mime_dir_value=(_val) ⇒ void

This method returns an undefined value.

Sets a raw value coming from a mimedir (iCalendar/vCard) file.

This has been ‘unfolded’, so only 1 line will be passed. Unescaping is not yet done, but parameters are not included.

Parameters:

  • val (String)


179
180
# File 'lib/tilia/v_object/property.rb', line 179

def raw_mime_dir_value=(_val)
end

#serializeString

Turns the object back into a serialized blob.

Returns:

  • (String)


191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/tilia/v_object/property.rb', line 191

def serialize
  str = @name
  str = "#{@group}.#{@name}" if @group

  parameters.each do |_name, param| # use parameters(), can be overwritten
    str += ";#{param.serialize}"
  end

  str += ":#{raw_mime_dir_value}"

  out = ''
  while str.size > 0
    if str.bytesize > 75
      tmp =  StringUtil.mb_strcut(str, 75)
      out += tmp + "\r\n"
      str = ' ' + str[tmp.length..-1]
    else
      out += str + "\r\n"
      str = ''
      break
    end
  end

  out
end

#to_sString

Called when this object is being cast to a string.

If the property only had a single value, you will get just that. In the case the property had multiple values, the contents will be escaped and combined with ,.

Returns:

  • (String)


338
339
340
# File 'lib/tilia/v_object/property.rb', line 338

def to_s
  value.to_s
end

#validate(options = 0) ⇒ array

Validates the node for correctness.

The following options are supported:

- Node::REPAIR - If something is broken, and automatic repair may
                 be attempted.

An array is returned with warnings.

Every item in the array has the following properties:

* level - (number between 1 and 3 with severity information)
* message - (human readable message)
* node - (reference to the offending node)

Parameters:

  • options (Fixnum) (defaults to: 0)

Returns:

  • (array)


436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
# File 'lib/tilia/v_object/property.rb', line 436

def validate(options = 0)
  warnings = []

  # Checking if our value is UTF-8
  if raw_mime_dir_value.is_a?(String) && !StringUtil.utf8?(raw_mime_dir_value)
    old_value = raw_mime_dir_value
    level = 3

    if options & REPAIR > 0
      new_value = StringUtil.convert_to_utf8(old_value)

      self.raw_mime_dir_value = new_value
      level = 1
    end

    matches = /([\x00-\x08\x0B-\x0C\x0E-\x1F\x7F])/.match(old_value)
    if matches
      message = format('Property contained a control character (0x%02x)', matches[1].ord)
    else
      message = "Property is not valid UTF-8! #{old_value}"
    end

    warnings << {
      'level'   => level,
      'message' => message,
      'node'    => self
    }
  end

  # Checking if the propertyname does not contain any invalid bytes.
  unless @name =~ /^([A-Z0-9-]+)$/
    warnings << {
      'level'   => 1,
      'message' => "The propertyname: #{@name} contains invalid characters. Only A-Z, 0-9 and - are allowed",
      'node'    => self
    }

    if options & REPAIR > 0
      # Uppercasing and converting underscores to dashes.
      @name = @name.upcase.tr('_', '-')

      # Removing every other invalid character
      @name = @name.gsub(/([^A-Z0-9-])/u, '')
    end
  end

  encoding = self['ENCODING']
  if encoding
    if @root.document_type == Document::VCARD40
      warnings << {
        'level'   => 1,
        'message' => 'ENCODING parameter is not valid in vCard 4.',
        'node'    => self
      }
    else
      encoding = encoding.to_s

      allowed_encoding = []

      case @root.document_type
      when Document::ICALENDAR20
        allowed_encoding = ['8BIT', 'BASE64']
      when Document::VCARD21
        allowed_encoding = ['QUOTED-PRINTABLE', 'BASE64', '8BIT']
      when Document::VCARD30
        allowed_encoding = ['B']
      end

      if allowed_encoding.any? && !allowed_encoding.include?(encoding.upcase)
        warnings << {
          'level'   => 1,
          'message' => "ENCODING=#{encoding.upcase} is not valid for this document type.",
          'node'    => self
        }
      end
    end
  end

  # Validating inner parameters
  @parameters.each do |_name, param|
    warnings.concat param.validate(options)
  end

  warnings
end

#value_typeString

Returns the type of value.

This corresponds to the VALUE= parameter. Every property also has a ‘default’ valueType.

Returns:

  • (String)


168
169
# File 'lib/tilia/v_object/property.rb', line 168

def value_type
end

#xml_serialize(writer) ⇒ void

This method returns an undefined value.

This method serializes the data into XML. This is used to create xCard or xCal documents.

Parameters:

  • writer (Xml\Writer)

    XML writer.



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'lib/tilia/v_object/property.rb', line 283

def xml_serialize(writer)
  parameters = []

  @parameters.each do |_, parameter|
    next if parameter.name == 'VALUE'

    parameters << parameter
  end

  writer.start_element(@name.downcase)

  if parameters.any?
    writer.start_element('parameters')

    parameters.each do |parameter|
      writer.start_element(parameter.name.downcase)
      writer.write(parameter)
      writer.end_element
    end

    writer.end_element
  end

  xml_serialize_value(writer)
  writer.end_element
end

#xml_value=(value) ⇒ void

This method returns an undefined value.

Hydrate data from a XML subtree, as it would appear in a xCard or xCal object.

Parameters:

  • value (array)


273
274
275
# File 'lib/tilia/v_object/property.rb', line 273

def xml_value=(value)
  self.json_value = value
end