phonelib 0.6.10 → 0.6.11

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9c2862f5e9f97af025f8a5beba5a99c68fa24a85
4
- data.tar.gz: e1d12a6507f085b7c1ee633e8940cf88dbdd1dab
3
+ metadata.gz: fa38e795e6d299330a008f39f359cdd29ba221fc
4
+ data.tar.gz: 9bf8ce164c4838722a06aff72037147852100244
5
5
  SHA512:
6
- metadata.gz: 4e5cb8d9c464042b48411057ff7367bcb5ed5d3893454469dd65ddd96812e5ada4048883c4eaa49dc8a5d0927125e9ee40b7c9ccc484121c67489b0427858b2b
7
- data.tar.gz: e0541b7cf75c20d71a65297263bfa06b6941a6afffd9375aed0968df040e2bb6f2642e650b4535faf15fc54c0c5827ca3957c525c47ee0197eb10877aff6ab03
6
+ metadata.gz: 61367e9387768b79bbb6d43c5b9718098c4a6772281b24111acd9bce2e6dadcfe08b9aa54aa64e4463b4457e593d4fb08e92da6e15d537dcf083df14d3c5e3f1
7
+ data.tar.gz: 58ba6833ce8aec90171faacef75b9fbfd865cd236242cb621c4fff26e457b4dc387c49d9e2293c7b9e0d77eac36d8442cbba830f1fe68011fff4539f54374758
Binary file
data/data/phone_data.dat CHANGED
Binary file
data/lib/phonelib/core.rb CHANGED
@@ -218,23 +218,28 @@ module Phonelib
218
218
  # @private Pattern key
219
219
  PATTERN = :pattern
220
220
 
221
+ PLUS_SIGN = '+'.freeze
222
+
223
+ # @private vanity numbers 4 keys letters
224
+ VANITY_4_LETTERS_KEYS_REGEX = /[SVYZ]/.freeze
225
+
221
226
  # @private Area code possible types
222
- AREA_CODE_TYPES = [FIXED_LINE, FIXED_OR_MOBILE, MOBILE]
227
+ AREA_CODE_TYPES = [FIXED_LINE, FIXED_OR_MOBILE, MOBILE].freeze
223
228
 
224
229
  # @private Area code countries for mobile type
225
- AREA_CODE_MOBILE_COUNTRIES = %w(AR MX BR)
230
+ AREA_CODE_MOBILE_COUNTRIES = %w(AR MX BR).freeze
226
231
 
227
232
  # @private Area code mobile phone token
228
233
  AREA_CODE_MOBILE_TOKENS = {
229
234
  'MX' => '1',
230
235
  'AR' => '9'
231
- }
236
+ }.freeze
232
237
 
233
238
  # @private Default number formatting data hash
234
239
  DEFAULT_NUMBER_FORMAT = {
235
240
  pattern: '(\\d+)(\\d{3})(\\d{4})',
236
241
  format: '$1 $2 $3'
237
- }
242
+ }.freeze
238
243
 
239
244
  # @private hash of all phone types with human representation
240
245
  TYPES_DESC = {
@@ -261,7 +266,7 @@ module Phonelib
261
266
  standard_rate: 'Standard Rate Destination',
262
267
  carrier_selection_codes: 'Carrier Selection codes',
263
268
  area_code_optional: 'Are code optional'
264
- }
269
+ }.freeze
265
270
 
266
271
  # @private short codes types keys
267
272
  SHORT_CODES = [
@@ -269,7 +274,7 @@ module Phonelib
269
274
  :expanded_emergency, :no_international_dialling, :carrier_services,
270
275
  :directory_services, :standard_rate, :carrier_selection_codes,
271
276
  :area_code_optional
272
- ]
277
+ ].freeze
273
278
 
274
279
  # @private Extended data prefixes hash key
275
280
  EXT_PREFIXES = :prefixes
@@ -58,29 +58,7 @@ module Phonelib
58
58
  import_timezone_data
59
59
  import_carrier_data
60
60
  save_data_file
