Module: Phonelib::DataImporterHelper

Included in:
Phonelib::DataImporter::Importer
Defined in:
lib/phonelib/data_importer_helper.rb

Constant Summary collapse

XML_COMMENT_ATTRIBUTES =

xml comments attributes names that should not be parsed

%w(text comment)
XML_FORMAT_NAMES =

xml format attributes names

%w(intlFormat format)
MAX_POSSIBLE_LENGTH =

libphonenumber's maximum supported national significant number length

17

Instance Method Summary collapse

Instance Method Details

#camel2snake(s) ⇒ Object

method that converts camel case to snake case



198
199
200
# File 'lib/phonelib/data_importer_helper.rb', line 198

def camel2snake(s)
  s.gsub(/[A-Z]+/) { |m| "_#{m.downcase}" }
end

#file_path(file) ⇒ Object



13
14
15
# File 'lib/phonelib/data_importer_helper.rb', line 13

def file_path(file)
  "#{File.dirname(__FILE__)}/../../#{file}"
end

#fill_prefixes(key, value, prefix, prefixes) ⇒ Object

method updates prefixes hash recursively



48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/phonelib/data_importer_helper.rb', line 48

def fill_prefixes(key, value, prefix, prefixes)
  prefixes = {} if prefixes.nil?
  if prefix.size == 1
    pr = prefix.to_i
    prefixes[pr] ||= {}
    prefixes[pr][key] = value
  else
    pr = prefix[0].to_i
    prefixes[pr] = fill_prefixes(key, value, prefix[1..-1], prefixes[pr])
  end
  prefixes
end

#hash_from_xml(data, type) ⇒ Object

method creates hash from xml elements/element attributes



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/phonelib/data_importer_helper.rb', line 74

def hash_from_xml(data, type)
  hash = {}
  case type
  when :attributes
    data.attributes.each do |k, v|
      hash[name2sym(k)] = str_clean(v)
    end
  when :children
    data.each do |f|
      hash[name2sym(f[0])] = f[1]
    end
  when :element
    data.elements.each do |child|
      if child.name == 'possibleLengths'
        attributes = hash_from_xml(child, :attributes)
        hash[Core::POSSIBLE_PATTERN] = possible_length_regex(attributes)

        national_lengths = possible_lengths(attributes[:national])
        hash[Core::POSSIBLE_LENGTHS] = national_lengths unless national_lengths.empty?

        local_only_lengths = possible_lengths(attributes[:local_only])
        unless local_only_lengths.empty?
          hash[Core::POSSIBLE_LOCAL_ONLY_LENGTHS] = local_only_lengths
        end
      else
        hash[name2sym(child.name)] = str_clean(child.children.first)
      end
    end
  end
  hash
end

#intern_hashes(hash, table = {}) ⇒ Object



39
40
41
42
43
44
45
# File 'lib/phonelib/data_importer_helper.rb', line 39

def intern_hashes(hash, table = {})
  canonical = {}
  hash.each do |k, v|
    canonical[k] = v.is_a?(Hash) ? intern_hashes(v, table) : v
  end
  table[canonical] ||= canonical
end

#main_from_xml(file) ⇒ Object

get main body from parsed xml document



179
180
181
182
183
184
185
# File 'lib/phonelib/data_importer_helper.rb', line 179

def main_from_xml(file)
  xml_data = File.read(file)
  xml_data.force_encoding('utf-8')

  doc = Nokogiri::XML(xml_data)
  doc.elements.first.elements.first
end

#name2sym(name) ⇒ Object

helper that converts xml element name to symbol



193
194
195
# File 'lib/phonelib/data_importer_helper.rb', line 193

def name2sym(name)
  camel2snake(name).to_sym
end

#not_format?(name) ⇒ Boolean

method for checking if element name is not a format element

Returns:

  • (Boolean)


62
63
64
# File 'lib/phonelib/data_importer_helper.rb', line 62

def not_format?(name)
  !XML_FORMAT_NAMES.include? name
