lib/phonie/country.rb in phonie-1.0.4 vs lib/phonie/country.rb in phonie-2.0.0

- old
+ new

@@ -1,120 +1,106 @@ module Phonie - class Country < Struct.new(:name, :country_code, :char_2_code, :char_3_code, :area_code, :local_number_format, :mobile_format, :full_number_length, :number_format) - cattr_accessor :all - + class Country < Struct.new(:name, :country_code, :char_2_code, :iso_3166_code, :area_code, :local_number_format, :mobile_format, :full_number_length, :number_format) def self.load - return @@all if @@all.present? - data_file = File.join(File.dirname(__FILE__), 'data', 'phone_countries.yml') - @@all = [] - YAML.load(File.read(data_file)).each_pair do |key, c| + all = [] + YAML.load(File.read(data_file)).each do |c| next unless c[:area_code] && c[:local_number_format] - @@all << Country.new(c[:name], c[:country_code], c[:char_2_code], c[:char_3_code], c[:area_code], c[:local_number_format], c[:mobile_format], c[:full_number_length], c[:number_format]) + all << Country.new(c[:name], c[:country_code], c[:char_2_code], c[:iso_3166_code], c[:area_code], c[:local_number_format], c[:mobile_format], c[:full_number_length], c[:number_format]) end - @@all + all end - def to_s - name - end + COUNTRIES = self.load + COUNTRIES_BY_PHONE_CODE = COUNTRIES.inject(Hash.new){|h, c| (h[c.country_code] ||= []) << c; h } + COUNTRIES_BY_COUNTRY_CODE = Hash[*COUNTRIES.map{|c| [c.iso_3166_code.downcase, c] }.flatten] + COUNTRIES_BY_NAME = Hash[*COUNTRIES.map{|c| [c.name.downcase, c] }.flatten] def self.find_all_by_phone_code(code) - return [] if code.nil? - @@all.select {|c| c.country_code == code } + COUNTRIES_BY_PHONE_CODE[code] || [] end def self.find_by_country_code(code) - return nil if code.nil? - @@all.each {|c| return c if c.char_3_code.downcase == code.downcase } - nil + COUNTRIES_BY_COUNTRY_CODE[code.downcase] if code end def self.find_by_name(name) - return nil if name.nil? - @@all.each {|c| return c if c.name.downcase == name.downcase } - nil + COUNTRIES_BY_NAME[name.downcase] if name end # detect country from the string entered def self.detect(string, default_country_code, default_area_code) - Country.find_all_by_phone_code(default_country_code).each do |country| - return country if country.matches_local_number?(string, default_area_code) + # use the default_country_code to try for a quick match + country = find_all_by_phone_code(default_country_code).find do |country| + country.matches_full_number?(string) || + country.matches_local_number_with_area_code?(string) || + country.matches_local_number?(string, default_area_code) end - # find if the number has a country code - Country.all.each do |country| - return country if country.matches_full_number?(string) - end - return nil + # then search all for a full match + country || COUNTRIES.find {|country| country.matches_full_number?(string) } end + def to_s + name + end + def is_mobile?(number) return true if mobile_format.nil? number =~ mobile_number_regex ? true : false end - def matches_local_number?(string, default_area_code) - ((string =~ full_number_regexp || - string =~ area_code_number_regexp) && string =~ number_format_regex) || - ((string =~ number_regex) && (default_area_code =~ area_code_regex)) + # true if string contains country_code + area_code + local_number + def matches_full_number?(string) + string =~ full_number_regex && string =~ number_format_regex end - def matches_full_number?(string) - string =~ full_number_regexp && string =~ number_format_regex + # true if string contains area_code + local_number + def matches_local_number_with_area_code?(string) + string =~ area_code_number_regex && string =~ number_format_regex end - def number_parts(number, default_area_code) - number_part = if default_area_code - number.match(number_regex) - $1 + # true if string contains only the local_number, but the default_area_code is valid + def matches_local_number?(string, default_area_code) + string =~ number_regex && default_area_code =~ area_code_regex + end + + def parse(number, default_area_code) + if md = number.match(full_number_regex) + {:area_code => md[2], :number => md[-1]} + elsif md = number.match(area_code_number_regex) + {:area_code => md[1], :number => md[-1]} + elsif md = number.match(number_regex) + {:area_code => default_area_code, :number => md[1]} else - nil + {} end - - if number_part.nil? - matches = number.match(area_code_number_regexp) - area_part = $1 - number_part = matches.to_a.last - end - - if number_part.nil? - matches = number.match(full_number_regexp) - country_part, area_part = $1, $2 - number_part = matches.to_a.last - end - - area_part ||= default_area_code - - raise "Could not determine area code" if area_part.nil? - raise "Could not determine number" if number_part.nil? - - {:number => number_part, :area_code => area_part, :country_code => country_code, :country => self} end private + def number_format_regex - Regexp.new("^[+0]?(#{country_code})?(#{number_format})$") + @number_format_regex ||= Regexp.new("^[+0]?(#{country_code})?(#{number_format})$") end - def full_number_regexp - Regexp.new("^[+]?(#{country_code})(#{area_code})(#{local_number_format})$") + def full_number_regex + @full_number_regex ||= Regexp.new("^[+]?(#{country_code})(#{area_code})(#{local_number_format})$") end - def area_code_number_regexp - Regexp.new("^0?(#{area_code})(#{local_number_format})$") + def area_code_number_regex + @area_code_number_regex ||= Regexp.new("^0?(#{area_code})(#{local_number_format})$") end def area_code_regex - Regexp.new("^0?(#{area_code})$") + @area_code_regex ||= Regexp.new("^0?(#{area_code})$") end def mobile_number_regex - Regexp.new("^(#{mobile_format})$") + @mobile_number_regex ||= Regexp.new("^(#{mobile_format})$") end def number_regex - Regexp.new("^(#{local_number_format})$") + @number_regex ||= Regexp.new("^(#{local_number_format})$") end end end