Class: Virginity::Param

Inherits:
Object
  • Object
show all
Defined in:
lib/virginity/dir_info/param.rb,
lib/virginity/api_extensions.rb

Overview

A directory information parameter is basically a key-value pair. An instance of this class represents such a pair. It can deal with comparison and encoding. The class contains some methods to deal with lists of parameters Param keys are case insensitive

Constant Summary collapse

PARAM_NAME_CHECK =

param-name = x-name / iana-token iana-token = 1*(ALPHA / DIGIT / “-”)

; identifier registered with IANA
/^((X|x)\-)?(\w|\-)+$/
ESCAPE_CHARS =

A semi-colon in a property parameter value must be escaped with a Blackslash character. commas too I think, since these are used to separate the param-values

param-value  = ptext / quoted-string
ptext  = *SAFE-CHAR
SAFE-CHAR    = WSP / %x21 / %x23-2B / %x2D-39 / %x3C-7E / NON-ASCII
   ; Any character except CTLs, DQUOTE, ";", ":", ","
quoted-string = DQUOTE *QSAFE-CHAR DQUOTE
   QSAFE-CHAR   = WSP / %x21 / %x23-7E / NON-ASCII
  ; Any character except CTLs, DQUOTE
/\\|\;|\,|\"/
LF =
"\n"
ESCAPED_LF =
"\\n"
ESCAPE_CHARS_WITH_LF =
/\\|\;|\,|\"|\n/
ESCAPE_HASH =
{
'\\' => '\\\\',
';' => '\;',
',' => '\,',
'"' => '\"',
"\n" => '\n'
}
COLON =
/:/
SEMICOLON =
/;/
COMMA =
/,/
EQUALS =
/=/
KEY =
/#{Bnf::NAME}/
PARAM_NAME =
/((X|x)\-)?(\w|\-)+/
PARAM_VALUE =
/#{Bnf::PVALUE}/
BASE64_OR_B =
/^(BASE64)|(B)$/i
XSYNTHESIS_REF =
/^X-Synthesis-Ref\d*$/i

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key, value) ⇒ Param

Returns a new instance of Param.



10
11
12
13
# File 'lib/virginity/dir_info/param.rb', line 10

def initialize(key, value)
  self.key = key
  @value = value.to_s
end

Instance Attribute Details

#keyObject

Returns the value of attribute key.



7
8
9
# File 'lib/virginity/dir_info/param.rb', line 7

def key
  @key
end

#valueObject

Returns the value of attribute value.



8
9
10
# File 'lib/virginity/dir_info/param.rb', line 8

def value
  @value
end

Class Method Details

.charset(value) ⇒ Object

convenience method, the same as calling Param.new(“CHARSET”, value)



25
26
27
# File 'lib/virginity/dir_info/param.rb', line 25

def self.charset(value)
  new('CHARSET', value)
end

.decode_value(val) ⇒ Object



110
111
112
113
114
115
116
# File 'lib/virginity/dir_info/param.rb', line 110

def self.decode_value(val)
  if Bnf::QUOTED_STRING =~ val
    EncodingDecoding::decode_text($2)
  else
    val
  end
end

.deep_copy(paramlist) ⇒ Object



201
202
203
204
205
# File 'lib/virginity/dir_info/param.rb', line 201

def self.deep_copy(paramlist)
  return [] if paramlist.nil? or paramlist.empty?
  # params_from_string(simple_params_to_s(paramlist)) # slower
  Marshal::load(Marshal::dump(paramlist)) # faster
end

.encoding(value) ⇒ Object

convenience method, the same as calling Param.new(“ENCODING”, value)



30
31
32
# File 'lib/virginity/dir_info/param.rb', line 30

def self.encoding(value)
  new('ENCODING', value)
end

.etag(value) ⇒ Object

convenience method, the same as calling Param.new(“ETAG”, value)



35
36
37
# File 'lib/virginity/dir_info/param.rb', line 35

def self.etag(value)
  new('ETAG', value)
end

.params_from_string(string) ⇒ Object



197
198
199
# File 'lib/virginity/dir_info/param.rb', line 197

def self.params_from_string(string)
  scan_params(StringScanner.new(string))
end

.params_to_s(params) ⇒ Object

encodes an array of params



126
127
128
129
130
131
132
133
134
# File 'lib/virginity/dir_info/param.rb', line 126

