Class: OperaContacts::ContactsParser

Inherits:
Object
  • Object
show all
Defined in:
lib/opera-contacts/parser.rb

Instance Method Summary collapse

Instance Method Details

#add_newlines(string) ⇒ Object

Turn’s Hotlist’s newlines into the conventional character



111
112
113
# File 'lib/opera-contacts/parser.rb', line 111

def add_newlines(string)
  return string.gsub("\x02\x02", "\n")
end

#build_collection!(parent, item_hashes) ⇒ Object

Recursively build a tree structure from item_hashes and add it to parent



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/opera-contacts/parser.rb', line 122

def build_collection!(parent, item_hashes)
  remaining = item_hashes
  not_finished = true
  while remaining != [] and not_finished do
    item_hash = remaining.first
    remaining = remaining[1..-1]

    case item_hash[:type]
    when "#CONTACT"
      contact = build_contact(item_hash)
      parent << contact
    when "#FOLDER"
      folder = build_folder(item_hash)
      parent << folder
      remaining = build_collection!(folder, remaining)
    when "end folder"
      not_finished = false
    else
      raise "Unknown type: #{item_hash[:type]}"
    end
  end

  return remaining
end

#build_contact(item_hash) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/opera-contacts/parser.rb', line 147

def build_contact(item_hash)
  data = item_hash[:data]
  id = Integer(data["ID"])
  contact = Contact.new(id, data["NAME"],
                        parse_date(data["CREATED"]), 
                        data["DESCRIPTION"])
  contact.homepage = data["URL"] if data["URL"]
  contact.phone = data["PHONE"] if data["PHONE"]
  contact.fax = data["FAX"] if data["FAX"]
  contact.postal_address = data["POSTALADDRESS"] if data["POSTALADDRESS"]
  #Strip off the newlines left by lines
  contact.emails = data["MAIL"].lines.map{|l| l.strip} if data["MAIL"]
  return contact
end

#build_folder(item_hash) ⇒ Object



162
163
164
165
166
167
168
# File 'lib/opera-contacts/parser.rb', line 162

def build_folder(item_hash)
  data = item_hash[:data]
  folder = ContactFolder.new(data["ID"], data["NAME"],
                             parse_date(data["CREATED"]), 
                             data["DESCRIPTION"])
  return folder
end

#build_structure(meta, item_hashes) ⇒ Object



115
116
117
118
119
# File 'lib/opera-contacts/parser.rb', line 115

def build_structure(meta, item_hashes)
  collection = ContactCollection.new
  build_collection!(collection, item_hashes)
  return collection
end

#extract_items(lines) ⇒ Object



38
39
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
# File 'lib/opera-contacts/parser.rb', line 38

def extract_items(lines)
  rtn = []
  remaining = lines

  def try_next_if_nil(*opts)
    opts.each do |opt|
      result = opt.call()
      if not result.nil?
        return result
      end
    end

    return nil
  end

  while remaining != []
    (item, remaining) = try_next_if_nil(
      lambda{parse_empty_line(remaining)},
      lambda{parse_item(remaining)},
      lambda{parse_folder_end(remaining)},
      lambda{fail "Parse error."}
    )
    rtn << item if item
  end

  return rtn
end

#extract_meta(lines) ⇒ Object



23
24
25
26
27
28
29
30
# File 'lib/opera-contacts/parser.rb', line 23

def extract_meta(lines)
  #TODO: Not sure how to turn this into split_at(lines) do |l|...
  (meta, remaining_lines) = split_at(lines, lambda{|l| l.strip != ""})
  if meta.count < 1 or not meta.first.start_with?("Opera Hotlist")
    raise "File broken (missing meta)"
  end
  return meta, remaining_lines
end

#parse_date(timestamp_string) ⇒ Object



170
171
172
173
# File 'lib/opera-contacts/parser.rb', line 170

def parse_date(timestamp_string)
  timestamp = Integer(timestamp_string)
  return Time.at(timestamp)
end

#parse_empty_line(lines) ⇒ Object



66
67
68
69
70
71
72
# File 'lib/opera-contacts/parser.rb', line 66

def parse_empty_line(lines)
  if lines.first.strip == ""
    return nil, lines[1..-1]
  else
    return nil
  end
end

#parse_folder_end(lines) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
# File 'lib/opera-contacts/parser.rb', line 74

def parse_folder_end(lines)
  if lines.first.strip == "-"
    end_folder = {
      :type=> "end folder",
      :data=>{}
    }
    return end_folder, lines[1..-1]
  else
    return nil
  end
end

#parse_item(lines) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/opera-contacts/parser.rb', line 86

def parse_item(lines)
  return nil unless lines.first.start_with? "#"

  type = lines.first
  item = {
    :type => lines.first.strip,
    :data => {},
  }

  not_finished = true
  rest = lines[1..-1]
  while rest != [] and not_finished do
    line = rest.first
    if line.start_with? "\t"
      (key, value) = line[1..-1].split("=", 2)
      item[:data][key] = add_newlines(value).strip
      rest = rest[1..-1]
    else
      not_finished = false
    end
  end
  return item, rest
end

#parse_s(hotlist_string) ⇒ Object



16
17
18
19
20
21
# File 'lib/opera-contacts/parser.rb', line 16

def parse_s(hotlist_string)
  lines = hotlist_string.lines
  (meta, remaining_lines) = extract_meta(lines)
  items = extract_items(remaining_lines)
  return build_structure(meta, items)
end

#split_at(arr, predicate) ⇒ Object

Divide an array into two parts based on a block TODO: Find built in function for this



34
35
36
# File 'lib/opera-contacts/parser.rb', line 34

def split_at(arr, predicate)
  return arr.take_while(&predicate), arr.drop_while(&predicate)
end

#try_next_if_nil(*opts) ⇒ Object



42
43
44
45
46
47
48
49
50
51
# File 'lib/opera-contacts/parser.rb', line 42

def try_next_if_nil(*opts)
  opts.each do |opt|
    result = opt.call()
    if not result.nil?
      return result
    end
  end

  return nil
end