61
- end
62
-
63
- # method saves parsed data to data files
64
- def save_data_file
65
- data_file =
66
- "#{File.dirname(__FILE__)}/../../#{Phonelib::Core::FILE_MAIN_DATA}"
67
-
68
- File.open(data_file, 'wb+') do |f|
69
- Marshal.dump(@data, f)
70
- end
71
-
72
- ext_file =
73
- "#{File.dirname(__FILE__)}/../../#{Phonelib::Core::FILE_EXT_DATA}"
74
- extended = {
75
- Phonelib::Core::EXT_PREFIXES => @prefixes,
76
- Phonelib::Core::EXT_GEO_NAMES => @geo_names,
77
- Phonelib::Core::EXT_TIMEZONES => @timezones,
78
- Phonelib::Core::EXT_CARRIERS => @carriers
79
- }
80
- File.open(ext_file, 'wb+') do |f|
81
- Marshal.dump(extended, f)
82
- end
83
- puts 'DATA SAVED'
61
+ save_extended_data_file
84
62
  end
85
63
 
86
64
  # method clones libphonenumber repo to local dir
@@ -97,10 +75,8 @@ module Phonelib
97
75
  puts 'IMPORTING MAIN DATA'
98
76
  main_from_xml("#{@destination}#{MAIN_FILE}").elements.each do |el|
99
77
  # each country
100
- country = get_hash_from_xml(el, :attributes)
101
- country[:types] = {}
102
-
103
- country.merge! get_types_and_formats(el.children)
78
+ country = hash_from_xml(el, :attributes)
79
+ country.merge! types_and_formats(el.children)
104
80
  country = add_double_country_flag country
105
81
  @data[country[:id]] = country
106
82
  end
@@ -111,17 +87,11 @@ module Phonelib
111
87
  puts 'IMPORTING SHORT NUMBER DATA'
112
88
  main_from_xml("#{@destination}#{SHORT_DATA_FILE}").elements.each do |el|
113
89
  # each country
114
- country = get_hash_from_xml(el, :attributes)
115
- country[:types] = {}
116
-
117
- country.merge! get_types_and_formats(el.children)
90
+ country = hash_from_xml(el, :attributes)
91
+ country.merge! types_and_formats(el.children)
118
92
 
119
93
  country[:types].each do |type, data|
120
- if @data[country[:id]][:types][type]
121
- merge_short_with_main_type(country[:id], type, data)
122
- else
123
- @data[country[:id]][:types][type] = data
124
- end
94
+ merge_short_with_main_type(country[:id], type, data)
125
95
  end
126
96
  end
127
97
  end
@@ -134,10 +104,8 @@ module Phonelib
134
104
  el.children.each do |phone_type|
135
105
  next unless phone_type.name == 'availableFormats'
136
106
 
137
- formats = parse_formats(phone_type.children)
138
-
139
- country_code = el.attribute('countryCode').value
140
- @data[get_country_by_code(country_code)][:formats] += formats
107
+ country_code = country_by_code(el.attribute('countryCode').value)
108
+ @data[country_code][:formats] += parse_formats(phone_type.children)
141
109
  end
142
110
  end
143
111
  end
@@ -175,26 +143,24 @@ module Phonelib
175
143
  end
176
144
 
177
145
  # method extracts formats and types from xml data
178
- def get_types_and_formats(children)
179
- types = {}
180
- formats = []
146
+ def types_and_formats(children)
147
+ result = { types: {}, formats: [] }
181
148
 
182
149
  without_comments(children).each do |phone_type|
183
150
  if phone_type.name == 'availableFormats'
184
- formats = parse_formats(phone_type.children)
151
+ result[:formats] = parse_formats(phone_type.children)
185
152
  else
186
- types[name2sym(phone_type.name)] =
187
- get_hash_from_xml(phone_type, :element)
153
+ result[:types][name2sym(phone_type.name)] =
154
+ hash_from_xml(phone_type, :element)
188
155
  end
189
156
  end
190
157
 
191
- types = add_possible_if_not_exists(types)
192
-
193
- { types: types, formats: formats }
158
+ fill_possible_to_types_if_nil(result)
194
159
  end
195
160
 
196
161
  # method adds short number patterns to main data parsed from main xml
197
162
  def merge_short_with_main_type(country_id, type, data)
163
+ @data[country_id][:types][type] ||= {}
198
164
  data.each do |k, v|
199
165
  if @data[country_id][:types][type][k]
