telephone_number 1.1.1 → 1.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ class TelephoneNumberValidator < ActiveModel::EachValidator
2
+ def validate_each(record, attribute, value)
3
+ country = options[:country].call(record) if options.key?(:country)
4
+ valid_types = options.fetch(:types, [])
5
+ args = [value, country, valid_types]
6
+
7
+ record.errors.add(attribute, :invalid) if TelephoneNumber.invalid?(*args)
8
+ end
9
+ end
@@ -1,10 +1,17 @@
1
1
  module TelephoneNumber
2
2
  module ClassMethods
3
- def parse(number, country = Parser.detect_country(number))
4
- TelephoneNumber::Number.new(number, country)
3
+ attr_accessor :override_file, :default_format_string
4
+ attr_reader :default_format_pattern
5
+
6
+ def default_format_pattern=(format_string)
7
+ @default_format_pattern = Regexp.new(format_string)
8
+ end
9
+
10
+ def parse(number, country = detect_country(number))
11
+ TelephoneNumber::Number.new(sanitize(number), country)
5
12
  end
6
13
 
7
- def valid?(number, country = Parser.detect_country(number), keys = [])
14
+ def valid?(number, country = detect_country(number), keys = [])
8
15
  parse(number, country).valid?(keys)
9
16
  end
10
17
 
@@ -12,6 +19,19 @@ module TelephoneNumber
12
19
  !valid?(*args)
13
20
  end
14
21
 
22
+ def sanitize(input_number)
23
+ input_number.to_s.gsub(/\D/, '')
24
+ end
25
+
26
+ def detect_country(number)
27
+ sanitized_number = sanitize(number)
28
+ detected_country = Country.all_countries.detect do |country|
29
+ sanitized_number.start_with?(country.country_code) && valid?(sanitized_number, country.country_id)
30
+ end
31
+
32
+ detected_country.country_id.to_sym if detected_country
33
+ end
34
+
15
35
  # generates binary file from xml that user gives us
16
36
  def generate_override_file(file)
17
37
  DataImporter.new(file, override: true).import!
