phoney 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 91ea215316dbde0a1e0ab7c0a8ee480c17021db9264ad5949f20ad87a9fb01c2
4
+ data.tar.gz: 8010af03683d901660a83ecd03a2b8fa6ff9e5e4ae19ce50a7c74b04d33f20ab
5
+ SHA512:
6
+ metadata.gz: 9803f88389d58b814d942589496dbca4e74b3891066c8501f375e2a6ebc6c5a97dc946f91287f5867d5a8f48a2fce8e31149ad2ca08db3abe3790a4280047d29
7
+ data.tar.gz: b8a687dcb6fbf2d00d4f4491aa36eb5d74a7ba45c2ec466ed48fba9000fbd3f3183a16ae3218e06dbcb8fbb9356b8d38f0908d18f1bbeeec9b157a378c5133a4
data/Gemfile CHANGED
@@ -1,6 +1,2 @@
1
1
  source "http://rubygems.org"
2
-
3
- gemspec
4
-
5
- # To use debugger
6
- # gem 'debugger'
2
+ gemspec
@@ -1,26 +1,18 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- phoney (0.1.3)
4
+ phoney (0.9.9)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
8
8
  specs:
9
- diff-lcs (1.1.3)
9
+ minitest (4.6.2)
10
10
  rake (0.9.2.2)
11
- rspec (2.11.0)
12
- rspec-core (~> 2.11.0)
13
- rspec-expectations (~> 2.11.0)
14
- rspec-mocks (~> 2.11.0)
15
- rspec-core (2.11.1)
16
- rspec-expectations (2.11.2)
17
- diff-lcs (~> 1.1.3)
18
- rspec-mocks (2.11.2)
19
11
 
20
12
  PLATFORMS
21
13
  ruby
22
14
 
23
15
  DEPENDENCIES
16
+ minitest
24
17
  phoney!
25
18
  rake
26
- rspec (= 2.11.0)
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Jan Habermann
1
+ Copyright (c) 2013 Jan Habermann
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -1,7 +1,7 @@
1
1
  = phoney
2
2
 
3
3
  This is a library for representing phone numbers.
4
- It provides a PhoneNumber class that can format phone numbers depending on the region you set.
4
+ It provides a Phoney class that can format phone numbers depending on the region you set.
5
5
 
6
6
  == Installation
7
7
 
@@ -14,7 +14,7 @@ Source:: <tt>git clone git://github.com/habermann24/phoney.git</tt>
14
14
 
15
15
  require 'phoney'
16
16
  # region defaults to US
17
- pn = PhoneNumber.new("+17041234567")
17
+ pn = Phoney.new("+17041234567")
18
18
  pn.to_s # "+1 (704) 123-4567"
19
19
  pn.area_code # "704"
20
20
  pn.country_code # "1"
@@ -24,30 +24,30 @@ Source:: <tt>git clone git://github.com/habermann24/phoney.git</tt>
24
24
 
25
25
  require 'phoney'
26
26
 
27
- PhoneNumber.default_region = :de
27
+ Phoney.region = :de
28
28
 
29
- pn = PhoneNumber.new("04105456789")
29
+ pn = Phoney.new("04105456789")
30
30
  pn.to_s # "+49 4105 456789"
31
31
  pn.area_code # "4105"
32
32
  pn.country_code # "49"
33
33
  pn.number # "456789"
34
34
 
35
- == Creating PhoneNumber instances
35
+ == Creating Phoney instances
36
36
 
37
- Phoney gives you a PhoneNumber class that wraps all the logic of phone number parsing and representation.
38
- The default region phoney uses for formatting is the US-region format. So if you want to parse phone numbers from a different country, you have to set PhoneNumber.default_region or pass the region code every time!
37
+ Phoney gives you a Phoney class that wraps all the logic of phone number parsing and representation.
38
+ The default region phoney uses for formatting is the US-region format. So if you want to parse phone numbers from a different country, you have to set Phoney.region or pass the region code every time!
39
39
 
40
- PhoneNumber.default_region = :us
40
+ Phoney.region = :us
41
41
 
