Class: Tilia::VObject::Property::Text

Inherits:
Tilia::VObject::Property show all
Defined in:
lib/tilia/v_object/property/text.rb

Overview

Text property.

This object represents TEXT values.

Constant Summary

Constants inherited from Node

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

Instance Attribute Summary collapse

Attributes inherited from Tilia::VObject::Property

#group, #name, #parameters, #value

Attributes inherited from Node

#iterator, #parent

Instance Method Summary collapse

Methods inherited from Tilia::VObject::Property

#==, #[], #[]=, #add, #delete, #destroy, #initialize_copy, #json_serialize, #json_value=, #key?, #parts, #parts=, #to_s, #xml_serialize, #xml_value=

Methods inherited from Node

#==, #[], #[]=, #delete, #destroy, #each, #json_serialize, #key?, #size, #xml_serialize

Constructor Details

#initialize(root, name, value = nil, parameters = [], group = nil) ⇒ void

Creates the property.

You can specify the parameters either in key=>value syntax, in which case parameters will automatically be created, or you can just pass a list of Parameter objects.

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



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/tilia/v_object/property/text.rb', line 40

def initialize(root, name, value = nil, parameters = [], group = nil)
  super(root, name, value, parameters, group)

  @delimiter = ','
  @structured_values = [
    # vCard
    'N',
    'ADR',
    'ORG',
    'GENDER',
    'CLIENTPIDMAP',

    # iCalendar
    'REQUEST-STATUS'
  ]
  @minimum_property_values = {
    'N'   => 5,
    'ADR' => 7
  }

  # There's two types of multi-valued text properties:
  # 1. multivalue properties.
  # 2. structured value properties
  #
  # The former is always separated by a comma, the latter by semi-colon.
  @delimiter = ';' if @structured_values.include?(name)
end

Instance Attribute Details

#delimiterString

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

Returns:

  • (String)


12
13
14
# File 'lib/tilia/v_object/property/text.rb', line 12

def delimiter
  @delimiter
end

Instance Method Details

#json_valuearray

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

This method must always return an array.

Returns:

  • (array)


140
141
142
143
144
145
146
147
# File 'lib/tilia/v_object/property/text.rb', line 140

def json_value
  # Structured text values should always be returned as a single
  # array-item. Multi-value text should be returned as multiple items in
  # the top-array.
  return [parts] if @structured_values.include?(@name)

  parts
end

#quoted_printable_value=(val) ⇒ void

This method returns an undefined value.

Sets the value as a quoted-printable encoded string.

Parameters:

  • val (String)


85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/tilia/v_object/property/text.rb', line 85

def quoted_printable_value=(val)
  val = Mail::Encodings::QuotedPrintable.decode(val)
  val = val.gsub(/\n/, "\r\n").gsub(/\r\r/, "\r")

  # force the correct encoding
  begin
    val.force_encoding(Encoding.find(@parameters['CHARSET'].to_s))
  rescue
    val.force_encoding(Encoding::UTF_8)
  end

  # Quoted printable only appears in vCard 2.1, and the only character
  # that may be escaped there is ;. So we are simply splitting on just
  # that.
  #
  # We also don't have to unescape \\, so all we need to look for is a
  # that's not preceeded with a \.
  matches = val.split(/ (?<!\\\\) ; /x)
  self.value = matches
end

#raw_mime_dir_valueString

Returns a raw mime-dir representation of the value.

Returns:

  • (String)


109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/tilia/v_object/property/text.rb', line 109

def raw_mime_dir_value
  val = parts

  if @minimum_property_values.key?(@name)
    val << '' while val.size < @minimum_property_values[@name]
  end

  val = val.map do |item|
    item = [item] unless item.is_a?(Array)

    item = item.map do |sub_item|
      sub_item.to_s.gsub(
        /[\\;,\n\r]/,
        '\\' => '\\\\',
        ';'  => '\;',
        ','  => '\,',
        "\n" => '\n',
        "\r" => ''
      )
    end
    item.join(',')
  end

  val.join(@delimiter)
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)


76
77
78
# File 'lib/tilia/v_object/property/text.rb', line 76

def raw_mime_dir_value=(val)
  self.value = Parser::MimeDir.unescape_value(val, @delimiter)
end

#serializeString

Turns the object back into a serialized blob.

Returns:

  • (String)


162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/tilia/v_object/property/text.rb', line 162

def serialize
  # We need to kick in a special type of encoding, if it's a 2.1 vcard.
  return super unless @root.document_type == Document::VCARD21

  val = parts

  if @minimum_property_values.key?(@name)
    val << '' while val.size < @minimum_property_values[@name]
  end

  # Imploding multiple parts into a single value, and splitting the
  # values with ;.
  if val.size > 1
    val = val.map do |v|
      v.gsub(';', '\\;')
    end
    val = val.join(';')
  else
    val = val[0]
  end

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

  @parameters.each do |_key, param|
    next if param.value == 'QUOTED-PRINTABLE'

    str += ';' + param.serialize
  end

  # If the resulting value contains a \n, we must encode it as
  # quoted-printable.
  if val.index("\n")
    str += ';ENCODING=QUOTED-PRINTABLE:'
    last_line = str
    out = ''

    # The PHP built-in quoted-printable-encode does not correctly
    # encode newlines for us. Specifically, the \r\n sequence must in
    # vcards be encoded as =0D=OA and we must insert soft-newlines
    # every 75 bytes.
    val.bytes.each do |ord|
      # These characters are encoded as themselves.
      if ord >= 32 && ord <= 126
        last_line += ord.chr
      else
        last_line += format('=%02X', ord)
      end

      next unless last_line.length >= 75
      out += last_line + "=\r\n "
      last_line = ''
    end

    out += last_line + "\r\n" unless last_line.blank?
    return out
  else
    str += ':' + val
    out = ''

    while str.length > 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

    return out
  end
end

#validate(options = 0) ⇒ array

Validates the node for correctness.

The following options are supported:

Node::REPAIR - May attempt to automatically repair the problem.
Node::PROFILE_CARDDAV - Validate the vCard for CardDAV purposes.
Node::PROFILE_CALDAV - Validate the iCalendar for CalDAV purposes.

This method returns an array with detected problems. Every element has the following properties:

* level - problem level.
* message - A human-readable string describing the issue.
* node - A reference to the problematic node.

The level means:

1 - The issue was repaired (only happens if REPAIR was turned on).
2 - A warning.
3 - An error.

Parameters:

  • options (Fixnum) (defaults to: 0)

Returns:

  • (array)


312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/tilia/v_object/property/text.rb', line 312

def validate(options = 0)
  warnings = super(options)

  if @minimum_property_values.key?(@name)
    minimum = @minimum_property_values[@name]
    parts = self.parts
    if parts.size < minimum
      warnings << {
        'level'   => 1,
        'message' => "This property must have at least #{minimum} components. It only has #{parts.size}",
        'node'    => self
      }

      if options & REPAIR > 0
        parts << '' while parts.size < minimum
        self.parts = parts
      end
    end
  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)


155
156
157
# File 'lib/tilia/v_object/property/text.rb', line 155

def value_type
  'TEXT'
end