end

#parse_raw_file(file) ⇒ Object

method parses raw data file



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/phonelib/data_importer_helper.rb', line 161

def parse_raw_file(file)
  data = {}
  File.readlines(file).each do |line|
    line = str_clean line, false
    next if line.empty? || line[0] == '#'
    prefix, line_data = line.split('|')
    if line_data
      data[prefix] = if line_data.strip =~ /[^ ]{3,}&[^ ]{3,}/
                       line_data.strip.split('&')
                     else
                       line_data.strip
                     end
    end
  end
  data
end

#possible_length_ranges(lengths) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/phonelib/data_importer_helper.rb', line 128

def possible_length_ranges(lengths)
  lengths.split(',').map do |length|
    raw_token = length
    token = if raw_token.include?('[') || raw_token.include?(']')
              unless raw_token =~ /\A\[\d+(?:-\d+)?\]\z/
                raise ArgumentError, "invalid possible length: #{raw_token}"
              end
              raw_token[1..-2]
            else
              raw_token
            end
    unless token =~ /\A(?:-1|\d+(?:-\d+)?)\z/
      raise ArgumentError, "invalid possible length: #{raw_token}"
    end

    next [-1, -1] if token == '-1'

    first, last = token.split('-').map(&:to_i)
    last ||= first
    [first, last].each do |value|
      unless (1..MAX_POSSIBLE_LENGTH).include?(value)
        raise ArgumentError, "possible length out of range: #{value}"
      end
    end
    if first > last
      raise ArgumentError, "invalid possible length range: #{token}"
    end

    [first, last]
  end
end

#possible_length_regex(attributes) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/phonelib/data_importer_helper.rb', line 106

def possible_length_regex(attributes)
  return '' unless attributes[:national]

  possible_length_ranges(attributes[:national]).map do |first, last|
    if first == -1
      '(?!)'
    elsif first == last
      "\\d{#{first}}"
    else
      "\\d{#{first},#{last}}"
    end
  end.join('|')
end

#possible_lengths(lengths) ⇒ Object



120
121
122
123
124
125
126
# File 'lib/phonelib/data_importer_helper.rb', line 120

def possible_lengths(lengths)
  return [] unless lengths

  possible_length_ranges(lengths).flat_map do |first, last|
    first == -1 ? [-1] : (first..last).to_a
  end.uniq.sort
end

#save_data_fileObject

method saves parsed data to data files



18
19
20
21
22
# File 'lib/phonelib/data_importer_helper.rb', line 18

def save_data_file
  File.open(file_path(Phonelib::Core::FILE_MAIN_DATA), 'wb+') do |f|
    Marshal.dump(@data, f)
  end
end

#save_extended_data_fileObject

method saves extended data file



25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/phonelib/data_importer_helper.rb', line 25

def save_extended_data_file
  extended = {
    Phonelib::Core::EXT_PREFIXES => intern_hashes(@prefixes),
    Phonelib::Core::EXT_GEO_NAMES => @geo_names,
    Phonelib::Core::EXT_COUNTRY_NAMES => @countries,
    Phonelib::Core::EXT_TIMEZONES => @timezones,
    Phonelib::Core::EXT_CARRIERS => @carriers
  }
  File.open(file_path(Phonelib::Core::FILE_EXT_DATA), 'wb+') do |f|
    Marshal.dump(extended, f)
  end
  puts 'DATA SAVED'
end

#str_clean(s, white_space = true) ⇒ Object

helper that cleans string



188
189
190
# File 'lib/phonelib/data_importer_helper.rb', line 188

def str_clean(s, white_space = true)
  s.to_s.tr(white_space ? " \n" : "\n", '')
end

#without_comments(data) ⇒ Object

method filters xml elements excluding comments elements



67
68
69
70
71
# File 'lib/phonelib/data_importer_helper.rb', line 67

def without_comments(data)
  data.select do |el|
    !XML_COMMENT_ATTRIBUTES.include? el.name
  end
end