42
- The most common way to create a PhoneNumber object is by parsing from a string:
43
- PhoneNumber.new("7041231234") # uses region :us
44
- PhoneNumber.new("01805708090", :de) # uses region :de
42
+ The most common way to create a Phoney object is by parsing from a string:
43
+ Phoney.new("7041231234") # uses region :us
44
+ Phoney.new("01805708090", :de) # uses region :de
45
45
 
46
46
  Or instead of parsing a string, you can provide a hash for the first parameter:
47
- PhoneNumber.new(:number => "1231234", :area_code => "704", :country_code => "1")
47
+ Phoney.new(:number => "1231234", :area_code => "704", :country_code => "1")
48
48
 
49
49
  # falls back to US region, so also uses "1" for <tt>country_code</tt>
50
- PhoneNumber.new(:number => "1231234", :area_code => "704")
50
+ Phoney.new(:number => "1231234", :area_code => "704")
51
51
 
52
52
  == Formatting
53
53
 
@@ -59,13 +59,13 @@ When given a string, it interpolates the string with the following fields:
59
59
  * %a - area_code (91)
60
60
  * %n - number (5125486)
61
61
 
62
- pn = PhoneNumber.new('+446546546546')
62
+ pn = Phoney.new('+446546546546')
63
63
 
64
64
  pn.to_s # => "+44 65 4654 6546"
65
65
  pn.format("%a/%n") # => "64/46546546"
66
66
  pn.format("+ %c (%a) %n") # => "+ 44 (65) 46546546"
67
67
 
68
- Usually you will just want PhoneNumber to figure out how to format the number correctly.
68
+ Usually you will just want Phoney to figure out how to format the number correctly.
69
69
  When given a symbol you can let the parser guess the best format and pass in one of the following auto-formatting symbols:
70
70
  pn.format(:default) # => "+44 65 4654 6546"
71
71
 
@@ -77,8 +77,4 @@ When given a symbol you can let the parser guess the best format and pass in one
77
77
 
78
78
  == TODOs
79
79
 
80
- - More test specs for different countries
81
-
82
- == Licence
83
-
84
- see LICENSE
80
+ - More tests for different countries
data/Rakefile CHANGED
@@ -1,29 +1,13 @@
1
- #!/usr/bin/env rake
2
- begin
3
- require 'bundler/setup'
4
- rescue LoadError
5
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
- end
7
-
8
- require 'rdoc/task'
9
-
10
- Rake::RDocTask.new do |rdoc|
11
- rdoc.rdoc_dir = 'doc/rdoc'
12
- rdoc.template = ENV['template'] if ENV['template']
13
- rdoc.title = "Phoney Documentation"
14
- rdoc.options << '--line-numbers' << '--inline-source'
15
- rdoc.options << '--charset' << 'utf-8'
16
- rdoc.rdoc_files.include('README.rdoc')
17
- rdoc.rdoc_files.include('lib/**/*.rb')
18
- end
19
-
20
- require 'rspec/core/rake_task'
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'rake'
4
+ require 'rake/testtask'
21
5
 
22
- desc 'Default: run specs.'
23
- task :default => :spec
6
+ task :default => :test
24
7
 
25
- RSpec::Core::RakeTask.new do |t|
26
- t.pattern = "./spec/**/*_spec.rb"
8
+ Rake::TestTask.new do |t|
9
+ t.libs << 'test/lib'
10
+ t.pattern = 'test/**/*_test.rb'
27
11
  end
28
12
 