200
166
  @data[country_id][:types][type][k] += "|#{v}"
@@ -205,20 +171,20 @@ module Phonelib
205
171
  end
206
172
 
207
173
  # adds possible pattern in case it doesn't exists
208
- def add_possible_if_not_exists(types)
209
- types.each do |type, data|
174
+ def fill_possible_to_types_if_nil(result)
175
+ result[:types].each do |type, data|
210
176
  if data[Core::VALID_PATTERN] && !data[Core::POSSIBLE_PATTERN]
211
- types[type][Core::POSSIBLE_PATTERN] =
177
+ result[:types][type][Core::POSSIBLE_PATTERN] =
212
178
  data[Core::VALID_PATTERN]
213
179
  end
214
180
  end
215
- types
181
+ result
216
182
  end
217
183
 
218
184
  # method parses xml for formats data
219
185
  def parse_formats(formats_children)
220
186
  without_comments(formats_children).map do |format|
221
- current_format = get_hash_from_xml(format, :children)
187
+ current_format = hash_from_xml(format, :children)
222
188
 
223
189
  without_comments(format.children).each do |f|
224
190
  current_format[name2sym(f.name)] =
@@ -226,7 +192,7 @@ module Phonelib
226
192
  end
227
193
 
228
194
  current_format
229
- end.compact
195
+ end
230
196
  end
231
197
 
232
198
  # method updates data from raw files
@@ -245,7 +211,7 @@ module Phonelib
245
211
  end
246
212
 
247
213
  # method finds country by country prefix
248
- def get_country_by_code(country_code)
214
+ def country_by_code(country_code)
249
215
  match = @data.select { |_k, v| v[:country_code] == country_code }
250
216
  if match.size > 1
251
217
  match = match.select { |_k, v| v[:main_country_for_code] == 'true' }
@@ -6,12 +6,38 @@ module Phonelib
6
6
  # xml format attributes names
7
7
  XML_FORMAT_NAMES = %w(intlFormat format)
8
8
 
9
+ def file_path(file)
10
+ "#{File.dirname(__FILE__)}/../../#{file}"
11
+ end
12
+
13
+ # method saves parsed data to data files
14
+ def save_data_file
15
+ File.open(file_path(Phonelib::Core::FILE_MAIN_DATA), 'wb+') do |f|
16
+ Marshal.dump(@data, f)
17
+ end
18
+ end
19
+
20
+ # method saves extended data file
21
+ def save_extended_data_file
22
+ extended = {
23
+ Phonelib::Core::EXT_PREFIXES => @prefixes,
24
+ Phonelib::Core::EXT_GEO_NAMES => @geo_names,
25
+ Phonelib::Core::EXT_TIMEZONES => @timezones,
26
+ Phonelib::Core::EXT_CARRIERS => @carriers
27
+ }
28
+ File.open(file_path(Phonelib::Core::FILE_EXT_DATA), 'wb+') do |f|
29
+ Marshal.dump(extended, f)
30
+ end
31
+ puts 'DATA SAVED'
32
+ end
33
+
9
34
  # method updates prefixes hash recursively
10
35
  def fill_prefixes(key, value, prefix, prefixes)
11
36
  prefixes = {} if prefixes.nil?
12
37
  if prefix.size == 1
13
- prefixes[prefix.to_i] = {} unless prefixes[prefix.to_i]
14
- prefixes[prefix.to_i][key] = value
38
+ pr = prefix.to_i
39
+ prefixes[pr] ||= {}
40
+ prefixes[pr][key] = value
15
41
  else
16
42
  pr = prefix[0].to_i
17
43
  prefixes[pr] = fill_prefixes(key, value, prefix[1..-1], prefixes[pr])
@@ -32,7 +58,7 @@ module Phonelib
32
58
  end
33
59
 
34
60
  # method creates hash from xml elements/element attributes
35
- def get_hash_from_xml(data, type)
61
+ def hash_from_xml(data, type)
36
62
  hash = {}
37
63
  case type
38
64
  when :attributes
@@ -42,20 +42,20 @@ module Phonelib
42
42
  def sanitized
43
43
  @sanitized ||=
