phony 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/README.textile +14 -2
  2. data/lib/phony.rb +58 -463
  3. data/lib/phony/countries/all_other.rb +417 -0
  4. data/lib/phony/countries/austria.rb +69 -0
  5. data/lib/phony/countries/egypt.rb +40 -0
  6. data/lib/phony/countries/germany.rb +156 -0
  7. data/lib/phony/countries/greece.rb +30 -0
  8. data/lib/phony/countries/hungary.rb +23 -0
  9. data/lib/phony/countries/italy.rb +105 -0
  10. data/lib/phony/country.rb +102 -0
  11. data/lib/phony/country_codes.rb +102 -0
  12. data/lib/phony/local_splitter.rb +46 -0
  13. data/lib/phony/national_code.rb +27 -0
  14. data/lib/phony/national_splitters/fixed.rb +36 -0
  15. data/lib/phony/national_splitters/variable.rb +64 -0
  16. data/lib/phony/vanity.rb +35 -0
  17. data/spec/lib/phony/countries/austria_spec.rb +24 -0
  18. data/spec/lib/phony/countries/egypt_spec.rb +18 -0
  19. data/spec/lib/phony/countries/germany_spec.rb +24 -0
  20. data/spec/lib/phony/countries/greece_spec.rb +18 -0
  21. data/spec/lib/phony/countries/hungary_spec.rb +18 -0
  22. data/spec/lib/phony/countries/switzerland_spec.rb +18 -0
  23. data/spec/lib/phony/country_codes_spec.rb +110 -0
  24. data/spec/lib/phony/country_spec.rb +91 -0
  25. data/spec/lib/phony/local_splitter_spec.rb +48 -0
  26. data/spec/lib/phony/national_code_spec.rb +36 -0
  27. data/spec/lib/phony/national_splitters/fixed_spec.rb +43 -0
  28. data/spec/lib/phony/national_splitters/variable_spec.rb +35 -0
  29. data/spec/lib/phony/vanity_spec.rb +34 -0
  30. data/spec/lib/phony_spec.rb +117 -238
  31. metadata +45 -21
  32. data/lib/ndc/austria.rb +0 -69
  33. data/lib/ndc/fixed_size.rb +0 -113
  34. data/lib/ndc/germany.rb +0 -157
  35. data/lib/ndc/prefix.rb +0 -67
  36. data/lib/ndc/splitter.rb +0 -81
  37. data/spec/lib/ndc/austria_spec.rb +0 -40
  38. data/spec/lib/ndc/fixed_size_spec.rb +0 -65
  39. data/spec/lib/ndc/germany_spec.rb +0 -40
  40. data/spec/lib/ndc/prefix_spec.rb +0 -25
  41. data/spec/lib/ndc/splitter_spec.rb +0 -59