@@ -0,0 +1,67 @@
1
+ module TelephoneNumber
2
+ class Country
3
+ attr_reader :country_code, :national_prefix, :national_prefix_formatting_rule,
4
+ :national_prefix_for_parsing, :national_prefix_transform_rule, :international_prefix,
5
+ :formats, :validations, :mobile_token, :country_id, :general_validation, :main_country_for_code
6
+
7
+ MOBILE_TOKEN_COUNTRIES = { AR: '9' }
8
+
9
+ def initialize(data_hash)
10
+ @country_code = data_hash[:country_code]
11
+ @country_id = data_hash[:id]
12
+ @formats = data_hash.fetch(:formats, []).map { |format| NumberFormat.new(format) }
13
+ @general_validation = NumberValidation.new(:general_desc, data_hash[:validations][:general_desc]) if data_hash.fetch(:validations, {})[:general_desc]
14
+ @international_prefix = Regexp.new(data_hash[:international_prefix]) if data_hash[:international_prefix]
15
+ @main_country_for_code = data_hash[:main_country_for_code] == 'true'
16
+ @mobile_token = MOBILE_TOKEN_COUNTRIES[@country_id.to_sym]
17
+ @national_prefix = data_hash[:national_prefix]
18
+ @national_prefix_formatting_rule = data_hash[:national_prefix_formatting_rule]
19
+ @national_prefix_for_parsing = Regexp.new(data_hash[:national_prefix_for_parsing]) if data_hash[:national_prefix_for_parsing]
20
+ @national_prefix_transform_rule = data_hash[:national_prefix_transform_rule]
21
+ @validations = data_hash.fetch(:validations, {})
22
+ .except(:general_desc, :area_code_optional)
23
+ .map { |name, data| NumberValidation.new(name, data) }
24
+ end
25
+
26
+ def detect_format(number)
27
+ native_format = formats.detect do |format|
28
+ number =~ Regexp.new("^(#{format.leading_digits})") && number =~ Regexp.new("^(#{format.pattern})$")
29
+ end
30
+
31
+ return native_format if native_format || main_country_for_code
32
+ parent_country.detect_format(number) if parent_country
33
+ end
34
+
35
+ def parent_country
36
+ return if main_country_for_code
37
+ Country.all_countries.detect do |country|
38
+ country.country_code == self.country_code && country.main_country_for_code
39
+ end
40
+ end
41
+
42
+ def full_general_pattern
43
+ %r{^(#{country_code})?(#{national_prefix})?(?<national_num>#{general_validation.pattern})$}
44
+ end
45
+
46
+ def self.phone_data
47
+ @phone_data ||= load_data
48
+ end
49
+
50
+ def self.find(country_id)
51
+ data = phone_data[country_id.to_s.upcase.to_sym]
52
+ new(data) if data
53
+ end
54
+
55
+ def self.load_data
56
+ data_file = "#{File.dirname(__FILE__)}/../../data/telephone_number_data_file.dat"
57
+ main_data = Marshal.load(File.binread(data_file))
58
+ override_data = {}
59
+ override_data = Marshal.load(File.binread(TelephoneNumber.override_file)) if TelephoneNumber.override_file
60
+ return main_data.deep_deep_merge!(override_data)
61
+ end
62
+
63
+ def self.all_countries
64
+ @all_countries ||= phone_data.values.map {|data| new(data)}
65
+ end
66
+ end
67
+ end
@@ -33,7 +33,7 @@ module TelephoneNumber
33
33
  {}.tap do |fhash|
34
34
  format.attributes.values.each do |attr|
35
35
  key = underscore(attr.name).to_sym
36
- fhash[key] = if key == PhoneData::NATIONAL_PREFIX_FORMATTING_RULE
36
+ fhash[key] = if key == :national_prefix_formatting_rule
37
37
  attr.value
38
38
  else
39
39
  attr.value.delete("\n ")
@@ -41,30 +41,30 @@ module TelephoneNumber
41
41
  end
42
42
  format.elements.each do |child|
43
43
  key = underscore(child.name).to_sym
44
- fhash[key] = [PhoneData::FORMAT, PhoneData::INTL_FORMAT].include?(key) ? child.text : child.text.delete("\n ")
44
+ fhash[key] = [:format, :intl_format].include?(key) ? child.text : child.text.delete("\n ")
45
45
  end
46
46
  end
47
47
  end
48
48
 
49
49
  return if override && formats_arr.empty?
50
- country_data[PhoneData::FORMATS] = formats_arr
50
+ country_data[:formats] = formats_arr
51
51
  end
52
52
 
53
53
  def load_validations(country_data, territory)
54
- country_data[PhoneData::VALIDATIONS] = {}
54
+ country_data[:validations] = {}
55
55
  territory.elements.each do |element|
56
56
  next if element.name == 'references' || element.name == 'availableFormats'
57
- country_data[PhoneData::VALIDATIONS][underscore(element.name).to_sym] = {}.tap do |validation_hash|
57
+ country_data[:validations][underscore(element.name).to_sym] = {}.tap do |validation_hash|
58
58
  element.elements.each { |child| validation_hash[underscore(child.name).to_sym] = child.text.delete("\n ") }
59
59
  end
60
60
  end
61
- country_data.delete(PhoneData::VALIDATIONS) if country_data[PhoneData::VALIDATIONS].empty? && override
61
+ country_data.delete(:validations) if country_data[:validations].empty? && override
62
62
  end
63
63
 
64
64
  def load_base_attributes(country_data, territory)
65
65
  territory.attributes.each do |key, value_object|
66
66
  underscored_key = underscore(key).to_sym
67
- country_data[underscored_key] = if underscored_key == PhoneData::NATIONAL_PREFIX_FOR_PARSING
67
+ country_data[underscored_key] = if underscored_key == :national_prefix_for_parsing
68
68
  value_object.value.delete("\n ")
69
69
  else
70
70
  value_object.value
@@ -94,4 +94,3 @@ module TelephoneNumber
94
94
  end
95
95
  end
96
96
  end
97
-
@@ -1,39 +1,28 @@
1
1
  module TelephoneNumber
2
2
  class Formatter
3
- extend Forwardable
4
3
 
5
- attr_reader :normalized_number, :phone_data, :valid
4
+ attr_reader :normalized_number, :country, :valid, :original_number
6
5
 
7
- delegate [:country_data, :country] => :phone_data
8
-
9
- def initialize(number_obj, phone_data)
6
+ def initialize(number_obj)
10
7
  @normalized_number = number_obj.normalized_number
11
- @phone_data = phone_data
8
+ @country = number_obj.country
12
9
  @valid = number_obj.valid?
10
+ @original_number = number_obj.original_number
13
11
  end
14
12
 
15
13
  def national_number(formatted: true)
16
- if formatted
17
- @formatted_national_number ||= build_national_number
18
- else
19
- @national_number ||= build_national_number(formatted: false)
20
- end
14
+ return original_or_default if !valid? || !number_format
15
+ build_national_number(formatted: formatted)
21
16
  end
22
17
 
23
18
  def e164_number(formatted: true)
24
- if formatted
25
- @formatted_e164_number ||= build_e164_number
26
- else
27
- @e164_number ||= build_e164_number(formatted: false)
28
- end
19
+ return original_or_default if !valid?
20
+ build_e164_number(formatted: formatted)
29
21
  end
30
22
 
31
23
  def international_number(formatted: true)
32
- if formatted
33
- @formatted_international_number ||= build_international_number
34
- else
35
- @international_number ||= build_international_number(formatted: false)
36
- end
24
+ return original_or_default if !valid? || !number_format
25
+ build_international_number(formatted: formatted)
37
26
  end
38
27
 
39
28
  alias_method :valid?, :valid
@@ -41,73 +30,47 @@ module TelephoneNumber
41
30
  private
42
31
 
43
32
  def number_format
44
- @number_format ||= extract_number_format
33
+ @number_format ||= country.detect_format(normalized_number)
45
34
  end
46
35
 
47
36
  def build_national_number(formatted: true)
48
- return normalized_or_default if !valid? || number_format.nil?
49
- captures = normalized_number.match(Regexp.new(number_format[PhoneData::PATTERN])).captures
50
- national_prefix_formatting_rule = number_format[PhoneData::NATIONAL_PREFIX_FORMATTING_RULE] \
51
- || country_data[PhoneData::NATIONAL_PREFIX_FORMATTING_RULE]
37
+ captures = normalized_number.match(number_format.pattern).captures
38
+ national_prefix_formatting_rule = number_format.national_prefix_formatting_rule || country.national_prefix_formatting_rule
52
39
 
53
- formatted_string = format(ruby_format_string(number_format[PhoneData::FORMAT]), *captures)
54
- captures.delete(PhoneData::MOBILE_TOKEN_COUNTRIES[country])
40
+ formatted_string = format(ruby_format_string(number_format.format), *captures)
41
+ captures.delete(country.mobile_token)
55
42
 
56
43
  if national_prefix_formatting_rule
57
44
  national_prefix_string = national_prefix_formatting_rule.dup
58
- national_prefix_string.gsub!(/\$NP/, country_data[PhoneData::NATIONAL_PREFIX])
45
+ national_prefix_string.gsub!(/\$NP/, country.national_prefix)
59
46
  national_prefix_string.gsub!(/\$FG/, captures[0])
60
47
  formatted_string.sub!(captures[0], national_prefix_string)
61
48
  end
62
49
 
63
- formatted ? formatted_string : Parser.sanitize(formatted_string)
50
+ formatted ? formatted_string : TelephoneNumber.sanitize(formatted_string)
64
51
  end
65
52
 
66
53
  def build_e164_number(formatted: true)
67
- return normalized_or_default if !country_data || normalized_number.empty?
68
- formatted_string = "+#{country_data[PhoneData::COUNTRY_CODE]}#{normalized_number}"
69
- formatted ? formatted_string : Parser.sanitize(formatted_string)
54
+ formatted_string = "+#{country.country_code}#{normalized_number}"
55
+ formatted ? formatted_string : TelephoneNumber.sanitize(formatted_string)
70
56
  end
71
57
 
72
58
  def build_international_number(formatted: true)
73
- return normalized_or_default if !valid? || number_format.nil?
74
- captures = normalized_number.match(Regexp.new(number_format[PhoneData::PATTERN])).captures
75
- key = number_format.fetch(PhoneData::INTL_FORMAT, 'NA') != 'NA' ? PhoneData::INTL_FORMAT : PhoneData::FORMAT
76
- formatted_string = "+#{country_data[PhoneData::COUNTRY_CODE]} #{format(ruby_format_string(number_format[key]), *captures)}"
77
- formatted ? formatted_string : Parser.sanitize(formatted_string)
59
+ return original_or_default if !valid? || number_format.nil?
60
+ captures = normalized_number.match(number_format.pattern).captures
61
+ key = number_format.intl_format || number_format.format
62
+ formatted_string = "+#{country.country_code} #{format(ruby_format_string(key), *captures)}"
63
+ formatted ? formatted_string : TelephoneNumber.sanitize(formatted_string)
78
64
  end
79
65
 
80
66
  def ruby_format_string(format_string)
81
67
  format_string.gsub(/(\$\d)/) { |cap| "%#{cap.reverse}s" }
82
68
  end
83
69
 
84
- def normalized_or_default
85
- return normalized_number unless TelephoneNumber.default_format_string && TelephoneNumber.default_format_pattern
86
- captures = normalized_number.match(TelephoneNumber.default_format_pattern).captures
70
+ def original_or_default
71
+ return original_number unless TelephoneNumber.default_format_string && TelephoneNumber.default_format_pattern
72
+ captures = original_number.match(TelephoneNumber.default_format_pattern).captures
87
73
  format(ruby_format_string(TelephoneNumber.default_format_string), *captures)
88
74
  end
89
-
90
- def extract_number_format
91
- native_country_format = detect_format(country.to_sym)
92
- return native_country_format if native_country_format
93
-
94
- # This means we couldn't find an applicable format so we now need to scan through the hierarchy
95
- parent_country_code = PhoneData.phone_data.detect do |_country_code, country_data|
96
- country_data[PhoneData::COUNTRY_CODE] == PhoneData.phone_data[self.country.to_sym][PhoneData::COUNTRY_CODE] \
97
- && country_data[PhoneData::MAIN_COUNTRY_FOR_CODE] == 'true'
98
- end
99
-
100
- detect_format(parent_country_code[0]) if parent_country_code
101
- end
102
-
103
- def detect_format(country_code)
104
- PhoneData.phone_data[country_code.to_sym][PhoneData::FORMATS].detect do |format|
105
- (format[PhoneData::LEADING_DIGITS].nil? \
106
- || normalized_number =~ Regexp.new("^(#{format[PhoneData::LEADING_DIGITS]})")) \
107
- && normalized_number =~ Regexp.new("^(#{format[PhoneData::PATTERN]})$")
108
- end
109
- end
110
75
  end
111
76
  end
112
-
113
-
@@ -2,15 +2,16 @@ module TelephoneNumber
2
2
  class Number
3
3
  extend Forwardable
4
4
 
5
- attr_reader :phone_data, :parser, :formatter
5
+ attr_reader :country, :parser, :formatter, :original_number
6
6
 
7
7
  delegate [:valid?, :valid_types, :normalized_number] => :parser
8
8
  delegate [:national_number, :e164_number, :international_number] => :formatter
9
9
 
10
10
  def initialize(number, country)
11
- @phone_data = PhoneData.new(country)
12
- @parser = Parser.new(number, @phone_data)
13
- @formatter = Formatter.new(self, @phone_data)
11
+ @original_number = number
12
+ @country = Country.find(country)
13
+ @parser = Parser.new(self)
14
+ @formatter = Formatter.new(self)
14
15
  end
15
16
  end
16
17
  end
@@ -0,0 +1,14 @@
1
+ module TelephoneNumber
2
+ class NumberFormat
3
+
4
+ attr_reader :pattern, :leading_digits, :format, :national_prefix_formatting_rule, :intl_format
5
+
6
+ def initialize(data_hash)
7
+ @pattern = Regexp.new(data_hash[:pattern]) if data_hash[:pattern]
8
+ @leading_digits = Regexp.new(data_hash[:leading_digits]) if data_hash[:leading_digits]
9
+ @format = data_hash[:format]
10
+ @intl_format = data_hash[:intl_format]
11
+ @national_prefix_formatting_rule = data_hash[:national_prefix_formatting_rule]
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module TelephoneNumber
2
+ class NumberValidation
3
+ attr_reader :name, :pattern
4
+
5
+ def initialize(name, data_hash)
6
+ @name = name
7
+ @pattern = data_hash[:national_number_pattern]
8
+ end
9
+ end
10
+ end
@@ -1,16 +1,11 @@
1
1
  module TelephoneNumber
2
2
  class Parser
3
- KEYS_TO_SKIP = [PhoneData::GENERAL, PhoneData::AREA_CODE_OPTIONAL]
4
- extend Forwardable
3
+ attr_reader :original_number, :normalized_number, :country
5
4
 
6
- delegate [:country_data, :country] => :phone_data
7
- attr_reader :sanitized_number, :original_number, :normalized_number, :phone_data
8
-
9
- def initialize(original_number, phone_data)
10
- @sanitized_number = self.class.sanitize(original_number)
11
- @phone_data = phone_data
12
- @original_number = original_number
13
- @normalized_number = build_normalized_number
5
+ def initialize(number_obj)
6
+ @original_number = number_obj.original_number
7
+ @country = number_obj.country
8
+ @normalized_number = build_normalized_number if @country
14
9
  end
15
10
 
16
11
  def valid_types
@@ -21,59 +16,35 @@ module TelephoneNumber
21
16
  keys.empty? ? !valid_types.empty? : !(valid_types & keys.map(&:to_sym)).empty?
22
17
  end
23
18
 
24
- def self.detect_country(number)
25
- sanitized_number = sanitize(number)
26
- detected_country = PhoneData.phone_data.detect(->{[]}) do |two_letter, value|
27
- sanitized_number =~ Regexp.new("^#{value[:country_code]}") && new(sanitized_number, PhoneData.new(two_letter)).valid?
28
- end.first
29
- end
30
-
31
- def self.sanitize(input_number)
32
- return input_number.to_s.gsub(/\D/, '')
33
- end
34
-
35
19
  private
36
20
 
37
- # returns an array of valid types for the normalized number
38
- # if array is empty, we can assume that the number is invalid
39
- def validate
40
- return [] unless country_data
41
- applicable_keys = country_data[PhoneData::VALIDATIONS].reject { |key, _value| KEYS_TO_SKIP.include?(key) }
42
- applicable_keys.map do |phone_type, validations|
43
- full = "^(#{validations[PhoneData::VALID_PATTERN]})$"
44
- phone_type.to_sym if normalized_number =~ Regexp.new(full)
45
- end.compact
46
- end
47
-
48
21
  # normalized_number is basically a "best effort" at national number without
49
22
  # any formatting. This is what we will use to derive formats, validations and
50
23
  # basically anything else that uses google data
51
24
  def build_normalized_number
52
- return sanitized_number unless country_data
53
- country_code = country_data[PhoneData::COUNTRY_CODE]
54
-
55
- number_with_correct_prefix = parse_prefix
56
-
57
- reg_string = "^(#{country_code})?"
58
- reg_string << "(#{country_data[PhoneData::NATIONAL_PREFIX]})?"
59
- reg_string << "(#{country_data[PhoneData::VALIDATIONS][PhoneData::GENERAL][PhoneData::VALID_PATTERN]})$"
25
+ match_result = parse_prefix.match(country.full_general_pattern)
26
+ match_result ? match_result[:national_num] : original_number
27
+ end
60
28
 
61
- match_result = number_with_correct_prefix.match(Regexp.new(reg_string))
62
- return sanitized_number unless match_result
63
- prefix_results = [match_result[1], match_result[2]]
64
- number_with_correct_prefix.sub(prefix_results.join, '')
29
+ # returns an array of valid types for the normalized number
30
+ # if array is empty, we can assume that the number is invalid
31
+ def validate
32
+ return [] unless country
33
+ country.validations.select do |validation|
34
+ normalized_number =~ Regexp.new("^(#{validation.pattern})$")
35
+ end.map(&:name)
65
36
  end
66
37
 
67
38
  def parse_prefix
68
- return sanitized_number unless country_data[:national_prefix_for_parsing]
69
- duped = sanitized_number.dup
70
- match_object = duped.match(Regexp.new(country_data[:national_prefix_for_parsing]))
39
+ return original_number unless country.national_prefix_for_parsing
40
+ duped = original_number.dup
41
+ match_object = duped.match(country.national_prefix_for_parsing)
71
42
 
72
43
  # we need to do the "start_with?" here because we need to make sure it's not finding
73
44
  # something in the middle of the number. However, we can't modify the regex to do this
74
45
  # for us because it will offset the match groups that are referenced in the transform rules
75
- return sanitized_number unless match_object && duped.start_with?(match_object[0])
76
- if country_data[:national_prefix_transform_rule]
46
+ return original_number unless match_object && duped.start_with?(match_object[0])
47
+ if country.national_prefix_transform_rule
77
48
  transform_national_prefix(duped, match_object)
78
49
  else
79
50
  duped.sub!(match_object[0], '')
@@ -81,7 +52,7 @@ module TelephoneNumber
81
52
  end
82
53
 
83
54
  def transform_national_prefix(duped, match_object)
84
- if PhoneData::MOBILE_TOKEN_COUNTRIES.include?(country) && match_object.captures.any?
55
+ if country.mobile_token && match_object.captures.any?
85
56
  format(build_format_string, duped.sub!(match_object[0], match_object[1]))
86
57
  elsif match_object.captures.none?
87
58
  duped.sub!(match_object[0], '')
@@ -91,7 +62,7 @@ module TelephoneNumber
91
62
  end
92
63
 
93
64
  def build_format_string
94
- country_data[:national_prefix_transform_rule].gsub(/(\$\d)/) { |cap| "%#{cap.reverse}s" }
65
+ country.national_prefix_transform_rule.gsub(/(\$\d)/) { |cap| "%#{cap.reverse}s" }
95
66
  end
96
67
  end
97
68
  end
@@ -6,23 +6,31 @@ module TelephoneNumber
6
6
  class TestDataGenerator
7
7
  URL = "https://libphonenumber.appspot.com/phonenumberparser?number=%s&country=%s".freeze
8
8
  COUNTRIES = {
9
+ AE: %w(971529933171 971553006144 971551000291),
9
10
  AR: %w(111512345678 380151234567 299154104587 01112345678),
10
11
  AU: %w(0467703037),
12
+ BE: %w(32498485960 32477702206 32474095692),
13
+ BO: %w(59178500348 59178006138 59178006139),
11
14
  BR: %w(011992339376 1123456789 11961234567),
12
15
  BY: %w(80152450911 294911911 152450911),
13
16
  CA: %w(16135550119 16135550171 16135550112 16135550194
14
17
  16135550122 16135550131 15146708700 14169158200),
18
+ CH: %w(41794173875 41795061129 41795820985),
15
19
  CL: %w(961234567 221234567),
16
20
  CN: %w(15694876068 13910503766 15845989469 05523245954 04717158875 03748086894),
17
21
  CO: %w(3211234567 12345678),
18
22
  CR: %w(22123456 83123456),
19
23
  DE: %w(15222503070),
24
+ DK: %w(4524453744 4551622172 4542428484),
25
+ EC: %w(593992441504 593984657155 593984015053),
26
+ EE: %w(37253629280 37253682997 37254004517),
27
+ ES: %w(34606217800 34667751353 34646570628),
20
28
  FR: %w(0607114556),
21
29
  GB: %w(448444156790 442079308181 442076139800 442076361000
22
30
  07780991912 442076299400 442072227888),
23
31
  HK: %w(64636251),
32
+ HU: %w(36709311285 36709311279 36709311206),
24
33
  IE: %w(0863634875),
25
- MX: %w(4423593227 14423593227),
26
34
  IN: %w(915622231515 912942433300 912912510101 911126779191
27
35
  912224818000 917462223999 912266653366 912266325757
28
36
  914066298585 911242451234 911166566162 911123890606
@@ -30,14 +38,31 @@ module TelephoneNumber
30
38
  1126779191 2224818000 7462223999 2266653366
31
39
  2266325757 4066298585 1242451234 1166566162
32
40
  1123890606 1123583754 09176642499),
41
+ IT: %w(393478258998 393440161350),
33
42
  JP: %w(312345678 9012345678),
43
+ KR: %w(821036424812 821053812833 821085894820),
44
+ MX: %w(4423593227 14423593227),
45
+ NL: %w(31610958780 31610000852 31611427604),
46
+ NO: %w(4792272668 4797065876 4792466013),
47
+ NZ: %w(64212715077 6421577017 64212862111),
48
+ PE: %w(51994156035 51987527881 51972737259),
49
+ PH: %w(639285588185 639285588262 639285548190),
50
+ PL: %w(48665666003 48885882321 48885889958),
51
+ QA: %w(97470482288 97474798678),
52
+ RO: %w(40724242563 40727798526 40727735377),
53
+ SA: %w(966503891468 966501543349 966500939012),
54
+ SE: %w(46708922920 46723985268 46761001966),
34
55
  SG: %w(96924755),
56
+ TR: %w(905497728782 905497728780 905497728781),
57
+ TT: %w(18687804765 18687804843 18687804752),
58
+ TW: %w(886905627933 886905627901 886905627925),
35
59
  US: %w(16502530000 14044879000 15123435283 13032450086 16175751300
36
60
  3175083345 13128404100 12485934000 19497941600 14257395600 13103106000
37
61
  16086699600 12125650000 14123456700 14157360000 12068761800
38
- 12023461100 3175082333)
62
+ 12023461100 3175082333),
63
+ VE: %w(584149993108 584248407260 584248271518),
64
+ ZA: %w(27826187617 27823014578 27828840632)
39
65
  }.freeze
40
-
41
66
  def self.import!
42
67
  output_hash = {}
43
68
  fetch_data(output_hash)
@@ -1,3 +1,3 @@
1
1
  module TelephoneNumber
2
- VERSION = "1.1.1"
2
+ VERSION = "1.2.0.rc1"
3
3
  end
@@ -1,48 +1,17 @@
1
1
  require 'telephone_number/version'
2
2
  require 'utilities/hash'
3
- require 'forwardable'
3
+ require 'active_model/telephone_number_validator' if defined?(ActiveModel)
4
4
 
5
5
  module TelephoneNumber
6
- autoload :DataImporter, 'telephone_number/data_importer'
6
+ autoload :DataImporter, 'telephone_number/data_importer'
7
7
  autoload :TestDataGenerator, 'telephone_number/test_data_generator'
8
- autoload :Parser, 'telephone_number/parser'
9
- autoload :Number, 'telephone_number/number'
10
- autoload :Formatter, 'telephone_number/formatter'
11
- autoload :PhoneData, 'telephone_number/phone_data'
12
- autoload :ClassMethods, 'telephone_number/class_methods'
8
+ autoload :Parser, 'telephone_number/parser'
9
+ autoload :Number, 'telephone_number/number'
10
+ autoload :Formatter, 'telephone_number/formatter'
11
+ autoload :Country, 'telephone_number/country'
12
+ autoload :NumberFormat, 'telephone_number/number_format'
13
+ autoload :NumberValidation, 'telephone_number/number_validation'
14
+ autoload :ClassMethods, 'telephone_number/class_methods'
13
15
 
14
16
  extend ClassMethods
15
-
16
- # allows users to override the default data
17
- @override_file = nil
18
-
19
- # allows users to provide a default format pattern
20
- @default_format_pattern = nil
21
-
22
- # allows users to provide a default format string
23
- @default_format_string = nil
24
-
25
- def self.override_file=(file_name)
26
- @override_file = file_name
27
- end
28
-
29
- def self.override_file
30
- @override_file
31
- end
32
-
33
- def self.default_format_string=(format_string)
34
- @default_format_string = format_string
35
- end
36
-
37
- def self.default_format_string
38
- @default_format_string
39
- end
40
-
41
- def self.default_format_pattern=(format_string)
42
- @default_format_pattern = Regexp.new(format_string)
43
- end
44
-
45
- def self.default_format_pattern
46
- @default_format_pattern
47
- end
48
17
  end
@@ -35,4 +35,13 @@ class Hash
35
35
 
36
36
  self
37
37
  end
38
+
39
+ def except(*keys)
40
+ dup.except!(*keys)
41
+ end
42
+
43
+ def except!(*keys)
44
+ keys.each { |key| delete(key) }
45
+ self
46
+ end
38
47
  end
@@ -24,9 +24,9 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency 'rake'
25
25
  spec.add_development_dependency 'minitest'
26
26
  spec.add_development_dependency 'pry'
27
- spec.add_development_dependency 'pry-byebug'
28
27
  spec.add_development_dependency 'nokogiri'
29
28
  spec.add_development_dependency 'httparty'
29
+ spec.add_development_dependency 'activemodel', '>= 4.0'
30
30
  spec.add_development_dependency 'minitest-focus'
31
31
  spec.add_development_dependency 'coveralls'
32
32
  end