44
44
  vanity_converted(@original).gsub(
45
- Phonelib.strict_check ? /^\+/.freeze : /[^0-9]+/.freeze,
45
+ Phonelib.strict_check ? cr('^\+') : cr('[^0-9]+'),
46
46
  '')
47
47
  end
48
48
 
49
49
  # Returns all phone types that matched valid patterns
50
50
  # @return [Array] all valid phone types
51
51
  def types
52
- @data.flat_map { |_iso2, data| data[:valid] }.uniq
52
+ @types ||= @data.flat_map { |_iso2, data| data[:valid] }.uniq
53
53
  end
54
54
 
55
55
  # Returns all possible types that matched possible patterns
56
56
  # @return [Array] all possible phone types
57
57
  def possible_types
58
- @data.flat_map { |_iso2, data| data[:possible] }.uniq
58
+ @possible_types ||= @data.flat_map { |_iso2, data| data[:possible] }.uniq
59
59
  end
60
60
 
61
61
  # Returns first phone type that matched
@@ -105,7 +105,7 @@ module Phonelib
105
105
  # Returns whether a current parsed phone number is valid
106
106
  # @return [Boolean] parsed phone is valid
107
107
  def valid?
108
- @data.select { |_iso2, data| data[:valid].any? }.any?
108
+ @valid ||= @data.select { |_iso2, data| data[:valid].any? }.any?
109
109
  end
110
110
 
111
111
  # Returns whether a current parsed phone number is invalid
@@ -117,7 +117,7 @@ module Phonelib
117
117
  # Returns whether a current parsed phone number is possible
118
118
  # @return [Boolean] parsed phone is possible
119
119
  def possible?
120
- @data.select { |_iso2, data| data[:possible].any? }.any?
120
+ @possible ||= @data.select { |_iso2, data| data[:possible].any? }.any?
121
121
  end
122
122
 
123
123
  # Returns whether a current parsed phone number is impossible
@@ -18,16 +18,16 @@ module Phonelib
18
18
  def analyze(phone, passed_country)
19
19
  country = country_or_default_country passed_country
20
20
 
21
- result = try_to_parse_country(phone, country)
21
+ result = parse_country(phone, country)
22
22
  d_result = case
23
- when result && result.values.find {|e| e[:valid].any? }
23
+ when result && result.values.find { |e| e[:valid].any? }
24
24
  # all is good, return result
25
25
  when passed_country.nil?
26
26
  # trying for all countries if no country was passed
27
27
  detect_and_parse phone
28
- when !original_string.start_with?('+') && country_can_double_prefix?(country)
28
+ when country_can_dp?(country)
29
29
  # if country allows double prefix trying modified phone
30
- try_to_parse_country(changed_double_prefixed_phone(country, phone), country)
30
+ parse_country(changed_dp_phone(country, phone), country)
31
31
  end
32
32
  better_result(result, d_result)
33
33
  end
@@ -36,19 +36,14 @@ module Phonelib
36
36
 
37
37
  # method checks which result is better to return
38
38
  def better_result(base_result, result = nil)
39
- if result.nil?
40
- return base_result || {}
41
- end
39
+ base_result ||= {}
40
+ return base_result unless result
42
41
 
43
- if base_result.nil? || base_result.empty? || base_result.values.find {|e| e[:possible].any? }.nil?
44
- return result
45
- end
42
+ return result unless base_result.values.find { |e| e[:possible].any? }
46
43
 
47
- if result && result.values.find {|e| e[:valid].any? }
48
- return result
49
- end
44
+ return result if result.values.find { |e| e[:valid].any? }
50
45
 
51
- base_result || {}
46
+ base_result
52
47
  end
53
48
 
54
49
  # trying to parse phone for single country including international prefix
@@ -58,9 +53,9 @@ module Phonelib
58
53
  #
59
54
  # * +phone+ - phone for parsing
60
55
  # * +country+ - country to parse phone with
61
- def try_to_parse_country(phone, country)
56
+ def parse_country(phone, country)
62
57
  data = Phonelib.phone_data[country]
63
- return nil unless country && data
58
+ return nil unless data
64
59
 
65
60
  # if country was provided and it's a valid country, trying to
66
61
  # create e164 representation of phone number,
