russian_phone 0.1.1 → 0.2.4

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.
data/README.md CHANGED
@@ -4,8 +4,6 @@
4
4
 
5
5
  Гем для разбора и нормализации русских телефонных номеров
6
6
 
7
- ## Внимание: гем находится в разработке и пока не готов для использования
8
-
9
7
  ## Альтернативные решения
10
8
 
11
9
  https://github.com/floere/phony
@@ -14,10 +12,13 @@ https://github.com/joost/phony_rails
14
12
 
15
13
  https://github.com/carr/phone
16
14
 
17
- Эти решения поддерживают несколько стран
15
+ Указанные решения поддерживают несколько стран
18
16
 
19
17
  russian_phone поддерживает и будет поддерживать только российские телефонные номера
20
18
 
19
+ Целью данного гема было скорее получение номера в чистом виде (10 значного) из введенных пользователем данных, и
20
+ возможный минимум отбраковки верных номеров, которые сможет разобрать человек, чем 100% отбраковка неверных номеров.
21
+
21
22
  ## Installation
22
23
 
23
24
  Add this line to your application's Gemfile:
@@ -34,7 +35,43 @@ Or install it yourself as:
34
35
 
35
36
  ## Usage
36
37
 
37
- TODO: Write usage instructions here
38
+ Использованиие для разбора телефонных номеров:
39
+
40
+ # phone = RussianPhone::Number.new('(906) 111-11-11', default_country: 7)
41
+ => "+7 (906) 111-11-11"
42
+ # phone.country
43
+ => "7"
44
+ # phone.city
45
+ => "906"
46
+ # phone.subscriber
47
+ => "1111111"
48
+ # phone.full
49
+ => "+7 (906) 111-11-11"
50
+ # phone.cell?
51
+ => true
52
+ # phone.free?
53
+ => false
54
+ # phone.valid?
55
+ => true
56
+
57
+ Использование с Mongoid:
58
+
59
+ class User
60
+ include Mongoid::Document
61
+ field :phone, type: RussianPhone.field(default_country: 7, allowed_cities: [495]), validate: true
62
+ end
63
+
64
+ # u = User.new(phone: '495 1111111')
65
+ # u.phone
66
+ => '+7 (495) 111-11-11'
67
+ # u.phone.valid?
68
+ => true
69
+
70
+ Обратите внимание, по умолчанию *валидация телефонного номера выключена*, это значит что номер будет
71
+ сохраняться в базу даже если гем не смог его разобрать. Включите валидацию, установив validate:true.
72
+
73
+ В базе телефоны храняться в виде строки в полном виде, если телефон удалось разобрать, и в том виде как
74
+ введено пользователем, если не удалось разобрать и validate == false
38
75
 
39
76
  ## Contributing
40
77
 
@@ -10,7 +10,7 @@ module RussianPhone
10
10
 
11
11
  ::Mongoid::Fields.option :validate do |model, field, value|
12
12
  if value
13
- model.validates_with RussianPhone::Validator, fields: [field.name]
13
+ model.validates_with(RussianPhone::Validator, fields: [field.name])
14
14
  end
15
15
  end
16
16
 
@@ -34,6 +34,7 @@ module RussianPhone
34
34
  @subscriber = data[:subscriber].to_s
35
35
  @city = data[:city].to_s
36
36
  @country = data[:country].to_s
37
+ @extra = data[:extra].to_s
37
38
  end
38
39
 
39
40
  data.has_key?(field) ? data[field] : nil
@@ -59,6 +60,10 @@ module RussianPhone
59
60
  @country ||= parse(:country)
60
61
  end
61
62
 
63
+ def extra
64
+ @extra ||= parse(:extra)
65
+ end
66
+
62
67
  def split(format, number)
63
68
  number = number.dup
64
69
  format.inject([]) do |result, size|
@@ -82,10 +87,10 @@ module RussianPhone
82
87
 
83
88
  def full
84
89
  if valid?
85
- if free?
90
+ if free? && extra == ''
86
91
  "8-#{city}-#{format.join('-')}"
