phony 1.0.1 → 1.1.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.
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