@@ -69,7 +64,7 @@ module Phonelib
69
64
  # if phone starts with international prefix of provided
70
65
  # country try to reanalyze without international prefix for
71
66
  # all countries
72
- return analyze(e164.delete('+'), nil) if e164[0] == '+'
67
+ return analyze(e164[1..-1], nil) if Core::PLUS_SIGN == e164[0]
73
68
  # trying to parse number for provided country
74
69
  parse_single_country e164, data
75
70
  end
@@ -83,10 +78,10 @@ module Phonelib
83
78
  def parse_single_country(e164, data)
84
79
  valid_match = phone_match_data?(e164, data)
85
80
  if valid_match
86
- national_and_data(e164, data, valid_match)
81
+ national_and_data(data, valid_match)
87
82
  else
88
83
  possible_match = phone_match_data?(e164, data, true)
89
- possible_match && national_and_data(e164, data, possible_match, true)
84
+ possible_match && national_and_data(data, possible_match, true)
90
85
  end
91
86
  end
92
87
 
@@ -100,7 +95,7 @@ module Phonelib
100
95
  Phonelib.phone_data.each do |key, data|
101
96
  parsed = parse_single_country(phone, data)
102
97
  if double_prefix_allowed?(data, phone, parsed && parsed[key])
103
- parsed = parse_single_country(changed_double_prefixed_phone(key, phone), data)
98
+ parsed = parse_single_country(changed_dp_phone(key, phone), data)
104
99
  end
105
100
  result.merge!(parsed) unless parsed.nil?
106
101
  end
@@ -114,13 +109,14 @@ module Phonelib
114
109
  # * +phone+ - phone number for parsing
115
110
  # * +data+ - country data to be based on for creating e164 representation
116
111
  def convert_to_e164(phone, data)
117
- match = phone.match full_regex_for_data(data, Core::VALID_PATTERN)
112
+ match = phone.match full_regex_for_data(data, Core::VALID_PATTERN, !original_starts_with_plus?)
118
113
  case
119
114
  when match
120
- national_start = phone.length - match.to_a.last.size
121
- "#{data[Core::COUNTRY_CODE]}#{phone[national_start..-1]}"
115
+ "#{data[Core::COUNTRY_CODE]}#{match.to_a.last}"
122
116
  when phone.match(cr("^#{data[Core::INTERNATIONAL_PREFIX]}"))
123
- phone.sub(cr("^#{data[Core::INTERNATIONAL_PREFIX]}"), '+')
117
+ phone.sub(cr("^#{data[Core::INTERNATIONAL_PREFIX]}"), Core::PLUS_SIGN)
118
+ when original_starts_with_plus? && phone.start_with?(data[Core::COUNTRY_CODE])
119
+ phone
124
120
  else
125
121
  "#{data[Core::COUNTRY_CODE]}#{phone}"
126
122
  end
@@ -130,18 +126,15 @@ module Phonelib
130
126
  #
131
127
  # ==== Attributes
132
128
  #
133
- # * +phone+ - phone number for parsing
134
129
  # * +data+ - country data
135
130
  # * +country_match+ - result of match of phone within full regex
136
131
  # * +not_valid+ - specifies that number is not valid by general desc pattern
137
- def national_and_data(phone, data, country_match, not_valid = false)
138
- prefix_length = data[Core::COUNTRY_CODE].length
139
- prefix_length += [1, 2].map { |i| country_match[i].to_s.size }.inject(:+)
132
+ def national_and_data(data, country_match, not_valid = false)
140
133
  result = data.select { |k, _v| k != :types && k != :formats }
141
- result[:national] = phone[prefix_length..-1] || ''
142
- result[:format] = number_format(result[:national], data[Core::FORMATS])
143
- result.merge! all_number_types(result[:national], data[Core::TYPES],
144
- not_valid)
134
+ phone = country_match.to_a.last
135
+ result[:national] = phone
136
+ result[:format] = number_format(phone, data[Core::FORMATS])
137
+ result.merge! all_number_types(phone, data[Core::TYPES], not_valid)
145
138
  result[:valid] = [] if not_valid
146
139
 
147
140
  { result[:id] => result }
@@ -178,9 +171,9 @@ module Phonelib
178
171
  # * +format_data+ - formatting data from country data