87
92
  else
88
- "+#{country} (#{city}) #{format.join('-')}"
93
+ "+#{country} (#{city}) #{format.join('-')}#{extra == '' ? '' : ' ' + extra}"
89
94
  end
90
95
  else
91
96
  ''
@@ -118,8 +123,11 @@ module RussianPhone
118
123
  end
119
124
 
120
125
  #def mongoize
121
- # valid? ? full : @phone
126
+ # @phone
122
127
  #end
128
+ # alias_method(:as_json, :mongoize)
129
+
130
+ alias_method(:as_json, :to_s)
123
131
  alias_method(:mongoize, :to_s)
124
132
 
125
133
  class << self
@@ -127,14 +135,36 @@ module RussianPhone
127
135
  string.tr('^0-9', '')
128
136
  end
129
137
 
138
+ #def _extract(string, subscriber_digits, code_digits)
139
+ # [string[-(subscriber_digits + code_digits), code_digits], string[-subscriber_digits,subscriber_digits]]
140
+ #end
141
+
130
142
  def _extract(string, subscriber_digits, code_digits)
131
- [string[-(subscriber_digits + code_digits), code_digits], string[-subscriber_digits,subscriber_digits]]
143
+ [string[0, code_digits], string[code_digits, subscriber_digits]]
132
144
  end
133
145
 
134
146
  def extract(string, subscriber_digits, code_digits)
135
147
  _extract(clean(string), subscriber_digits, code_digits)
136
148
  end
137
149
 
150
+ def _extra(string, position)
151
+ i = 0
152
+ digits = 0
153
+
154
+ string.each_char do |char|
155
+ if char.match(/[0-9]/)
156
+ digits += 1
157
+ end
158
+ i += 1
159
+ # puts "#{char} #{digits} #{i} #{position}"
160
+ if digits >= position
161
+ return string[i..-1].strip
162
+ end
163
+ end
164
+
165
+ ''
166
+ end
167
+
138
168
  def country_code(string)
139
169
  clean(string)[-10, 1]
140
170
  end
@@ -166,10 +196,6 @@ module RussianPhone
166
196
 
167
197
  clean_string = clean(string)
168
198
 
169
- if clean_string.length > 11
170
- return nil
171
- end
172
-
173
199
  if clean_string.length < 10
174
200
  if opts[:default_city].nil?
175
201
  return nil
@@ -186,22 +212,65 @@ module RussianPhone
186
212
  end
187
213
  end
188
214
 
215
+ extra_after = 10
216
+
217
+ if clean_string.length > 10 && string.starts_with?('+7') || string.starts_with?('8 ') || string.starts_with?('8(') || string.starts_with?('8-')
218
+ clean_string[0] = ''
219
+ extra_after += 1
220
+ end
221
+
222
+ if clean_string.length == 11 && string.starts_with?('7')
223
+ clean_string[0] = ''
224
+ extra_after += 1
225
+ end
226
+
227
+ if clean_string.length == 11 && string.starts_with?('8')
228
+ clean_string[0] = ''
229
+ extra_after += 1
230
+ end
231
+
232
+ # handles stuff like 89061010101 д. 123
233
+ if string.split(' ').length > 1 && string.split(/\D/)[0].length > 10
234
+ if string.starts_with?('7')
235
+ clean_string[0] = ''
236
+ extra_after += 1
237
+ end
238
+
239
+ if string.starts_with?('8')
240
+ clean_string[0] = ''
241
+ extra_after += 1
242
+ end
243
+ end
244
+
245
+ # handle 7906123-12-12 доб 123
246
+ if clean_string.length > 10 && extra_after == 10 && (clean_string[0] == '7' || clean_string[0] == '8')
247
+ result = ''
248
+ string.split(/\D/).each do |segm|
249
+ result += segm
250
+ break if result.length >= 10
251
+ end
252
+ if result.length > 10
253
+ clean_string[0] = ''
254
+ extra_after += 1
255
+ end
256
+ end
257
+
189
258
  code_3_digit, phone_7_digit = _extract(clean_string, 7, 3)