@@ -0,0 +1,102 @@
1
+ module Phony
2
+
3
+ # Handles determining the correct national code handler.
4
+ #
5
+ class CountryCodes
6
+
7
+ def normalize number
8
+ # Remove non-digit chars.
9
+ #
10
+ number.gsub! /\D*/, ''
11
+ remove_relative_zeros! number
12
+ end
13
+
14
+ # Splits this number into cc, ndc and locally split number parts.
15
+ #
16
+ def split number
17
+ national_handler, cc, rest = split_cc number
18
+ [cc, *national_handler.split(rest)]
19
+ end
20
+
21
+ def formatted number, options = {}
22
+ format_cc_ndc_local options[:format], options[:spaces] || ' ', *split(number)
23
+ end
24
+ # Formats country code and national destination code.
25
+ #
26
+ def format_cc_ndc_local format, space, cc, ndc, *parts
27
+ "#{format_cc_ndc(format, space, cc, ndc)}#{format_local(space, parts)}"
28
+ end
29
+ def format_cc_ndc format, space, cc, ndc
30
+ format, split_phone_number = case format
31
+ when nil, :international_absolute, :international, :+
32
+ [ndc.blank? ? '+%s%s' : '+%s%s%s%s', [cc, space, ndc, space]]
33
+ when :international_relative
34
+ [ndc.blank? ? '00%s%s' : '00%s%s%s%s', [cc, space, ndc, space]]
35
+ when :national
36
+ [ndc.blank? ? '' : '0%s%s', [ndc, space]]
37
+ when :local
38
+ ['', []]
39
+ end
40
+ format % split_phone_number
41
+ end
42
+ def format_local space, parts_ary
43
+ parts_ary.join space.to_s
44
+ end
45
+
46
+ # TODO Speed these methods up.
47
+ #
48
+ def service? number
49
+ national_handler, cc, rest = split_cc number
50
+ national_handler.service? rest
51
+ end
52
+ def mobile? number
53
+ national_handler, cc, rest = split_cc number
54
+ national_handler.mobile? rest
55
+ end
56
+ def landline? number
57
+ national_handler, cc, rest = split_cc number
58
+ national_handler.landline? rest
59
+ end
60
+
61
+ # Is the given number a vanity number?
62
+ #
63
+ def vanity? number
64
+ national_handler, _, rest = split_cc number
65
+ national_handler.vanity? rest
66
+ end
67
+ # Converts a vanity number into a normalized E164 number.
68
+ #
69
+ def vanity_to_number vanity_number
70
+ national_handler, cc, rest = split_cc vanity_number
71
+ "#{cc}#{national_handler.vanity_to_number(rest)}"
72
+ end
73
+
74
+ def split_cc rest
75
+ presumed_cc = ''
76
+ 1.upto(3) do |i|
77
+ presumed_cc << rest.slice!(0..0)
78
+ national_code_handler = mapping[i][presumed_cc]
79
+ return [national_code_handler, presumed_cc, rest] if national_code_handler
80
+ end
81
+ # TODO raise
82
+ end
83
+
84
+ # Removes 0s from partially normalized numbers
85
+ # such as 410443643533.
86
+ #
87
+ # Example:
88
+ # 410443643533 -> 41443643533
89
+ def remove_relative_zeros! phone_number
90
+ _, cc, rest = split_cc phone_number
91
+ '%s%s' % [cc, rest].collect! { |code| code.gsub(/^0+/, '') }
92
+ end
93
+
94
+ # Cached mapping of all countries.
95
+ #
96
+ def mapping
97
+ @mapping ||= Phony::Countries.mapping
98
+ end
99
+
100
+ end
101
+
102
+ end
@@ -0,0 +1,46 @@
1
+ module Phony
2
+
3
+ # Local splitter class to split the last part of
4
+ # a number, i.e. minus cc or ndc.
5
+ #
6
+ # Countries can create new instances according to their needs.
7
+ #
8
+ # Note: Countries should use instance_for
9
+ # to avoid getting new local splitter instances.
10
+ #
11
+ class LocalSplitter
12
+
13
+ @mapping = {}
14
+
15
+ # Get a splitter for the given format.
16
+ #
17
+ # Caches the created splitter for the given format.
18
+ #
19
+ def self.instance_for format = nil
20
+ @mapping[format] ||= new(format)
21
+ end
22
+
23
+ # Initialize with a local format, like [3, 2, 2] (also the default).
24
+ #
25
+ # The format [3, 2, 2] splits a number like '3332222' into ['333', '22', '22'].
26
+ #
27
+ def initialize format = nil
28
+ @format = format || [3, 2, 2]
29
+ end
30
+
31
+ # Split a local number according to an assumed country specific format.
32
+ #
33
+ # Examples
34
+ # * split '3643533' # => ['364', '35', '33'] # (Switzerland)
35
+ #
36
+ def split number
37
+ @format.inject([]) do |result, size|
38
+ result << number.slice!(0..size-1)
39
+ return result if number.empty?
40
+ result
41
+ end
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,27 @@
1
+ module Phony
2
+
3
+ # This is the superclass of all special national number handlers.
4
+ #
5
+ # NationalCodes have a special numbers splitter, a national code splitter and a local code splitter.
6
+ #
7
+ class NationalCode
8
+
9
+ #
10
+ #
11
+ def initialize national_splitter, local_splitter
12
+ @national_splitter = national_splitter
13
+ @local_splitter = local_splitter
14
+ end
15
+
16
+ # Split gets a number without country code and splits it into
17
+ # its parts.
18
+ #
19
+ def split national_number
20
+ ndc, rest = @national_splitter.split national_number.dup
21
+ return ndc unless rest
22
+ [ndc, *@local_splitter.split(rest)]
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,36 @@
1
+ module Phony
2
+
3
+ module NationalSplitters
4
+
5
+ # TODO
6
+ #
7
+ class Fixed
8
+
9
+ attr_writer :special_splitter
10
+
11
+ @mapping = {}
12
+
13
+ # Get a splitter for the given format.
14
+ #
15
+ # Caches the created splitter for the given format.
16
+ #
17
+ def self.instance_for size
18
+ @mapping[size] ||= new(size)
19
+ end
20
+
21
+ def initialize size
22
+ @size = size
23
+ end
24
+
25
+ # Takes a national number and splits it into ndc and rest.
26
+ #
27
+ def split national_number
28
+ return [national_number] unless @size
29
+ [national_number.slice!(0...@size), national_number]
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,64 @@
1
+ module Phony
2
+
3
+ module NationalSplitters
4
+
5
+ class Variable < Fixed
6
+
7
+ #
8
+ #
9
+ def initialize fallback, ndc_map
10
+ super fallback
11
+ @ndcs = restructure ndc_map
12
+ end
13
+
14
+ # Takes a national number and splits it into ndc and rest.
15
+ #
16
+ def split national_number
17
+ fallback_number = national_number.dup
18
+
19
+ # Extract a starting point.
20
+ #
21
+ presumed_code = if @mapped_ndc_min_length > 0
22
+ national_number.slice!(0..@mapped_ndc_min_length-1)
23
+ else
24
+ ''
25
+ end
26
+
27
+ # Try for all possible mapped.
28
+ #
29
+ @mapped_ndc_min_length.upto(@mapped_ndc_max_length) do |i|
30
+ sized_ndcs = @ndcs[i]
31
+ return [presumed_code, national_number] unless sized_ndcs && !sized_ndcs.include?(presumed_code)
32
+ presumed_code << national_number.slice!(0..0)
33
+ end
34
+
35
+ # Not found.
36
+ #
37
+ return super(fallback_number)
38
+ end
39
+
40
+ private
41
+
42
+ def restructure ndc_map
43
+ optimize ndc_map.values.flatten
44
+ end
45
+
46
+ # Optimizes and restructures the given ndcs array.
47
+ #
48
+ def optimize(ndc_ary)
49
+ ndcs = {}
50
+ ndc_ary.each do |ndc|
51
+ ndcs[ndc.length] ||= []
52
+ ndcs[ndc.length] << ndc
53
+ end
54
+ keys = ndcs.keys
55
+ @mapped_ndc_min_length = keys.min # || 1
56
+ @mapped_ndc_max_length = keys.max
57
+ ndcs
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -0,0 +1,35 @@
1
+ module Phony
2
+ module Vanity
3
+
4
+ # Returns a char to number mapping string for the String#tr method.
5
+ #
6
+ def self.mapping
7
+ @@mapping ||= [
8
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.freeze,
9
+ '2223334445556667777888999922233344455566677778889999'.freeze
10
+ ]
11
+ end
12
+
13
+ # Replaces (and normalizes) vanity characters of passed number with correct digits.
14
+ #
15
+ def self.replace number
16
+ number.tr *mapping
17
+ end
18
+
19
+ # Returns true if there is a character in the number
20
+ # after the first four numbers.
21
+ #
22
+ @@vanity_regexp = /\A\d{3}[a-zA-Z]{6,12}\Z/
23
+ def self.vanity? number
24
+ !(normalized(number) =~ @@vanity_regexp).nil?
25
+ end
26
+
27
+ # Vanity-Normalized.
28
+ #
29
+ @@vanity_normalizing_regexp = /^0*|[^\d\w]/
30
+ def self.normalized number
31
+ number.gsub @@vanity_normalizing_regexp, ''
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Phony::Countries::Austria do
4
+
5
+ before(:each) do
6
+ @austria = Phony::Countries::Austria
7
+ end
8
+
9
+ describe "split" do
10
+ it "should handle Vienna" do
11
+ @austria.split('198110').should == ['1', '98110']
12
+ end
13
+ it "should handle some mobile services" do
14
+ @austria.split('66914093902').should == ['669', '14093902']
15
+ end
16
+ it "should handle Graz" do
17
+ @austria.split('3161234567891').should == ['316', '1234567891']
18
+ end
19
+ it "should handle Rohrau" do
20
+ @austria.split('2164123456789').should == ['2164', '123456789']
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Phony::Countries::Egypt do
4
+
5
+ before(:each) do
6
+ @egypt = Phony::Countries::Egypt
7
+ end
8
+
9
+ describe "split" do
10
+ it "works" do
11
+ @egypt.split('233453756').should == ['2', '33453756']
12
+ end
13
+ it "works" do
14
+ @egypt.split('921234567').should == ['92', '1234567']
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Phony::Countries::Germany do
4
+
5
+ before(:each) do
6
+ @germany = Phony::Countries::Germany
7
+ end
8
+
9
+ describe "split" do
10
+ it "should handle Berlin" do
11
+ @germany.split('3038625454').should == ['30', '386', '25454']
12
+ end
13
+ it "should handle Cologne" do
14
+ @germany.split('22137683323').should == ['221', '376', '83323']
15
+ end
16
+ it "should handle Freiburg im Breisgau" do
17
+ @germany.split('7614767676').should == ['761', '476', '7676']
18
+ end
19
+ it "should handle Nettetal-Lobberich" do
20
+ @germany.split('21535100').should == ['2153', '510', '0']
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Phony::Countries::Greece do
4
+
5
+ before(:each) do
6
+ @greece = Phony::Countries::Greece
7
+ end
8
+
9
+ describe "split" do
10
+ it 'works' do
11
+ @greece.split('21123456').should == ['21', '123456']
12
+ end
13
+ it 'works' do
14
+ @greece.split('25941234').should == ['2594', '1234']
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Phony::Countries::Hungary do
4
+
5
+ before(:each) do
6
+ @hungary = Phony::Countries::Hungary
7
+ end
8
+
9
+ describe "split" do
10
+ it 'handles Budapest' do
11
+ @hungary.split('12345678').should == ['1', '234', '5678']
12
+ end
13
+ it 'works' do
14
+ @hungary.split('22123456').should == ['22', '123', '456']
15
+ end
16
+ end
17
+
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Switzerland' do
4
+
5
+ before(:each) do
6
+ @switzerland = Phony::Countries.with_cc '41'
7
+ end
8
+
9
+ describe "split" do
10
+ it "works" do
11
+ @switzerland.split('443643532').should == ['44', '364', '35', '32']
12
+ end
13
+ it "works" do
14
+ @switzerland.split('800123456').should == ['800', '123', '456']
15
+ end
16
+ end
17
+
18
+ end