def self.params_to_s(params)
  return "" if params.empty?
  s = []
  params.map {|p| p.key }.uniq.sort!.each do |key|
    values = params.select {|p| p.has_key? key }.map {|p| p.escaped_value }.uniq.sort!
    s << "#{key}=#{values.join(",")}"
  end
  ";#{s.join(";")}"
end

.prefObject



20
21
22
# File 'lib/virginity/dir_info/param.rb', line 20

def self.pref
  new('TYPE', 'PREF')
end

.scan_params(scanner) ⇒ Object

scans all params at the given position from a StringScanner including the pending colon



159
160
161
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
# File 'lib/virginity/dir_info/param.rb', line 159

def self.scan_params(scanner)
  unless scanner.skip(SEMICOLON)
    scanner.skip(COLON)
    return []
  end
  params = []
  until scanner.skip(COLON) # a colon indicates the end of the paramlist
    key = scanner.scan(PARAM_NAME)
    unless scanner.skip(EQUALS)
      # it's not a proper DirInfo param but nevertheless some companies (Apple) put vCard2.1 shorthand params without a key in they vCard3.0. Therefore we include support for these special cases.
      case key
      when Vcard21::QUOTED_PRINTABLE
        params << Param.new('ENCODING', key)
      when BASE64_OR_B
        params << Param.new('ENCODING', 'B')
      when XSYNTHESIS_REF
        # we ignore this crap.
      when *Vcard21::KNOWNTYPES
        params << Param.new('TYPE', key)
      else
        raise InvalidEncoding, "encountered paramkey #{key.inspect} without a paramvalue"
      end
    end
    key.upcase!
    begin
      if value = scanner.scan(PARAM_VALUE)
        params << Param.new(key, Param::decode_value(value))
      end
      break if scanner.skip(SEMICOLON) # after a semicolon, we expect key=(value)+
    end until scanner.skip(COMMA).nil? # a comma indicates another values (TYPE=HOME,WORK)
  end
  params
rescue InvalidEncoding
  raise
rescue => e
  raise InvalidEncoding, "#{scanner.string.inspect} at character #{scanner.pos}\noriginal error: #{e}"
end

.simple_params_to_s(params) ⇒ Object

encodes an array of params



119
120
121
122
# File 'lib/virginity/dir_info/param.rb', line 119

def self.simple_params_to_s(params)
  return "" if params.empty?
  ";" + params.uniq.sort.join(";")
end

.type(value) ⇒ Object

convenience method, the same as calling Param.new(“TYPE”, value)



16
17
18
# File 'lib/virginity/dir_info/param.rb', line 16

def self.type(value)
  new('TYPE', value)
end

Instance Method Details

#<=>(other) ⇒ Object



72
73
74
75
76
77
78
# File 'lib/virginity/dir_info/param.rb', line 72

def <=>(other)
  if has_key?(other.key)
    @value <=> other.value
  else
    @key <=> other.key
  end
end

#==(other) ⇒ Object

NB. Other doesn’t necessarily have to be a Param



66
67
68
69
70
# File 'lib/virginity/dir_info/param.rb', line 66

def ==(other)
  has_key?(other.key) && @value == other.value
rescue
  false
end

#as_json(options = {}) ⇒ Object



22
23
24
# File 'lib/virginity/api_extensions.rb', line 22

def as_json(options = {})
  { key => value }
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


57
58
59
# File 'lib/virginity/dir_info/param.rb', line 57

def eql?(other)
  other.is_a?(Param) && has_key?(other.key)&& @value == other.value
end

#escaped_valueObject



100
101
102
103
104
105
106
107
108
# File 'lib/virginity/dir_info/param.rb', line 100

def escaped_value
  if @value =~ ESCAPE_CHARS_WITH_LF
    # put quotes around the escaped string
    "\"#{@value.gsub(ESCAPE_CHARS) { |char| "\\#{char}" }.gsub(LF, ESCAPED_LF)}\""
#         "\"#{@value.gsub(ESCAPE_CHARS_WITH_LF, ESCAPE_HASH)}\"" # ruby1.9
  else
    @value
  end
end

#has_key?(other_key) ⇒ Boolean

Returns:

  • (Boolean)


61
62
63
# File 'lib/virginity/dir_info/param.rb', line 61

def has_key?(other_key)
  @key.casecmp(other_key) == 0
end

#hashObject



53
54
55
# File 'lib/virginity/dir_info/param.rb', line 53

def hash
  [@key, @value].hash
end

#to_sObject Also known as: inspect



39
40
41
# File 'lib/virginity/dir_info/param.rb', line 39

def to_s
  "#{@key}=#{escaped_value}"
end