29
- Bundler::GemHelper.install_tasks
13
+ Dir.glob('resources/tasks/*.rake').each { |r| import r }
Binary file
@@ -1,8 +1,105 @@
1
- require File.join(File.dirname(__FILE__), 'phoney', 'version')
2
- require File.join(File.dirname(__FILE__), 'phoney', 'utils')
3
- require File.join(File.dirname(__FILE__), 'phoney', 'region')
4
- require File.join(File.dirname(__FILE__), 'phoney', 'parser')
5
- require File.join(File.dirname(__FILE__), 'phoney', 'base')
1
+ require 'phoney/version'
2
+ require 'phoney/rules'
3
+ require 'phoney/region'
4
+ require 'phoney/formatter'
5
+ require 'phoney/parser'
6
+
7
+ module Phoney
8
+ PLACEHOLDER_CHAR = '#'
9
+ DIGITS = '0123456789'
10
+ NUMPAD_CHARS = '+#*'+DIGITS
11
+
12
+ class << self
13
+ def region
14
+ @region ||= Region[:us]
15
+ end
16
+
17
+ def region=(region)
18
+ @region = Region[region.to_s.to_sym]
19
+ end
20
+
21
+ def country_code
22
+ @country_code ||= region.country_code.to_s
23
+ end
24
+
25
+ def area_code
26
+ @area_code ||= nil
27
+ end
28
+
29
+ def area_code=(area_code)
30
+ @area_code = area_code
31
+ end
32
+
33
+ def version
34
+ VERSION::STRING
35
+ end
36
+ end
37
+
38
+ def initialize(params, region_code=nil)
39
+ region = Region.find(region_code)
40
+ country_code = region.country_code.to_s if region
41
+
42
+ if params.is_a?(String)
43
+ params = Parser.parse_to_parts(params, region_code)
44
+ end
45
+
46
+ self.number = params[:number].to_s
47
+ # The rare case when some digits are in front of the area code
48
+ self.prefix_code = params[:prefix_code].to_s
49
+ # Can be empty, because some special numbers just don't have an area code (e.g. 911)
50
+ self.area_code = params[:area_code].to_s || self.class.area_code
51
+ self.country_code = params[:country_code].to_s || country_code || self.class.country_code
52
+
53
+ raise "Must enter number" if(self.number.nil? || self.number.empty?)
54
+ raise "Must enter country code or set default country code" if(self.country_code.nil? || self.country_code.empty?)
55
+ end
56
+
57
+ # Does this number belong to the default country code?
58
+ def has_default_country_code?
59
+ country_code.to_s == self.class.country_code.to_s
60
+ end
61
+
62
+ # Does this number belong to the default area code?
63
+ def has_default_area_code?
64
+ (!area_code.to_s.empty? && area_code.to_s == self.class.area_code.to_s)
65
+ end
66
+
67
+ # Formats the phone number.
68
+ # If the method argument is a String, it is used as a format string, with the following fields being interpolated:
69
+ #
70
+ # * %c - country_code (385)
71
+ # * %a - area_code (91)
72
+ # * %n - number (5125486)
73
+ #
74
+ # If the method argument is a Symbol, we use one of the default formattings and let the parser do the rest.
75
+ def format(fmt)
76
+ if fmt.is_a?(Symbol)
77
+ case fmt
78
+ when :default
79
+ Parser::parse("+#{country_code} #{prefix_code}#{area_code} #{number}", country_code)
80
+ when :national
81
+ Parser::parse("#{area_code} #{number}", country_code)
82
+ when :local
83
+ STDERR.puts "Warning: Using local format without setting a default area code!?" if Phoney.area_code.nil?
84
+ Parser::parse(number, country_code)
85
+ else
86
+ raise "The format #{fmt} doesn't exist'"
87
+ end
88
+ else
89
+ format_number(fmt)
90
+ end
91
+ end
92
+
93
+ # The default format is the canonical format: "+{country_code} {area_code} {number}"
94
+ def to_s
95
+ format(:default)
96
+ end
97
+
98
+ private
99
+ def format_number(fmt)
100
+ fmt.gsub("%c", country_code || "").gsub("%a", area_code || "").gsub("%n", number || "")
101
+ end
102
+ end
6
103
 
7
104
  # Load our region file when we require the library