179
172
  def number_format(national, format_data)
180
173
  format_data && format_data.find do |format|
181
- (format[Core::LEADING_DIGITS].nil? \
182
- || national.match(cr("^(#{format[Core::LEADING_DIGITS]})"))) \
183
- && national.match(cr("^(#{format[Core::PATTERN]})$"))
174
+ (format[Core::LEADING_DIGITS].nil? || \
175
+ national.match(cr("^(#{format[Core::LEADING_DIGITS]})"))) && \
176
+ national.match(cr("^(#{format[Core::PATTERN]})$"))
184
177
  end || Core::DEFAULT_NUMBER_FORMAT
185
178
  end
186
179
 
@@ -3,24 +3,28 @@ module Phonelib
3
3
  module PhoneAnalyzerHelper
4
4
  private
5
5
 
6
+ def original_starts_with_plus?
7
+ original_s[0] == Core::PLUS_SIGN
8
+ end
9
+
10
+ # converts symbols in phone to numbers
6
11
  def vanity_converted(phone)
7
12
  return phone unless Phonelib.vanity_conversion
8
13
 
9
- (phone || '').gsub(/[a-z]/i.freeze) do |c|
14
+ (phone || '').gsub(cr('[a-zA-Z]')) do |c|
10
15
  c.upcase!
11
16
  # subtract "A"
12
17
  n = (c.ord - 65) / 3
13
18
  # account for #7 & #9 which have 4 chars
14
- n -= 1 if c == 'S'.freeze || c == 'V'.freeze || c >= 'Y'.freeze
19
+ n -= 1 if c.match(Core::VANITY_4_LETTERS_KEYS_REGEX)
15
20
  (n + 2).to_s
16
21
  end
17
22
  end
18
23
 
19
-
20
24
  # defines if to validate against single country or not
21
25
  def passed_country(country)
22
26
  code = country_prefix(country)
23
- if @original.start_with?('+') && code && !sanitized.start_with?(code)
27
+ if Core::PLUS_SIGN == @original[0] && code && !sanitized.start_with?(code)
24
28
  # in case number passed with + but it doesn't start with passed
25
29
  # country prefix
26
30
  country = nil
@@ -37,17 +41,18 @@ module Phonelib
37
41
 
38
42
  # caches regular expression, reusing it for later lookups
39
43
  def cr(regexp)
40
- Phonelib.phone_regexp_cache[regexp] ||= Regexp.new(regexp)
44
+ Phonelib.phone_regexp_cache[regexp] ||= Regexp.new(regexp).freeze
41
45
  end
42
46
 
43
47
  # defines whether country can have double country prefix in number
44
- def country_can_double_prefix?(country)
48
+ def country_can_dp?(country)
45
49
  Phonelib.phone_data[country] &&
46
- Phonelib.phone_data[country][Core::DOUBLE_COUNTRY_PREFIX_FLAG]
50
+ Phonelib.phone_data[country][Core::DOUBLE_COUNTRY_PREFIX_FLAG] &&
51
+ !original_starts_with_plus?
47
52
  end
48
53
 
49
54
  # changes phone to with/without double country prefix
50
- def changed_double_prefixed_phone(country, phone)
55
+ def changed_dp_phone(country, phone)
51
56
  data = Phonelib.phone_data[country]
52
57
  return if data.nil? || data[Core::DOUBLE_COUNTRY_PREFIX_FLAG].nil?
53
58
 
@@ -67,14 +72,15 @@ module Phonelib
67
72
  # * +phone+ - phone number being parsed
68
73
  # * +parsed+ - parsed regex match for phone
69
74
  def double_prefix_allowed?(data, phone, parsed = {})
70
- data && data[Core::DOUBLE_COUNTRY_PREFIX_FLAG] &&
75
+ data[Core::DOUBLE_COUNTRY_PREFIX_FLAG] &&
71
76
  phone =~ cr("^#{data[Core::COUNTRY_CODE]}") &&
72
- parsed && (parsed[:valid].nil? || parsed[:valid].empty?)
77
+ parsed && (parsed[:valid].nil? || parsed[:valid].empty?) &&
78
+ !original_starts_with_plus?
73
79
  end
74
80
 
