phonetic 1.0.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 (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +98 -0
  7. data/Rakefile +1 -0
  8. data/lib/phonetic.rb +10 -0
  9. data/lib/phonetic/algorithm.rb +24 -0
  10. data/lib/phonetic/caverphone.rb +68 -0
  11. data/lib/phonetic/caverphone2.rb +69 -0
  12. data/lib/phonetic/core_ext/string.rb +3 -0
  13. data/lib/phonetic/core_ext/string/caverphone.rb +11 -0
  14. data/lib/phonetic/core_ext/string/caverphone2.rb +11 -0
  15. data/lib/phonetic/core_ext/string/double_metaphone.rb +18 -0
  16. data/lib/phonetic/core_ext/string/metaphone.rb +12 -0
  17. data/lib/phonetic/core_ext/string/nysiis.rb +12 -0
  18. data/lib/phonetic/core_ext/string/refined_soundex.rb +12 -0
  19. data/lib/phonetic/core_ext/string/soundex.rb +12 -0
  20. data/lib/phonetic/double_metaphone.rb +640 -0
  21. data/lib/phonetic/metaphone.rb +161 -0
  22. data/lib/phonetic/metaphone2.rb +5 -0
  23. data/lib/phonetic/nysiis.rb +63 -0
  24. data/lib/phonetic/refined_soundex.rb +39 -0
  25. data/lib/phonetic/soundex.rb +39 -0
  26. data/lib/phonetic/version.rb +3 -0
  27. data/phonetic.gemspec +26 -0
  28. data/spec/phonetic/algorithm_spec.rb +15 -0
  29. data/spec/phonetic/caverphone2_spec.rb +66 -0
  30. data/spec/phonetic/caverphone_spec.rb +115 -0
  31. data/spec/phonetic/core_ext/string/caverphone2_spec.rb +9 -0
  32. data/spec/phonetic/core_ext/string/caverphone_spec.rb +9 -0
  33. data/spec/phonetic/core_ext/string/double_metaphone_spec.rb +15 -0
  34. data/spec/phonetic/core_ext/string/metaphone_spec.rb +11 -0
  35. data/spec/phonetic/core_ext/string/nysiis_spec.rb +12 -0
  36. data/spec/phonetic/core_ext/string/refined_soundex_spec.rb +10 -0
  37. data/spec/phonetic/core_ext/string/soundex_spec.rb +14 -0
  38. data/spec/phonetic/double_metaphone_spec.rb +16 -0
  39. data/spec/phonetic/metaphone2_spec.rb +9 -0
  40. data/spec/phonetic/metaphone_spec.rb +81 -0
  41. data/spec/phonetic/nysiis_spec.rb +20 -0
  42. data/spec/phonetic/refined_soundex_spec.rb +13 -0
  43. data/spec/phonetic/soundex_spec.rb +24 -0
  44. data/spec/spec_helper.rb +11 -0
  45. data/spec/support/double_metaphone_data.rb +142 -0
  46. data/spec/support/nysiis_data.rb +31 -0
  47. metadata +180 -0
@@ -0,0 +1,161 @@
1
+ require 'phonetic/algorithm'
2
+
3
+ module Phonetic
4
+ # Metaphone is a phonetic algorithm, published by Lawrence Philips in 1990,
5
+ # for indexing words by their English pronunciation.
6
+ # This class implements this algorithm.
7
+ # @see http://aspell.net/metaphone/metaphone.basic Original Basic code by Lawrence Philips (1990)
8
+ # @example
9
+ # Phonetic::Metaphone.encode('Accola') # => 'AKKL'
10
+ # Phonetic::Metaphone.encode('Nikki') # => 'NK'
11
+ # Phonetic::Metaphone.encode('Wright') #=> 'RT'
12
+ class Metaphone < Algorithm
13
+ VOWELS = 'AEIOU'
14
+ FRONT_VOWELS = 'EIY'
15
+ VARSON = 'CSPTG'
16
+
17
+ # Encode word to its Metaphone code
18
+ def self.encode_word(word, options = { size: 4 })
19
+ code_size = options[:size] || 4
20
+ w = word.upcase.gsub(/[^A-Z]/, '')
21
+ return if w.empty?
22
+ two = w[0, 2]
23
+ if ['PN', 'AE', 'KN', 'GN', 'WR'].include?(two) then w[0] = '' end
24
+ if w[0] == 'X' then w[0] = 'S' end
25
+ if two == 'WH' then w[1] = '' end
26
+ l = w.size
27
+ metaph = ''
28
+ for n in 0..(l - 1)
29
+ break unless metaph.size < code_size
30
+ symb = w[n]
31
+ if !(symb != 'C' && n > 0 && w[n - 1] == symb)
32
+ case
33
+ when vowel?(symb) && n == 0
34
+ metaph = symb
35
+ when symb == 'B'
36
+ unless n == l - 1 && w[n - 1] == 'M'
37
+ metaph = metaph + symb
38
+ end
39
+ when symb == 'C'
40
+ if !(n > 0 && w[n - 1] == 'S' && front_vowel?(w[n + 1]))
41
+ if w[n + 1, 2] == 'IA'
42
+ metaph = metaph + 'X'
43
+ else
44
+ if front_vowel?(w[n + 1])
45
+ metaph = metaph + 'S'
46
+ else
47
+ if n > 0 && w[n + 1] == 'H' && w[n - 1] == 'S'
48
+ metaph = metaph + 'K'
49
+ else
50
+ if w[n + 1] == 'H'
51
+ if n == 0 && !vowel?(w[n + 2])
52
+ metaph = metaph + 'K'
53
+ else
54
+ metaph = metaph + 'X'
55
+ end
56
+ else
57
+ metaph = metaph + 'K'
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ when symb == 'D'
64
+ if w[n + 1] == 'G' && front_vowel?(w[n + 2])
65
+ metaph = metaph + 'J'
66
+ else
67
+ metaph = metaph + 'T'
68
+ end
69
+ when symb == 'G'
70
+ silent = (w[n + 1] == 'H' && !vowel?(w[n + 2]))
71
+ if n > 0 && (w[n + 1] == 'N' || w[n + 1, 3] == 'NED')
72
+ silent = true
73
+ end
74
+ if n > 0 && w[n - 1] == 'D' && front_vowel?(w[n + 1])
75
+ silent = true
76
+ end
77
+ hard = (n > 0 && w[n - 1] == 'G')
78
+ unless silent
79
+ if front_vowel?(w[n + 1]) && !hard
80
+ metaph = metaph + 'J'
81
+ else
82
+ metaph = metaph + 'K'
83
+ end
84
+ end
85
+ when symb == 'H'
86
+ if !(n == l - 1 || (n > 0 && VARSON[w[n - 1]]))
87
+ if vowel?(w[n + 1])
88
+ metaph = metaph + 'H'
89
+ end
90
+ end
91
+ when 'FJLMNR'[symb]
92
+ metaph = metaph + symb
93
+ when symb == 'K'
94
+ if n > 0 && w[n - 1] != 'C'
95
+ metaph = metaph + 'K'
96
+ else
97
+ if n == 0
98
+ metaph = 'K'
99
+ end
100
+ end
101
+ when symb == 'P'
102
+ if w[n + 1] == 'H'
103
+ metaph = metaph + 'F'
104
+ else
105
+ metaph = metaph + 'P'
106
+ end
107
+ when symb == 'Q'
108
+ metaph = metaph + 'K'
109
+ when symb == 'S'
110
+ if w[n + 1] == 'I' && (w[n + 2] == 'O' || w[n + 2] == 'A')
111
+ metaph += 'X'
112
+ else
113
+ if w[n + 1] == 'H'
114
+ metaph += 'X'
115
+ else
116
+ metaph += 'S'
117
+ end
118
+ end
119
+ when symb == 'T'
120
+ if w[n + 1] == 'I' && (w[n + 2] == 'O' || w[n + 2] == 'A')
121
+ metaph = metaph + 'X'
122
+ else
123
+ if w[n + 1] == 'H'
124
+ if !(n > 0 && w[n - 1] == 'T')
125
+ metaph = metaph + '0'
126
+ end
127
+ else
128
+ if !(w[n + 1] == 'C' && w[n + 2] == 'H')
129
+ metaph = metaph + 'T'
130
+ end
131
+ end
132
+ end
133
+ when symb == 'V'
134
+ metaph = metaph + 'F'
135
+ when symb == 'W' || symb == 'Y'
136
+ if vowel?(w[n + 1])
137
+ metaph = metaph + symb
138
+ end
139
+ when symb == 'X'
140
+ metaph = metaph + 'KS'
141
+ when symb == 'Z'
142
+ metaph = metaph + 'S'
143
+ end
144
+ end
145
+ end
146
+ metaph
147
+ end
148
+
149
+ private
150
+
151
+ def self.vowel?(symbol)
152
+ v = VOWELS[symbol.to_s]
153
+ !v.nil? && !v.empty?
154
+ end
155
+
156
+ def self.front_vowel?(symbol)
157
+ v = FRONT_VOWELS[symbol.to_s]
158
+ !v.nil? && !v.empty?
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,5 @@
1
+ require 'phonetic/double_metaphone'
2
+
3
+ module Phonetic
4
+ Metaphone2 = DoubleMetaphone
5
+ end
@@ -0,0 +1,63 @@
1
+ require 'phonetic/algorithm'
2
+
3
+ module Phonetic
4
+ # This class implements original version of NYSIIS algorithm.
5
+ # @example
6
+ # Phonetic::NYSIIS.encode('Alexandra') # => 'ALAXANDR'
7
+ # Phonetic::NYSIIS.encode('Aumont') # => 'AANAD'
8
+ # Phonetic::NYSIIS.encode('Bonnie') # => 'BANY'
9
+ class NYSIIS < Algorithm
10
+ FIRST_CHAR_TABLE = {
11
+ /^MAC/ => 'MCC',
12
+ /^KN/ => 'NN',
13
+ /^K/ => 'C',
14
+ /^(PH|PF)/ => 'FF',
15
+ /^SCH/ => 'SSS'
16
+ }
17
+
18
+ LAST_CHAR_TABLE = {
19
+ /(EE|IE)$/ => 'Y',
20
+ /(DT|RT|RD|NT|ND)$/ => 'D'
21
+ }
22
+
23
+ REMAINING_TABLE = {
24
+ 'EV' => 'AF',
25
+ /[AEIOU]+/ => 'A',
26
+ 'Q' => 'G',
27
+ 'Z' => 'S',
28
+ 'M' => 'N',
29
+ 'KN' => 'N',
30
+ 'K' => 'C',
31
+ 'SCH' => 'SSS',
32
+ 'PH' => 'FF',
33
+ /([^AEIOU])H/ => '\1',
34
+ /(.)H[^AEIOU]/ => '\1',
35
+ /[AEIOU]W/ => 'A'
36
+ }
37
+
38
+ LAST_TABLE = {
39
+ /S$/ => '',
40
+ /AY$/ => 'Y',
41
+ /A$/ => ''
42
+ }
43
+
44
+ # Convert word to its NYSIIS code
45
+ def self.encode_word(word, options = { trim: true })
46
+ return if !word or word.empty?
47
+ trim = options[:trim]
48
+ w = word.upcase
49
+ w.gsub!(/[^A-Z]/, '')
50
+ return if w.empty?
51
+ FIRST_CHAR_TABLE.each{ |rx, str| break if w.sub!(rx, str) }
52
+ LAST_CHAR_TABLE.each{ |rx, str| w.sub!(rx, str) }
53
+ first = w[0]
54
+ w = w[1...w.size].to_s
55
+ REMAINING_TABLE.each{ |rx, str| w.gsub!(rx, str) }
56
+ LAST_TABLE.each{ |rx, str| w.gsub!(rx, str) }
57
+ w.gsub!(/[^\w\s]|(.)(?=\1)/, '') # remove duplicates
58
+ w = first + w
59
+ w = w[0..5] if trim
60
+ w
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,39 @@
1
+ require 'phonetic/algorithm'
2
+
3
+ module Phonetic
4
+ # Class for encoding string to Refined Soundex code.
5
+ # A refined soundex code is optimized for spell checking words.
6
+ #
7
+ # @example
8
+ # Phonetic::RefinedSoundex.encode('Caren') # => 'C30908'
9
+ # Phonetic::RefinedSoundex.encode('Hayers') # => 'H093'
10
+ # Phonetic::RefinedSoundex.encode('Lambard') # => 'L7081096'
11
+ class RefinedSoundex < Algorithm
12
+ CODE = {
13
+ B: 1, P: 1,
14
+ F: 2, V: 2,
15
+ C: 3, K: 3, S: 3,
16
+ G: 4, J: 4,
17
+ Q: 5, X: 5, Z: 5,
18
+ D: 6, T: 6,
19
+ L: 7,
20
+ M: 8, N: 8,
21
+ R: 9
22
+ }
23
+
24
+ # Encode word to its Refined Soundex value
25
+ def self.encode_word(word, options = {})
26
+ w = word.upcase
27
+ res = w[0]
28
+ pg = nil
29
+ w.chars.each do |c|
30
+ g = CODE[c.to_sym] || 0
31
+ if pg != g
32
+ res += g.to_s
33
+ pg = g
34
+ end
35
+ end
36
+ res
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,39 @@
1
+ require 'phonetic/algorithm'
2
+
3
+ module Phonetic
4
+ # Soundex phonetic algorithm was developed by Robert C. Russell and Margaret K. Odell.
5
+ # This class implements American Soundex version of algorithm.
6
+ #
7
+ # @example
8
+ # Phonetic::Soundex.encode('Ackerman') # => 'A265'
9
+ # Phonetic::Soundex.encode('ammonium') # => 'A500'
10
+ # Phonetic::Soundex.encode('implementation') # => 'I514'
11
+ class Soundex < Algorithm
12
+ CODE = {
13
+ B: 1, P: 1, F: 1, V: 1,
14
+ C: 2, S: 2, K: 2, G: 2, J: 2, Q: 2, X: 2, Z: 2,
15
+ D: 3, T: 3,
16
+ L: 4,
17
+ M: 5, N: 5,
18
+ R: 6
19
+ }
20
+
21
+ # Convert word to its Soundex code
22
+ def self.encode_word(word, options = {})
23
+ return '' if word.empty?
24
+ w = word.upcase
25
+ res = w[0]
26
+ pg = CODE[w[0].to_sym]
27
+ (1...w.size).each do |i|
28
+ g = CODE[w[i].to_sym]
29
+ if g and pg != g
30
+ res += g.to_s
31
+ pg = g
32
+ end
33
+ break if res.size > 3
34
+ end
35
+ res = res.ljust(4, '0')
36
+ res
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,3 @@
1
+ module Phonetic
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'phonetic/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'phonetic'
8
+ spec.version = Phonetic::VERSION
9
+ spec.authors = ['n7v']
10
+ spec.email = ['novsem@gmail.com']
11
+ spec.description = %q{Ruby library for phonetic algorithms.}
12
+ spec.summary = %q{Ruby library for phonetic algorithms. It supports Soundex, Metaphone, Caverphone, NYSIIS and others}
13
+ spec.homepage = 'http://github.com/n7v/phonetic'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
22
+ spec.add_development_dependency 'rake'
23
+ spec.add_development_dependency 'rspec'
24
+ spec.add_development_dependency 'simplecov'
25
+ spec.add_development_dependency 'yard'
26
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Phonetic::Algorithm do
4
+ describe '.encode_word' do
5
+ it 'should return not modified word' do
6
+ Phonetic::Algorithm.encode_word('cat').should == 'cat'
7
+ end
8
+ end
9
+
10
+ describe '.encode' do
11
+ it 'should return list of words without extra spaces' do
12
+ Phonetic::Algorithm.encode(' cat dog ').should == 'cat dog'
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ # Examples are taken from Caversham Project's paper
4
+ # http://caversham.otago.ac.nz/files/working/ctp150804.pdf
5
+ CAVERPHONE2_TEST_TABLE = {
6
+ 'STFNSN1111' => ['Stevenson'],
7
+ 'PTA1111111' => ['Peter'],
8
+ 'AT11111111' => [
9
+ 'add', 'aid', 'at', 'art', 'eat', 'earth', 'head', 'hit', 'hot',
10
+ 'hold', 'hard', 'heart', 'it', 'out', 'old'
11
+ ],
12
+ 'RTA1111111' => ['rather', 'ready', 'writer'],
13
+ 'SSA1111111' => ['social'],
14
+ 'APA1111111' => ['able', 'appear'],
15
+ 'TTA1111111' => [
16
+ 'Darda', 'Datha', 'Dedie', 'Deedee', 'Deerdre', 'Deidre', 'Deirdre',
17
+ 'Detta', 'Didi', 'Didier', 'Dido', 'Dierdre', 'Dieter', 'Dita',
18
+ 'Ditter', 'Dodi', 'Dodie', 'Dody', 'Doherty', 'Dorthea', 'Dorthy',
19
+ 'Doti', 'Dotti', 'Dottie', 'Dotty', 'Doty', 'Doughty', 'Douty',
20
+ 'Dowdell', 'Duthie', 'Tada', 'Taddeo', 'Tadeo', 'Tadio', 'Tati',
21
+ 'Teador', 'Tedda', 'Tedder', 'Teddi', 'Teddie', 'Teddy', 'Tedi',
22
+ 'Tedie', 'Teeter', 'Teodoor', 'Teodor', 'Terti', 'Theda', 'Theodor',
23
+ 'Theodore', 'Theta', 'Thilda', 'Thordia', 'Tilda', 'Tildi', 'Tildie',
24
+ 'Tildy', 'Tita', 'Tito', 'Tjader', 'Toddie', 'Toddy', 'Torto', 'Tuddor',
25
+ 'Tudor', 'Turtle', 'Tuttle', 'Tutto'
26
+ ],
27
+ 'KLN1111111' => [
28
+ 'Cailean', 'Calan', 'Calen', 'Callahan', 'Callan', 'Callean',
29
+ 'Carleen', 'Carlen', 'Carlene', 'Carlin', 'Carline', 'Carlyn',
30
+ 'Carlynn', 'Carlynne', 'Charlean', 'Charleen', 'Charlene',
31
+ 'Charline', 'Cherlyn', 'Chirlin', 'Clein', 'Cleon', 'Cline',
32
+ 'Cohleen', 'Colan', 'Coleen', 'Colene', 'Colin', 'Colleen',
33
+ 'Collen', 'Collin', 'Colline', 'Colon', 'Cullan', 'Cullen',
34
+ 'Cullin', 'Gaelan', 'Galan', 'Galen', 'Garlan', 'Garlen',
35
+ 'Gaulin', 'Gayleen', 'Gaylene', 'Giliane', 'Gillan', 'Gillian',
36
+ 'Glen', 'Glenn', 'Glyn', 'Glynn', 'Gollin', 'Gorlin', 'Kalin',
37
+ 'Karlan', 'Karleen', 'Karlen', 'Karlene', 'Karlin', 'Karlyn',
38
+ 'Kaylyn', 'Keelin', 'Kellen', 'Kellene', 'Kellyann', 'Kellyn',
39
+ 'Khalin', 'Kilan', 'Kilian', 'Killen', 'Killian', 'Killion',
40
+ 'Klein', 'Kleon', 'Kline', 'Koerlin', 'Kylen', 'Kylynn', 'Quillan',
41
+ 'Quillon', 'Qulllon', 'Xylon'
42
+ ],
43
+ 'TN11111111' => [
44
+ 'Dan', 'Dane', 'Dann', 'Darn', 'Daune', 'Dawn', 'Ddene', 'Dean', 'Deane',
45
+ 'Deanne', 'DeeAnn', 'Deeann', 'Deeanne', 'Deeyn', 'Den', 'Dene', 'Denn',
46
+ 'Deonne', 'Diahann', 'Dian', 'Diane', 'Diann', 'Dianne', 'Diannne', 'Dine',
47
+ 'Dion', 'Dione', 'Dionne', 'Doane', 'Doehne', 'Don', 'Donn', 'Doone', 'Dorn',
48
+ 'Down', 'Downe', 'Duane', 'Dun', 'Dunn', 'Duyne', 'Dyan', 'Dyane', 'Dyann',
49
+ 'Dyanne', 'Dyun', 'Tan', 'Tann', 'Teahan', 'Ten', 'Tenn', 'Terhune', 'Thain',
50
+ 'Thaine', 'Thane', 'Thanh', 'Thayne', 'Theone', 'Thin', 'Thorn', 'Thorne',
51
+ 'Thun', 'Thynne', 'Tien', 'Tine', 'Tjon', 'Town', 'Towne', 'Turne', 'Tyne'
52
+ ]
53
+ }
54
+
55
+ describe Phonetic::Caverphone2 do
56
+ describe '.encode' do
57
+ it 'should return Caverphone 2 value of string' do
58
+ CAVERPHONE2_TEST_TABLE.each do |code, words|
59
+ words.each do |word|
60
+ res = Phonetic::Caverphone2.encode(word)
61
+ res.should eq(code), "expected: #{code}\ngot: #{res}\nword: #{word}"
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,115 @@
1
+ require 'spec_helper'
2
+
3
+ CAVERPHONE_TEST_TABLE = {
4
+ 'Addis' => 'ATS111',
5
+ 'Alcantara' => 'AKNTR1',
6
+ 'Allegra' => 'ALKR11',
7
+ 'Allende' => 'ALNT11',
8
+ 'America' => 'AMRK11',
9
+ 'Andera' => 'ANTR11',
10
+ 'Annamarie' => 'ANMR11',
11
+ 'Anya' => 'ANY111',
12
+ 'Ariane' => 'ARN111',
13
+ 'Arnoldo' => 'ANT111',
14
+ 'Beltran' => 'PTRN11',
15
+ 'Blanch' => 'PLNK11',
16
+ 'Blose' => 'PLS111',
17
+ 'Bodie' => 'PT1111',
18
+ 'Celentano' => 'SLNTN1',
19
+ 'Celestine' => 'SLSTN1',
20
+ 'Charmain' => 'KMN111',
21
+ 'Chelsea' => 'KS1111',
22
+ 'Coleman' => 'KLMN11',
23
+ 'Collis' => 'KLS111',
24
+ 'Crysta' => 'KRST11',
25
+ 'Culwell' => 'KW1111',
26
+ 'Dilworth' => 'TWT111',
27
+ 'Dinkins' => 'TNKNS1',
28
+ 'Donetta' => 'TNT111',
29
+ 'Dreama' => 'TRM111',
30
+ 'Dulce' => 'TS1111',
31
+ 'Eastwood' => 'ASTWT1',
32
+ 'Eddy' => 'AT1111',
33
+ 'Ellett' => 'ALT111',
34
+ 'Fazekas' => 'FSKS11',
35
+ 'Francesco' => 'FRNSSK',
36
+ 'Gary' => 'KR1111',
37
+ 'Genoveva' => 'KNFF11',
38
+ 'Gossman' => 'KSMN11',
39
+ 'Goudy' => 'KT1111',
40
+ 'Greta' => 'KRT111',
41
+ 'Gunn' => 'KN1111',
42
+ 'Hackman' => 'AKMN11',
43
+ 'Hassie' => 'AS1111',
44
+ 'Henrietta' => 'ANRT11',
45
+ 'Hollaway' => 'ALW111',
46
+ 'Hulbert' => 'APT111',
47
+ 'Isaacson' => 'ASKSN1',
48
+ 'Ishibashi' => 'ASPS11',
49
+ 'Isreal' => 'ASR111',
50
+ 'Jerez' => 'YRS111',
51
+ 'Joette' => 'YT1111',
52
+ 'Jonathon' => 'YNTN11',
53
+ 'Karin' => 'KRN111',
54
+ 'Kenneth' => 'KNT111',
55
+ 'Koontz' => 'KNTS11',
56
+ 'Korey' => 'KR1111',
57
+ 'Krystle' => 'KRSTL1',
58
+ 'Landey' => 'LNT111',
59
+ 'Lashaunda' => 'LSNT11',
60
+ 'Legere' => 'LKR111',
61
+ 'Lela' => 'LL1111',
62
+ 'Louis' => 'LS1111',
63
+ 'Lovely' => 'LFL111',
64
+ 'Lozano' => 'LSN111',
65
+ 'Margo' => 'MK1111',
66
+ 'Maricle' => 'MRKL11',
67
+ 'Mario' => 'MR1111',
68
+ 'Mccormick' => 'MKMK11',
69
+ 'Melody' => 'MLT111',
70
+ 'Mike' => 'MK1111',
71
+ 'Milagros' => 'MLKRS1',
72
+ 'Modesto' => 'MTST11',
73
+ 'Mor' => 'M11111',
74
+ 'Muse' => 'MS1111',
75
+ 'Neil' => 'N11111',
76
+ 'Nicolas' => 'NKLS11',
77
+ 'Olney' => 'AN1111',
78
+ 'Pannell' => 'PN1111',
79
+ 'Posada' => 'PST111',
80
+ 'Raeann' => 'RN1111',
81
+ 'Rameau' => 'RM1111',
82
+ 'Regal' => 'RK1111',
83
+ 'Renetta' => 'RNT111',
84
+ 'Sachiko' => 'SKK111',
85
+ 'Samira' => 'SMR111',
86
+ 'Sammie' => 'SM1111',
87
+ 'Sara' => 'SR1111',
88
+ 'Searcy' => 'SS1111',
89
+ 'Seeley' => 'SL1111',
90
+ 'Shannon' => 'SNN111',
91
+ 'Siegmund' => 'SKMNT1',
92
+ 'Silvera' => 'SFR111',
93
+ 'Sitz' => 'STS111',
94
+ 'Smyth' => 'SMT111',
95
+ 'Steedley' => 'STTL11',
96
+ 'Teri' => 'TR1111',
97
+ 'Tourville' => 'TFL111',
98
+ 'Ute' => 'AT1111',
99
+ 'Vernon' => 'FNN111',
100
+ 'Vidaurri' => 'FTR111',
101
+ 'Wolff' => 'WF1111',
102
+ 'Zeck' => 'SK1111',
103
+ 'Zirkind' => 'SKNT11'
104
+ }
105
+
106
+ describe Phonetic::Caverphone do
107
+ describe '.encode' do
108
+ it 'should return Caverphone value of string' do
109
+ CAVERPHONE_TEST_TABLE.each do |word, code|
110
+ res = Phonetic::Caverphone.encode(word)
111
+ res.should eq(code), "expected: #{code}\ngot: #{res}\nword: #{word}"
112
+ end
113
+ end
114
+ end
115
+ end