190
259
  if code_3_digit == '800' || Codes.cell_codes.include?(code_3_digit) || Codes.ndcs_with_7_subscriber_digits.include?(code_3_digit)
191
- return {country: opts[:default_country], city: code_3_digit, subscriber: phone_7_digit}
260
+ return {country: opts[:default_country], city: code_3_digit, subscriber: phone_7_digit, extra: _extra(string, extra_after)}
192
261
  end
193
262
 
194
263
  code_4_digit, phone_6_digit = _extract(clean_string, 6, 4)
195
264
  if Codes.ndcs_with_6_subscriber_digits.include? code_4_digit
196
- return {country: opts[:default_country], city: code_4_digit, subscriber: phone_6_digit}
265
+ return {country: opts[:default_country], city: code_4_digit, subscriber: phone_6_digit, extra: _extra(string, extra_after)}
197
266
  end
198
267
 
199
268
  code_5_digit, phone_5_digit = _extract(clean_string, 5, 5)
200
269
  if Codes.ndcs_with_5_subscriber_digits.include? code_5_digit
201
- return {country: opts[:default_country], city: code_5_digit, subscriber: phone_5_digit}
270
+ return {country: opts[:default_country], city: code_5_digit, subscriber: phone_5_digit, extra: _extra(string, extra_after)}
202
271
  end
203
272
 
204
- nil
273
+ return {country: opts[:default_country], city: code_3_digit, subscriber: phone_7_digit, extra: _extra(string, extra_after)}
205
274
  end
206
275
  end
207
276
  end
@@ -1,3 +1,3 @@
1
1
  module RussianPhone
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.4"
3
3
  end
@@ -121,7 +121,21 @@ describe RussianPhone do
121
121
  phone.full.should eq '+7 (4912) 12-34-56'
122
122
  end
123
123
 
124
- it 'should parse 12-34-56 number whith default city' do
124
+ it 'should parse 2-34-56 number whith default city' do
125
+ phone = RussianPhone::Number.new('2-34-56', default_country: 7, default_city: 87252)
126
+ phone.should_not be_nil
127
+ phone.valid?.should be_true
128
+
129
+ phone.cell?.should be_false
130
+ phone.free?.should be_false
131
+
132
+ phone.city.should eq '87252'
133
+ phone.country.should eq '7'
134
+ phone.subscriber.should eq '23456'
135
+ phone.full.should eq '+7 (87252) 2-34-56'
136
+ end
137
+
138
+ it 'should parse 12-34-56 number whith default city' do
125
139
  phone = RussianPhone::Number.new('12-34-56', default_country: 7, default_city: 4912)
126
140
  phone.should_not be_nil
127
141
  phone.valid?.should be_true
@@ -151,6 +165,92 @@ describe RussianPhone do
151
165
  phone.full.should eq '+7 (343) 565-67-89'
152
166
  end
153
167
 