8
- PhoneNumber::Region.load
105
+ Phoney::Region.load
@@ -0,0 +1,144 @@
1
+ module Phoney
2
+ module Formatter
3
+ # Returns the string formatted according to a pattern.
4
+ #
5
+ # Examples:
6
+ # format('123456789', 'XXX-XX-XXXX')
7
+ # => "123-45-6789"
8
+ # format('12345', 'XXX-XX-XXXX')
9
+ # => "123-45"
10
+ #
11
+ # Parameters:
12
+ # string -- The string to be formatted.
13
+ # pattern -- The format string, see above examples.
14
+ # fill -- A string for padding. If the empty string, then the pattern is
15
+ # filled as much as possible, and the rest of the pattern is
16
+ # truncated. If nil, and the string is too long for the pattern,
17
+ # the string is returned unchanged. Otherwise, the string is
18
+ # padded to fill the pattern, which is not truncated.
19
+ def format(input, pattern, options={})
20
+ fill = options[:fill]
21
+ intl_prefix = options[:intl_prefix]||''
22
+ trunk_prefix = options[:trunk_prefix]||''
23
+ slots = pattern.count(PLACEHOLDER_CHAR)
24
+
25
+ # Return original input if it is too long
26
+ return input if (fill.nil? && input.length > slots)
27
+
28
+ # Pad and clone the string if necessary.
29
+ source = (fill.nil? || fill.empty?) ? input : input.ljust(slots, fill)
30
+
31
+ result = ''
32
+ slot = 0
33
+ has_open = had_c = had_n = false
34
+
35
+ pattern.split('').each_with_index do |chr, index|
36
+ case chr
37
+ when 'c'
38
+ had_c = true
39
+ result << intl_prefix
40
+ when 'n'
41
+ had_n = true
42
+ result << trunk_prefix
43
+ when '#'
44
+ if slot < source.length
45
+ result << source[slot]
46
+ slot += 1
47
+ else
48
+ result << ' ' if has_open
49
+ end
50
+ when '('
51
+ if slot < source.length
52
+ has_open = true
53
+ result << chr
54
+ end
55
+ when ')'
56
+ if (slot < source.length || has_open)
57
+ has_open = false
58
+ result << chr
59
+ end
60
+ else
61
+ # Don't show space after n if no trunk prefix or after c if no intl prefix
62
+ next if (chr == ' ' && pattern[index-1] == 'n' && trunk_prefix.empty?)
63
+ next if (chr == ' ' && pattern[index-1] == 'c' && intl_prefix.empty?)
64
+
65
+ result << chr if (slot < source.length)
66
+ end
67
+ end
68
+
69
+ # Not all format strings have a 'c' or 'n' in them.
70
+ # If we have an international prefix or a trunk prefix but the format string
71
+ # doesn't explictly say where to put it then simply add it to the beginning.
72
+ result.prepend trunk_prefix if (!had_n && !trunk_prefix.empty?)
73
+ result.prepend "#{intl_prefix} " if (!had_c && !intl_prefix.empty?)
74
+
75
+ result.strip
76
+ end
77
+
78
+ # Strips all non-numberpad characters from a string
79
+ # => For example: "+45 (123) 023 1.1.1" -> "+45123023111"
80
+ def normalize(str)
81
+ str.gsub(/[^0-9+*#]/,'') unless str.nil?
82
+ end
83
+
84
+ def international_call_prefix_for(input, options={})
85
+ options[:region] ||= Phoney.region
86
+
87
+ return nil if input.length == 0
88
+
89
+ options[:region].dialout_prefixes.each do |prefix|
90
+ stripped_prefix = Regexp.escape prefix.delete(' ').split('->').first[0, input.length]
91
+ regexp = Regexp.new "^#{stripped_prefix.gsub('\\#', '[0-9]')}"
92
+
93
+ return format(input, prefix.gsub(/[\\+0-9]/, '#'), fill: '') if input =~ regexp
94
+
95
+ if (input.start_with?('+') && (stripped_prefix.start_with?(input[1..-1]) || input[1..-1] =~ regexp))
96
+ return format(input, '#'+prefix.gsub(/[\\+0-9]/, '#'), fill: '')
97
+ end
98
+ end
99
+
100
+ input.start_with?('+') ? '+' : nil
101
+ end
102
+
103
+ # TODO: handle case where international call prefix implicitly specifies country (e.g. tz: "005->254")
104
+ def extract_country_code(input, options={})
105
+ options[:region] ||= Phoney.region
106
+ intl_prefix = international_call_prefix_for(input, region: options[:region])
107
+
108
+ # only try to extract a country code if we're dialing internationally
109
+ if intl_prefix
110
+ rest = input[intl_prefix.count(NUMPAD_CHARS)..-1]
111
+ region = Phoney::Region.all.find { |r| rest.start_with? r.country_code.to_s }
112
+
113
+ region.country_code.to_s if region
114
+ end
115
+ end
116
+
117
+ def extract_trunk_prefix(input, options={})
118
+ options[:region] ||= Phoney.region
119
+
120
+ intl_prefix = international_call_prefix_for input
121
+ country_code = extract_country_code(input, region: options[:region])
122
+ region_scope = country_code.nil? ? options[:region] : Phoney::Region[country_code]
123
+
124
+ if intl_prefix
125
+ # Strip international prefix from number
126
+ input = input[intl_prefix.count(NUMPAD_CHARS)..-1]
127
+ end
128
+
129
+ if country_code
130
+ # Strip country code from number
131
+ input = input[country_code.count(DIGITS)..-1]
132
+ end
133
+
134
+ region_scope.trunk_prefixes.each do |prefix|
135
+ stripped_prefix = Regexp.escape prefix.delete(' ')
136
+ regexp = Regexp.new "^#{stripped_prefix.gsub('\\#', '[0-9]')}"
137
+
138
+ return format(input, prefix.gsub(/[0-9]/, '#'), fill: '') if input =~ regexp
139
+ end
140
+
141
+ return nil
142
+ end
143
+ end
144
+ end
@@ -1,245 +1,89 @@
1
1
  require 'strscan'
2
2
 
3
- class PhoneNumber
4
-
3
+ module Phoney
5
4
  module Parser
6
5
  class << self
7
- include Utils
8
-
9
- def parse(phone_number, region_code=nil)
10
- parse_to_parts(phone_number, region_code)[:formatted_number]
11
- end
6
+ include Formatter
12
7
 
13
- def parse_to_parts(phone_number, region_code=nil)
14
- phone_number = normalize(phone_number.to_s)
15
-
16
- # we don't really need to do anything unless we get more input
17
- unless phone_number.length > 1
18
- return { :formatted_number => phone_number, :number => normalize(phone_number) }
19
- end
20
-
21
- region = Region.find(region_code) || PhoneNumber.default_region
22
- country_code = region.country_code.to_s
23
- prefix_code = nil
24
- area_code = nil
25
-
26
- dialout_prefix = get_dialout_prefix(phone_number, region)
27
- national_prefix = get_national_prefix(phone_number, region)
28
- dialout_region = get_dialout_region(phone_number, region)
29
- dialout_country = ''
30
-
31
- # No dialout prefix without a dialout region, and no dialout region without a prefix
32
- if((dialout_region && dialout_prefix.empty?) || (!dialout_region && !dialout_prefix.empty?))
33
- rule_sets = []
34
- else
35
- rule_sets = get_rule_sets_for_region(phone_number, dialout_region || region)
8
+ def parse(input, options={})
9
+ number = normalize(input)
10
+ intl_prefix = international_call_prefix_for number
11
+ country_code = extract_country_code number
12
+ trunk_prefix = extract_trunk_prefix number
13
+ region = options[:region] || Phoney.region
14
+ flags = []
15
+
16
+ if intl_prefix
17
+ # Strip international prefix from number
18
+ number = number[intl_prefix.count(NUMPAD_CHARS)..-1]
19
+ region = Phoney::Region[country_code]
20
+ flags << :c
36
21
  end
37
22
 
38
- # build our total prefix
39
- if dialout_region
40
- prefix = dialout_prefix.delete(' ') + dialout_region.country_code.to_s
41
- country_code = dialout_region.country_code.to_s
42
- dialout_country = country_code
43
- else
44
- prefix = national_prefix
45
- prefix += dialout_prefix.delete(' ') unless(dialout_prefix.empty?)
46
- end
47
-
48
- # strip the total prefix from the beginning of the number
49
- phone_number = phone_number[prefix.length..-1]
50
- number = phone_number
51
-
52
- prefered_type = 0 # for sorting the priority
53
-
54
- # if we're dialing out or using the national prefix
55
- if(dialout_region || !national_prefix.empty?)
56
- # we need to sort the rules slightly different
57
- prefered_type = dialout_region.nil? ? 1 : 2
58
- end
59
-
60
- # sorting for rule priorities
61
- rule_sets.each do |rule_set|
62
- rule_set[:rules] = rule_set[:rules].sort_by do |rule|
63
- # [ prefered rule type ASC, total_digits ASC ]
64
- [ (rule[:type]==prefered_type) ? -1 : rule[:type], rule[:total_digits], rule[:index] ]
65
- end
66
- end
67
-
68
- # finally...find our matching rule
69
- matching_rule = find_matching_rule(phone_number, rule_sets)
70
-
71
- # now that know how to format the number, do the formatting work...
72
- if(matching_rule)
73
- if(matching_rule[:areacode_offset] > 0)
74
- prefix_code = phone_number[0, matching_rule[:areacode_offset]]
75
- end
76
- area_code = phone_number[matching_rule[:areacode_offset], matching_rule[:areacode_length]]
77
- number = phone_number[matching_rule[:areacode_offset]+matching_rule[:areacode_length]..-1]
78
- phone_number = format(phone_number, matching_rule[:format].to_s)
79
-
80
- # replace 'n' with our national_prefix if it exists
81
- if(phone_number[/n/])
82
- phone_number.gsub!(/n{1}/, national_prefix)
83
-
84
- # reset the national_prefix so we don't add it twice
85
- national_prefix = ''
86
- end
87
- end
23
+ if country_code
24
+ # Strip country code from number
25
+ number = number[country_code.count(DIGITS)..-1]
88
26
 
89
- # strip possible whitespace from the left
90
- phone_number.lstrip!
91
-
92
- if(matching_rule && phone_number[/c/])
93
- # format the country code
94
- if(dialout_prefix == '+')
95
- phone_number.gsub!(/c{1}/, "+#{dialout_country}")
27
+ if intl_prefix == '+'
28
+ intl_prefix += country_code
96
29
  else
97
- phone_number.gsub!(/c{1}/, dialout_country)
98
- phone_number = "#{dialout_prefix} #{phone_number}" unless dialout_prefix.empty?
99
- end
100
- else
101
- # default formatting
102
- if(dialout_prefix == '+')
103
- if(dialout_country.empty?)
104
- phone_number = "+#{phone_number}"
105
- else
106
- phone_number = "+#{dialout_country} #{phone_number}"
107
- end
108
- else
109
- phone_number = "#{dialout_country} #{phone_number}" unless dialout_country.empty?
110
- phone_number = "#{dialout_prefix} #{phone_number}" unless dialout_prefix.empty?
111
- phone_number = national_prefix + phone_number unless national_prefix.empty?
30
+ intl_prefix = [intl_prefix, country_code].join(' ')
112
31
  end
113
32
  end
114
33
 
115
- # strip possible whitespace
116
- phone_number.rstrip!
117
- phone_number.lstrip!
118
- # remove possible non-numeric characters from the (invalid) number
119
- number.gsub!(/[^0-9]/,'') if number
120
-
121
- # Finally...we can output our parts as a hash
122
- { :formatted_number => phone_number,
123
- :prefix_code => prefix_code,
124
- :area_code => area_code,
125
- :country_code => country_code,
126
- :number => number }
127
- end
128
-
129
- private
130
- # Returns the rule sets that we need to check for a given number and region.
131
- # The rule_sets are filtered by the length of the number!
132
- def get_rule_sets_for_region(string, region)
133
- rule_sets = []
34
+ rule = find_matching_rule_for number, region: region, flags: flags
35
+ rule ||= find_matching_rule_for number, region: region
36
+ return format number, rule.pattern, intl_prefix: intl_prefix if rule
134
37
 
135
- if(region && region.rule_sets)
136
- rule_sets = region.rule_sets.select do |rule_set|
137
- rule_set[:digits] <= string.length
38
+ if trunk_prefix
39
+ # Strip trunk prefix from number
40
+ number = number[trunk_prefix.count(DIGITS)..-1]
41
+ flags << :n
42
+
43
+ if intl_prefix
44
+ intl_prefix += " (#{trunk_prefix})"
45
+ trunk_prefix = nil
138
46
  end
139
47
  end
140
48
 
141
- rule_sets
142
- end
143
-
144
- # Given any number, find the rule in rule_sets that applies.
145
- # Returns nil if no matching rule was found!
146
- def find_matching_rule(number, rule_sets)
147
- return nil if !number.match(/\A[0-9]+\Z/)
148
- match = nil
149
-
150
- # go through all our given rules
151
- for rule_set in rule_sets do
152
- digits = rule_set[:digits]
153
- prefix = number[0,digits].to_i
154
- rules = rule_set[:rules].select { |rule| rule[:total_digits] >= number.length }
155
-
156
- rules.each do |rule|
157
- if(prefix >= rule[:min] && prefix <= rule[:max])
158
- match = rule
159
- break
160
- end
161
- end
49
+ if country_code || intl_prefix != '+'
50
+ rule = find_matching_rule_for number, region: region, flags: flags
51
+ rule ||= find_matching_rule_for number, region: region
162
52
 
163
- break if match
53
+ pattern = '#'*number.length
54
+ pattern = rule.pattern if rule
55
+
56
+ format number, pattern, intl_prefix: intl_prefix, trunk_prefix: trunk_prefix
57
+ else
58
+ input
164
59
  end
165
-
166
- match
167
- end
168
-
169
- # According to the region, is this number input trying to dial out?
170
- def dialing_out?(string, region=nil)
171
- region ||= PhoneNumber.default_region
172
- !get_dialout_prefix(string, region).empty?
173
60
  end
174
61
 
175
- # Get the dialout prefix from the given string.
176
- # Returns an empty string if no dialout prefix was found.
177
- def get_dialout_prefix(string, region=nil)
178
- region ||= PhoneNumber.default_region
179
- prefixes = region.dialout_prefixes
180
- dialout_prefix = ''
181
-
182
- # check if we're dialing outside our region
183
- if string[0].chr == '+'
184
- dialout_prefix = '+'
185
- end
186
-
187
- for prefix in prefixes do
188
- regexp = Regexp.escape(prefix)
189
- match_str = string
62
+ private
63
+ def find_matching_rule_for(number, options={})
64
+ options[:region] ||= Region.new
190
65
 
191
- # we have matching wild cards
192
- if(prefix[/X/] && string =~ Regexp.new("^#{Regexp.escape(prefix.delete('X '))}"))
193
- regexp.gsub!(/X/, "[0-9]{0,1}")
194
- match_str = format(string[prefix.scan(/[0-9]/).size, prefix.count('X')], prefix)
195
- prefix = match_str
196
- end
66
+ # Consider all rule sets that aren't too specific for the number
67
+ options[:region].rule_sets.select { |r| number.length >= r.significant_digits }.each do |rule_set|
68
+ rules = rule_set.rules
69
+
70
+ # Only consider rules with :c flag if this flag is set
71
+ if options[:flags] && options[:flags].include?(:c)
72
+ rules = rules.reject { |r| !r.flags.include? :c }
73
+ else
74
+ # Only consider rules with :n flag if this flag is set
75
+ if options[:flags] && options[:flags].include?(:n)
76
+ rules = rules.reject { |r| !r.flags.include? :n }
77
+ end
78
+ end
197
79
 
198
- if(match_str =~ Regexp.new("^#{regexp}"))
199
- dialout_prefix = prefix
200
- break
201
- end
202
- end
203
-
204
- dialout_prefix
205
- end
206
-
207
- # Get the national prefix from the given string.
208
- # Returns an empty string if no national prefix was found.
209
- def get_national_prefix(string, region=nil)
210
- region ||= PhoneNumber.default_region
211
- prefix = region.national_prefix
212
- national_prefix = ''
213
-
214
- # in case we're not dialing out and the number starts with the national_prefix
215
- if(!dialing_out?(string, region) && string =~ Regexp.new("^#{Regexp.escape(prefix)}"))
216
- national_prefix = prefix
217
- end
218
-
219
- national_prefix
220
- end
221
-
222
- # Get the dialout region by looking at the string.
223
- # Returns a Region object if we're dialing outside a region that is supported.
224
- # Otherwise returns nil.
225
- def get_dialout_region(string, region)
226
- region ||= PhoneNumber.default_region
227
- dialout_prefix = get_dialout_prefix(string, region)
228
- dialout_region = nil
229
-
230
- unless dialout_prefix.empty?
231
- # region codes are 1 to 3 digits
232
- range_end = [string.length-dialout_prefix.delete(' ').length, 3].min
233
-
234
- (1..range_end).each do |i|
235
- dialout_region = Region.find(string[dialout_prefix.delete(' ').length, i])
236
- break if dialout_region
80
+ # Find and return the first rule that matches
81
+ matching_rule = rules.find { |rule| rule.matches? number }
82
+ return matching_rule unless matching_rule.nil?
237
83
  end
84
+
85
+ return nil
238
86
  end
239
-
240
- dialout_region
241
- end
242
87
  end
243
88
  end
244
-
245
89
  end