phoney 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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