168
+ it 'should parse 7 (906) 123-45-67 number correctly' do
169
+ # это номер в Екатеринбурге, с неправильно указанным кодом города
170
+
171
+ phone = RussianPhone::Number.new('7 (906) 123-45-67', default_country: 7)
172
+ phone.should_not be_nil
173
+ phone.valid?.should be_true
174
+
175
+ phone.cell?.should be_true
176
+ phone.free?.should be_false
177
+ phone.extra.should eq ''
178
+ phone.city.should eq '906'
179
+ phone.country.should eq '7'
180
+ phone.subscriber.should eq '1234567'
181
+ phone.full.should eq '+7 (906) 123-45-67'
182
+ end
183
+
184
+ it 'should handle phones with extra stuff [8 (906) 111-11-11 доб. 123]' do
185
+ phone = RussianPhone::Number.new('8 (906) 111-11-11 доб. 123', default_country: 7)
186
+ phone.should_not be_nil
187
+ phone.valid?.should be_true
188
+
189
+ phone.cell?.should be_true
190
+ phone.free?.should be_false
191
+
192
+ phone.city.should eq '906'
193
+ phone.country.should eq '7'
194
+ phone.subscriber.should eq '1111111'
195
+ phone.full.should eq '+7 (906) 111-11-11 доб. 123'
196
+ end
197
+
198
+ it 'should handle phones with extra stuff [8 (906) 111-11-11 д. 123]' do
199
+ phone = RussianPhone::Number.new('8 (906) 111-11-11 д. 123', default_country: 7)
200
+ phone.should_not be_nil
201
+ phone.valid?.should be_true
202
+
203
+ phone.cell?.should be_true
204
+ phone.free?.should be_false
205
+
206
+ phone.city.should eq '906'
207
+ phone.country.should eq '7'
208
+ phone.subscriber.should eq '1111111'
209
+ phone.full.should eq '+7 (906) 111-11-11 д. 123'
210
+ end
211
+
212
+ it 'should handle phones with extra stuff [89061010101 д. 123]' do
213
+ phone = RussianPhone::Number.new('89061010101 д. 123', default_country: 7)
214
+ phone.should_not be_nil
215
+ phone.valid?.should be_true
216
+
217
+ phone.cell?.should be_true
218
+ phone.free?.should be_false
219
+
220
+ phone.city.should eq '906'
221
+ phone.country.should eq '7'
222
+ phone.subscriber.should eq '1010101'
223
+ phone.full.should eq '+7 (906) 101-01-01 д. 123'
224
+ end
225
+
226
+ it 'should handle phones with extra stuff [89061010101-д. 123]' do
227
+ phone = RussianPhone::Number.new('89061010101-д. 123', default_country: 7)
228
+ phone.should_not be_nil
229
+ phone.valid?.should be_true
230
+
231
+ phone.cell?.should be_true
232
+ phone.free?.should be_false
233
+
234
+ phone.city.should eq '906'
235
+ phone.country.should eq '7'
236
+ phone.subscriber.should eq '1010101'
237
+ phone.full.should eq '+7 (906) 101-01-01 -д. 123'
238
+ end
239
+
240
+ it 'should handle phones with unknown codes [8 (533) 111-11-11]' do
241
+ phone = RussianPhone::Number.new('8 (533) 111-11-11', default_country: 7)
242
+ phone.should_not be_nil
243
+ phone.valid?.should be_true
244
+
245
+ phone.cell?.should be_false
246
+ phone.free?.should be_false
247
+
248
+ phone.city.should eq '533'
249
+ phone.country.should eq '7'
250
+ phone.subscriber.should eq '1111111'
251
+ phone.full.should eq '+7 (533) 111-11-11'
252
+ end
253
+
154
254
  tests = {
155
255
  '+79261234567' => [7, 926, 1234567],
156
256
  '89261234567' => [7, 926, 1234567],
@@ -187,6 +287,8 @@ describe RussianPhone do
187
287
  '7 (927) 12 342 34' => [7, 927, 1234234],
188
288
  '7-(927)-12-342-34' => [7, 927, 1234234],
189
289
  '7 84543 123 12' => [7, 84543, 12312],
290
+ '78454312312' => [7, 84543, 12312],
291
+ '88454312312' => [7, 84543, 12312],
190
292
  }
191
293
 
192
294
  tests.each_pair do |str, result|
@@ -212,10 +314,10 @@ describe RussianPhone do
212
314
 
213
315
  bad_phones = [
214
316
  '123 123',
215
- '11 11 11 11 11 11 11',
317
+ '000000',
216
318
  '123',
217
319
  'пыщ пыщ ололо я водитель НЛО',
218
- '11 11 11 11 1'
320
+ '11 1 11 1'
219
321
  ]
220
322
 
221
323
  bad_phones.each do |phone|
@@ -228,8 +330,15 @@ describe RussianPhone do
228
330
 
229
331
  describe 'when using ::Field' do
230
332
  it 'should serialize and deserialize correctly' do
333
+ RussianPhone::Number.new('8 (906) 111-11-11 д. 123').mongoize.should eq '+7 (906) 111-11-11 д. 123'
334
+
231
335
  RussianPhone::Number.new('495 111 11 11').mongoize.should eq '+7 (495) 111-11-11'
