diff --git a/lib/global_phone/context.rb b/lib/global_phone/context.rb index 4524524..dc0d066 100644 --- a/lib/global_phone/context.rb +++ b/lib/global_phone/context.rb @@ -23,6 +23,12 @@ def parse(string, territory_name = default_territory_name) db.parse(string, territory_name) end + def territory_for_country_code(string) + region = db.region_for_country_code(string) + return unless region + region.territory_for_contry_code + end + def normalize(string, territory_name = default_territory_name) number = parse(string, territory_name) number.international_string if number diff --git a/lib/global_phone/database.rb b/lib/global_phone/database.rb index a1f27a3..a4fd197 100644 --- a/lib/global_phone/database.rb +++ b/lib/global_phone/database.rb @@ -1,26 +1,38 @@ -require 'global_phone/parsing' +require 'json' require 'global_phone/region' module GlobalPhone class Database - include Parsing + attr_reader :regions def self.load_file(filename) load(File.read(filename)) end def self.load(json) - require 'json' new(JSON.parse(json)) end - attr_reader :regions - def initialize(record_data) @regions = record_data.map { |data| Region.new(data) } @territories_by_name = {} end + def parse(string, territory_name) + string = Number.normalize(string) + territory = self.territory(territory_name) + raise ArgumentError, "unknown territory `#{territory_name}'" unless territory + + if starts_with_plus?(string) + parse_international_string(string) + elsif string =~ territory.international_prefix + string = strip_international_prefix(territory, string) + parse_international_string(string) + else + territory.parse_national_string(string) + end + end + def region(country_code) regions_by_country_code[country_code.to_s] end @@ -36,13 +48,51 @@ def inspect "#<#{self.class.name}>" end - protected - def regions_by_country_code - @regions_by_country_code ||= Hash[*regions.map { |r| [r.country_code, r] }.flatten] + def region_for_country_code(string) + country_code_candidates_for(strip_leading_plus(string)).each do |country_code| + if found_region = region(country_code) + return found_region + end + end + nil + end + + private + + def parse_international_string(string) + string = strip_leading_plus(Number.normalize(string)) + + if region = region_for_country_code(string) + region.parse_national_string(string) end + end + + def starts_with_plus?(string) + string[0, 1] == "+" + end - def region_for_territory(name) - regions.find { |r| r.has_territory?(name) } + def strip_leading_plus(string) + if starts_with_plus?(string) + string[1..-1] + else + string end + end + + def strip_international_prefix(territory, string) + string.sub(territory.international_prefix, "") + end + + def country_code_candidates_for(string) + (1..3).map { |length| string[0, length] } + end + + def regions_by_country_code + @regions_by_country_code ||= Hash[*regions.map { |r| [r.country_code, r] }.flatten] + end + + def region_for_territory(name) + regions.find { |r| r.has_territory?(name) } + end end end diff --git a/lib/global_phone/database_generator.rb b/lib/global_phone/database_generator.rb index 959edad..de49393 100644 --- a/lib/global_phone/database_generator.rb +++ b/lib/global_phone/database_generator.rb @@ -35,7 +35,7 @@ def inspect "#<#{self.class.name} (#{doc.search("*").size} elements)>" end - protected + private def territory_nodes doc.search("territory") end diff --git a/lib/global_phone/number.rb b/lib/global_phone/number.rb index 7f209a5..71f78e6 100644 --- a/lib/global_phone/number.rb +++ b/lib/global_phone/number.rb @@ -65,7 +65,7 @@ def to_s international_string end - protected + private def format @format ||= find_format_for(national_string) end diff --git a/lib/global_phone/parsing.rb b/lib/global_phone/parsing.rb deleted file mode 100644 index 1aa88b0..0000000 --- a/lib/global_phone/parsing.rb +++ /dev/null @@ -1,52 +0,0 @@ -require 'global_phone/number' -require 'global_phone/utils' - -module GlobalPhone - module Parsing - def parse(string, territory_name) - string = Number.normalize(string) - territory = self.territory(territory_name) - raise ArgumentError, "unknown territory `#{territory_name}'" unless territory - - if starts_with_plus?(string) - parse_international_string(string) - elsif string =~ territory.international_prefix - string = strip_international_prefix(territory, string) - parse_international_string(string) - else - territory.parse_national_string(string) - end - end - - def parse_international_string(string) - string = Number.normalize(string) - string = strip_leading_plus(string) if starts_with_plus?(string) - - if region = region_for_string(string) - region.parse_national_string(string) - end - end - - protected - def starts_with_plus?(string) - string[0, 1] == "+" - end - - def strip_leading_plus(string) - string[1..-1] - end - - def strip_international_prefix(territory, string) - string.sub(territory.international_prefix, "") - end - - def region_for_string(string) - candidates = country_code_candidates_for(string) - Utils.map_detect(candidates) { |country_code| region(country_code) } - end - - def country_code_candidates_for(string) - (1..3).map { |length| string[0, length] } - end - end -end diff --git a/lib/global_phone/region.rb b/lib/global_phone/region.rb index 813ec37..83f9772 100644 --- a/lib/global_phone/region.rb +++ b/lib/global_phone/region.rb @@ -1,7 +1,6 @@ require 'global_phone/format' require 'global_phone/record' require 'global_phone/territory' -require 'global_phone/utils' module GlobalPhone class Region < Record @@ -23,7 +22,7 @@ def territories def territory(name) name = name.to_s.upcase - territories.detect { |region| region.name == name } + territories.detect { |territory| territory.name == name } end def has_territory?(name) @@ -38,11 +37,15 @@ def parse_national_string(string) end end + def territory_for_contry_code + territories.first + end + def inspect "#<#{self.class.name} country_code=#{country_code} territories=[#{territory_names.join(",")}]>" end - protected + private def territory_names territory_record_data.map(&:first) end diff --git a/lib/global_phone/territory.rb b/lib/global_phone/territory.rb index 3dd95b0..514e051 100644 --- a/lib/global_phone/territory.rb +++ b/lib/global_phone/territory.rb @@ -30,7 +30,7 @@ def inspect "#<#{self.class.name} country_code=#{country_code} name=#{name}>" end - protected + private def strip_prefixes(string) if national_prefix_for_parsing transform_rule = national_prefix_transform_rule || "" diff --git a/lib/global_phone/utils.rb b/lib/global_phone/utils.rb deleted file mode 100644 index 778203e..0000000 --- a/lib/global_phone/utils.rb +++ /dev/null @@ -1,14 +0,0 @@ -module GlobalPhone - module Utils - extend self - - def map_detect(collection) - collection.each do |value| - if result = yield(value) - return result - end - end - nil - end - end -end diff --git a/test/context_test.rb b/test/context_test.rb index 637b62d..b84b58c 100644 --- a/test/context_test.rb +++ b/test/context_test.rb @@ -71,11 +71,33 @@ class ContextTest < TestCase assert_nil context.validate("+0651816068") end + test 'finding region by string' do + assert_found_territory_for_country_code('1', {country_code: '1', country_name: 'US'}) + assert_found_territory_for_country_code('+1', {country_code: '1', country_name: 'US'}) + assert_found_territory_for_country_code('131', {country_code: '1', country_name: 'US'}) + assert_found_territory_for_country_code('+375', {country_code: '375', country_name: 'BY'}) + + assert_not_found_territory_for_country_code('+9') + end + def assert_parses(string, assertions) territory_name = assertions.delete(:with_territory) || context.default_territory_name number = context.parse(string, territory_name) assert_kind_of Number, number - assert_equal({ :country_code => number.country_code, :national_string => number.national_string }, assertions) + assert_equal(assertions, + { :country_code => number.country_code, :national_string => number.national_string }) + end + + def assert_found_territory_for_country_code(string, assertions) + territory = context.territory_for_country_code(string) + + assert_equal(assertions, {country_code: territory.country_code, country_name: territory.name}) + end + + def assert_not_found_territory_for_country_code(string) + territory = context.territory_for_country_code(string) + + assert_nil territory end def assert_does_not_parse(string, options = {})