75
81
  # Returns original number passed if it's a string or empty string otherwise
76
- def original_string
77
- @original.is_a?(String) ? @original : ''
82
+ def original_s
83
+ @original_s ||= @original.is_a?(String) ? @original : ''
78
84
  end
79
85
 
80
86
  # Get country that was provided or default country in needable format
@@ -83,7 +89,7 @@ module Phonelib
83
89
  #
84
90
  # * +country+ - country passed for parsing
85
91
  def country_or_default_country(country)
86
- country ||= (original_string.start_with?('+') ? nil : Phonelib.default_country)
92
+ country ||= (original_starts_with_plus? ? nil : Phonelib.default_country)
87
93
  country && country.to_s.upcase
88
94
  end
89
95
 
@@ -97,11 +103,7 @@ module Phonelib
97
103
  def full_regex_for_data(data, type, country_optional = true)
98
104
  regex = []
99
105
  regex << "(#{data[Core::INTERNATIONAL_PREFIX]})?"
100
- regex << if country_optional
101
- "(#{data[Core::COUNTRY_CODE]})?"
102
- else
103
- data[Core::COUNTRY_CODE]
104
- end
106
+ regex << "(#{data[Core::COUNTRY_CODE]})#{country_optional ? '?' : ''}"
105
107
  regex << "(#{data[Core::NATIONAL_PREFIX_FOR_PARSING] || data[Core::NATIONAL_PREFIX]})?"
106
108
  regex << "(#{data[Core::TYPES][Core::GENERAL][type]})"
107
109
 
@@ -165,22 +167,27 @@ module Phonelib
165
167
  # ==== Attributes
166
168
  #
167
169
  # * +number+ - phone number for validation
168
- # * +possible_pattern+ - possible pattern for validation
169
- # * +national_pattern+ - valid pattern for validation
170
+ # * +p_regex+ - possible regex pattern for validation
171
+ # * +v_regex+ - valid regex pattern for validation
170
172
  # * +not_valid+ - specifies that number is not valid by general desc pattern
171
- def number_valid_and_possible?(number, possible_pattern, national_pattern, not_valid = false)
172
- possible_match = number.match(cr("^(?:#{possible_pattern})$"))
173
- possible = possible_match && possible_match.to_s.length == number.length
174
-
175
- return [!not_valid && possible, possible] if possible_pattern == national_pattern
176
- valid = false
177
- if !not_valid && possible
178
- # doing national pattern match only in case possible matches
179
- national_match = number.match(cr("^(?:#{national_pattern})$"))
180
- valid = national_match && national_match.to_s.length == number.length
181
- end
173
+ def number_valid_and_possible?(number, p_regex, v_regex, not_valid = false)
174
+ possible = number_match?(number, p_regex)
175
+
176
+ return [!not_valid && possible, possible] if p_regex == v_regex
177
+ valid = !not_valid && possible && number_match?(number, v_regex)
182
178
 
183
179
  [valid && possible, possible]
184
180
  end
181
+
182
+ # Checks number against regex and compares match length
183
+ #
184
+ # ==== Attributes
185
+ #
186
+ # * +number+ - phone number for validation
187
+ # * +regex+ - regex for perfoming a validation
188
+ def number_match?(number, regex)
189
+ match = number.match(cr("^(?:#{regex})$"))
190
+ match && match.to_s.length == number.length
191
+ end
185
192
  end
186
193
  end
@@ -32,24 +32,23 @@ module Phonelib
32
32
  # Returns the country code from the original phone number.
33
33
  # @return [String] matched country phone code
34
34
  def country_code
35
- Phonelib.phone_data[country] && \
36
- Phonelib.phone_data[country][Core::COUNTRY_CODE]
35
+ @country_code ||= Phonelib.phone_data[country] && \
36
+ Phonelib.phone_data[country][Core::COUNTRY_CODE]
37
37
  end
38
38
 
39
39
  # Returns e164 formatted phone number
40
40
  # @param formatted [Boolean] whether to return numbers only or formatted
41
41
  # @return [String] formatted international number
42
42
  def international(formatted = true)
43
- return nil if sanitized.nil? || sanitized.empty?
43
+ return nil if sanitized.empty?
44
44
  return "+#{country_prefix_or_not}#{sanitized}" unless valid?