336
+
232
337
  RussianPhone::Number.demongoize('+7 (495) 111-11-11').mongoize.should eq '+7 (495) 111-11-11'
338
+
339
+ RussianPhone::Field.mongoize(RussianPhone::Number.new('495 111 11 11')).should eq '+7 (495) 111-11-11'
340
+ RussianPhone::Field.evolve(RussianPhone::Number.new('495 111 11 11')).should eq '+7 (495) 111-11-11'
341
+ RussianPhone::Field.evolve(RussianPhone::Number.new('495 111 11 11 доб 123')).should eq '+7 (495) 111-11-11 доб 123'
233
342
  end
234
343
  end
235
344
 
@@ -292,6 +401,81 @@ describe RussianPhone do
292
401
  u = UserWithValidation.new(phone: '495 121 11 11')
293
402
  u.valid?.should be_true
294
403
  u.save.should be_true
404
+ UserWithValidation.first.read_attribute(:phone).should eq '+7 (495) 121-11-11'
405
+ UserWithValidation.first.phone.should eq '+7 (495) 121-11-11'
406
+ end
407
+
408
+ it 'should pass validation when validate is on and phone is valid' do
409
+ u = UserWithValidation.new(phone: '7495 121 11 11')
410
+ u.valid?.should be_true
411
+ u.save.should be_true
412
+ UserWithValidation.first.read_attribute(:phone).should eq '+7 (495) 121-11-11'
413
+ UserWithValidation.first.phone.should eq '+7 (495) 121-11-11'
414
+ end
415
+
416
+ it 'should pass validation when validate is on and phone is valid' do
417
+ u = UserWithValidation.new(phone: '7 495 121 11 11')
418
+ u.valid?.should be_true
419
+ u.save.should be_true
420
+ UserWithValidation.first.read_attribute(:phone).should eq '+7 (495) 121-11-11'
421
+ UserWithValidation.first.phone.should eq '+7 (495) 121-11-11'
422
+ end
423
+
424
+ it 'should pass validation when validate is on and phone is valid' do
425
+ u = UserWithValidation.new(phone: '8495 121 11 11')
426
+ u.valid?.should be_true
427
+ u.save.should be_true
428
+ UserWithValidation.first.read_attribute(:phone).should eq '+7 (495) 121-11-11'
429
+ UserWithValidation.first.phone.should eq '+7 (495) 121-11-11'
430
+ end
431
+
432
+ it 'should pass validation when validate is on and phone is valid' do
433
+ u = UserWithValidation.new(phone: '7495123-12-12 доб 123')
434
+
435
+ u.valid?.should be_true
436
+ u.save.should be_true
437
+ UserWithValidation.first.read_attribute(:phone).should eq '+7 (495) 123-12-12 доб 123'
438
+ UserWithValidation.first.phone.should eq '+7 (495) 123-12-12 доб 123'
439
+ end
440
+
441
+ it 'should pass validation when phone is valid (unknown city code)' do
442
+ u = UserWithAnyCode.new(phone: '7701123-12-12 доб 123')
443
+ u.valid?.should be_true
444
+ u.save.should be_true
445
+ UserWithAnyCode.first.read_attribute(:phone).should eq '+7 (701) 123-12-12 доб 123'
446
+ UserWithAnyCode.first.phone.should eq '+7 (701) 123-12-12 доб 123'
447
+ end
448
+
449
+ it 'should pass validation when validate is on and phone is valid (unknown city code)' do
450
+ u = UserWithAnyCode.new(phone: '701123-12-12 доб 123')
451
+ u.valid?.should be_true
452
+ u.save.should be_true
453
+ UserWithAnyCode.first.read_attribute(:phone).should eq '+7 (701) 123-12-12 доб 123'
454
+ UserWithAnyCode.first.phone.should eq '+7 (701) 123-12-12 доб 123'
455
+ end
456
+
457
+ it 'should pass validation when validate is on and phone is valid' do
458
+ u = UserWithValidation.new(phone: '8 495 121 11 11')
459
+ u.valid?.should be_true
460
+ u.save.should be_true
461
+ UserWithValidation.first.read_attribute(:phone).should eq '+7 (495) 121-11-11'
462
+ UserWithValidation.first.phone.should eq '+7 (495) 121-11-11'
463
+ end
464
+
465
+ it 'should pass validation when validate is on and phone is valid' do
466
+ u = UserWithValidation.new(phone: '+7 495 121 11 11')
467
+ u.valid?.should be_true
468
+ u.save.should be_true
469
+ UserWithValidation.first.read_attribute(:phone).should eq '+7 (495) 121-11-11'
470
+ UserWithValidation.first.phone.should eq '+7 (495) 121-11-11'
471
+ end
472
+
473
+ it 'should pass validation when validate is on and phone is valid' do
474
+ u = UserWithValidation.new(phone: '495 121 11 11 доб 123')
475
+ u.valid?.should be_true
476
+ u.save.should be_true
477
+ UserWithValidation.first.read_attribute(:phone).should eq '+7 (495) 121-11-11 доб 123'
478
+ UserWithValidation.first.phone.should eq '+7 (495) 121-11-11 доб 123'
295
479
  end
296
480
 
297
481
  it 'should fail validation when validate is on and city is not in allowed_cities' do
@@ -0,0 +1,7 @@
1
+ # coding: utf-8
2
+
3
+ class UserWithAnyCode
4
+ include Mongoid::Document
5
+
6
+ field :phone, type: RussianPhone.field(default_country: 7), validate: true
7
+ end
@@ -0,0 +1,33 @@
1
+ #!/bin/bash
2
+
3
+ if ! which md5sum > /dev/null; then
4
+ echo Install md5sum
5
+ exit 1
6
+ fi
7
+
8
+ if ! which curl > /dev/null; then
9
+ echo Install curl
10
+ exit 1
11
+ fi
12
+
13
+ home=$(gem env GEM_HOME)
14
+ cache=$home/cache
15
+
16
+ echo This will take a while...
17
+
18
+ for gem in $cache/*.gem; do
19
+ gemfile=$(basename $gem)
20
+
21
+ local=$(md5sum $gem | awk '{print $1}')
22
+ remote=$(curl -s -D - -X HEAD -H 'Connection:close' http://production.cf.rubygems.org/gems/$gemfile | grep 'ETag' | cut -d '"' -f 2)
23
+
24
+ # echo $gemfile local: $local, remote: $remote
25
+
26
+ if [[ ! $local = $remote ]]; then
27
+ echo $gemfile mismatch. local: $local, remote: $remote
28
+ fi
29
+
30
+
31
+ done
32
+
33
+ echo All done.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: russian_phone
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-28 00:00:00.000000000 Z
12
+ date: 2013-02-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mongoid
@@ -114,8 +114,10 @@ files:
114
114
  - spec/phone_spec.rb
115
115
  - spec/spec_helper.rb
116
116
  - spec/support/user.rb
117
+ - spec/support/user_with_any_code.rb
117
118
  - spec/support/user_with_validation.rb
118
119
  - spec/support/user_without_validation.rb
120
+ - validate.sh
119
121
  homepage: https://github.com/glebtv/russian_phone
120
122
  licenses: []
121
123
  post_install_message:
@@ -136,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
136
138
  version: '0'
137
139
  requirements: []
138
140
  rubyforge_project:
139
- rubygems_version: 1.8.25
141
+ rubygems_version: 1.8.24
140
142
  signing_key:
141
143
  specification_version: 3
142
144
  summary: Поле для хранения Российских телефонных номеров в Mongoid
@@ -144,5 +146,6 @@ test_files:
144
146
  - spec/phone_spec.rb
145
147
  - spec/spec_helper.rb
146
148
  - spec/support/user.rb
149
+ - spec/support/user_with_any_code.rb
147
150
  - spec/support/user_with_validation.rb
148
151
  - spec/support/user_without_validation.rb