45
- return "#{country_code}#{@national_number}" unless formatted
45
+ return country_code + @national_number unless formatted
46
46
 
47
- format = @data[country][:format]
48
- if (matches = @national_number.match(/#{format[Core::PATTERN]}/))
49
- fmt = format[:intl_format] || format[:format]
47
+ fmt = @data[country][:format]
48
+ national = @national_number
49
+ if (matches = @national_number.match(cr(fmt[Core::PATTERN])))
50
+ fmt = fmt[:intl_format] || fmt[:format]
50
51
  national = fmt.gsub(/\$\d/) { |el| matches[el[1].to_i] }
51
- else
52
- national = @national_number
53
52
  end
54
53
 
55
54
  "+#{country_code} #{national}"
@@ -88,7 +87,7 @@ module Phonelib
88
87
  format_match, _format_string = formatting_data
89
88
  take_group = 1
90
89
  if type == Core::MOBILE && Core::AREA_CODE_MOBILE_TOKENS[country] && \
91
- format_match[1] == Core::AREA_CODE_MOBILE_TOKENS[country]
90
+ format_match[1] == Core::AREA_CODE_MOBILE_TOKENS[country]
92
91
  take_group = 2
93
92
  end
94
93
  format_match[take_group]
@@ -98,7 +97,7 @@ module Phonelib
98
97
 
99
98
  # @private defines if phone can have area code
100
99
  def area_code_possible?
101
- return false unless possible?
100
+ return false if impossible?
102
101
 
103
102
  # has national prefix
104
103
  return false unless @data[country][Core::NATIONAL_PREFIX] || country == 'IT'
@@ -126,10 +125,11 @@ module Phonelib
126
125
  def formatting_data
127
126
  return @formatting_data if defined?(@formatting_data)
128
127
 
129
- format = @data[country][:format]
130
- prefix = @data[country][Core::NATIONAL_PREFIX]
131
- rule = (format[Core::NATIONAL_PREFIX_RULE] ||
132
- @data[country][Core::NATIONAL_PREFIX_RULE] || '$1')
128
+ data = @data[country]
129
+ format = data[:format]
130
+ prefix = data[Core::NATIONAL_PREFIX]
131
+ rule = format[Core::NATIONAL_PREFIX_RULE] ||
132
+ data[Core::NATIONAL_PREFIX_RULE] || '$1'
133
133
 
134
134
  # change rule's constants to values
135
135
  rule.gsub!(/(\$NP|\$FG)/, '$NP' => prefix, '$FG' => '$1')
@@ -1,4 +1,4 @@
1
1
  module Phonelib
2
2
  # @private
3
- VERSION = '0.6.10'
3
+ VERSION = '0.6.11'
4
4
  end
@@ -43,21 +43,32 @@ class PhoneValidator < ActiveModel::EachValidator
43
43
  # Validation method
44
44
  def validate_each(record, attribute, value)
45
45
  return if options[:allow_blank] && value.blank?
46
- country = options[:country_specifier].call(record) if options[:country_specifier]
47
46
 
48
- phone = parse(value, country)
47
+ phone = parse(value, specified_country(record))
49
48
  valid = if simple_validation?
50
- method = options[:possible] ? :possible? : :valid?
51
- phone.send(method)
49
+ phone.send(validate_method)
52
50
  else
53
51
  (phone_types(phone) & types).size > 0
54
52
  end
55
53
 
56
- record.errors.add(attribute, options[:message] || :invalid, options) unless valid
54
+ record.errors.add(attribute, message, options) unless valid
57
55
  end
58
56
 
59
57
  private
60
58
 
59
+ def message
60
+ options[:message] || :invalid
61
+ end
62
+
63
+ def validate_method
64
+ options[:possible] ? :possible? : :valid?
65
+ end
66
+
67
+ def specified_country(record)
68
+ return unless options[:country_specifier]
69
+ options[:country_specifier].call(record)
70
+ end
71
+
61
72
  # @private
62
73
  def simple_validation?
63
74
  options[:types].nil?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phonelib
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.10
4
+ version: 0.6.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vadim Senderovich
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-01 00:00:00.000000000 Z
11
+ date: 2017-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake