nameable 1.1.3 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,8 +1,8 @@
1
- require "nameable/version"
2
- require "nameable/assets"
3
- require "nameable/error"
4
- require "nameable/latin"
5
- require "nameable/extensions"
1
+ require 'nameable/version'
2
+ require 'nameable/error'
3
+ require 'nameable/assets'
4
+ require 'nameable/latin'
5
+ require 'nameable/extensions'
6
6
 
7
7
  module Nameable
8
8
  def self.parse(name)
@@ -1,4 +1,6 @@
1
- module Nameable::Assets
2
- GENDER_TABLE = File.expand_path(File.join('..', '..', '..', 'data', 'yob2014.txt'), __FILE__)
3
- ETHNICITY_TABLE = File.expand_path(File.join('..', '..', '..', 'data', 'app_c.csv'), __FILE__)
1
+ module Nameable
2
+ module Assets
3
+ GENDER_TABLE = File.expand_path(File.join('..', '..', '..', 'data', 'yob2016.txt'), __FILE__)
4
+ ETHNICITY_TABLE = File.expand_path(File.join('..', '..', '..', 'data', 'app_c.csv'), __FILE__)
5
+ end
4
6
  end
@@ -1,5 +1,4 @@
1
1
  module Nameable
2
- # Raised if something other than a valid Name is supplied
3
2
  class InvalidNameError < StandardError
4
3
  end
5
4
  end
@@ -9,7 +9,6 @@ module Nameable
9
9
 
10
10
  attr_accessor :prefix, :first, :middle, :last, :suffix
11
11
 
12
- ##
13
12
  def initialize(*args)
14
13
  if args.size == 1 && args.first.class == Hash
15
14
  parts = args.first
@@ -19,29 +18,28 @@ module Nameable
19
18
  @last = parts[:last] ? parts[:last] : nil
20
19
  @suffix = parts[:suffix] ? parts[:suffix] : nil
21
20
  else
22
- @first = args.shift if args.size > 0
21
+ @first = args.shift unless args.empty?
23
22
  @middle = args.shift if args.size >= 2 # Only grab a middle name if we've got a last name left
24
- @last = args.shift if args.size > 0
23
+ @last = args.shift unless args.empty?
25
24
  end
26
25
  end
27
26
 
28
27
  ##
29
28
  # name is an Array
30
29
  def extract_prefix(name)
31
- return unless name and name.size > 1 and @prefix.nil? and @first.nil?
32
- Nameable::Latin::Patterns::PREFIX.each_pair do |pretty, regex|
33
- if name.first =~ regex
34
- @prefix = pretty
35
- name.delete(name.first)
36
- return
37
- end
30
+ return unless name && name.size > 1 && @prefix.nil? && @first.nil?
31
+ Nameable::Latin::Patterns::PREFIX.each do |pretty, regex|
32
+ next unless name.first =~ regex
33
+ @prefix = pretty
34
+ name.delete(name.first)
35
+ break
38
36
  end
39
37
  end
40
38
 
41
39
  ##
42
40
  # name is an Array
43
41
  def extract_suffix(name)
44
- return unless name and name.size >= 3
42
+ return unless name && name.size >= 3
45
43
 
46
44
  (name.size - 1).downto(2) do |n|
47
45
  suff = nil
@@ -50,48 +48,52 @@ module Nameable
50
48
  suff = pretty if name[n] =~ regex
51
49
  end
52
50
 
53
- if name[n] =~ Nameable::Latin::Patterns::SUFFIX_ACADEMIC or name[n] =~ Nameable::Latin::Patterns::SUFFIX_PROFESSIONAL or name[n] =~ Nameable::Latin::Patterns::SUFFIX_GENERATIONAL_ROMAN
54
- suff = name[n].upcase.gsub(/\./,'')
51
+ if name[n] =~ Nameable::Latin::Patterns::SUFFIX_ACADEMIC ||
52
+ name[n] =~ Nameable::Latin::Patterns::SUFFIX_PROFESSIONAL ||
53
+ name[n] =~ Nameable::Latin::Patterns::SUFFIX_GENERATIONAL_ROMAN
54
+ suff = name[n].upcase.delete('.')
55
55
  end
56
56
 
57
- if !suff && name.join != name.join.upcase and name[n].length > 1 and name[n] =~ Nameable::Latin::Patterns::SUFFIX_ABBREVIATION
58
- suff = name[n].upcase.gsub(/\./,'')
57
+ if !suff &&
58
+ name.join != name.join.upcase &&
59
+ name[n].length > 1 &&
60
+ name[n] =~ Nameable::Latin::Patterns::SUFFIX_ABBREVIATION
61
+ suff = name[n].upcase.delete('.')
59
62
  end
60
63
 
61
64
  if suff
62
65
  @suffix = @suffix ? "#{suff}, #{@suffix}" : suff
63
66
  name.delete_at(n)
64
67
  end
65
-
66
68
  end
67
69
  end
68
70
 
69
71
  ##
70
72
  # name is an Array
71
73
  def extract_first(name)
72
- return unless name and name.size >= 1
74
+ return unless name && name.size >= 1
73
75
 
74
76
  @first = name.first
75
77
  name.delete_at(0)
76
78
 
77
- @first.capitalize! unless @first =~ /[a-z]/ and @first =~ /[A-Z]/
79
+ @first.capitalize! unless @first =~ /[a-z]/ && @first =~ /[A-Z]/
78
80
  end
79
81
 
80
82
  ##
81
83
  # name is an Array
82
84
  def extract_last(name)
83
- return unless name and name.size >= 1
85
+ return unless name && name.size >= 1
84
86
 
85
87
  @last = name.last.gsub(/['`"]+/, "'").gsub(/-+/, '-')
86
88
  name.delete_at(name.size - 1)
87
89
 
88
- @last.capitalize! unless @last =~ /[a-z]/ and @last =~ /[A-Z]/
90
+ @last.capitalize! unless @last =~ /[a-z]/ && @last =~ /[A-Z]/
89
91
  end
90
92
 
91
93
  ##
92
94
  # name is an Array
93
95
  def extract_middle(name)
94
- return unless name and name.size >= 1
96
+ return unless name && name.size >= 1
95
97
 
96
98
  (name.size - 1).downto(0) do |n|
97
99
  next unless name[n]
@@ -100,9 +102,9 @@ module Nameable
100
102
  @last = "#{name[n].downcase.capitalize} #{@last}"
101
103
  elsif name[n] =~ Nameable::Latin::Patterns::O_LAST_NAME_PRE_CONCATS
102
104
  @last = "O'#{@last}"
103
- elsif name[n] =~ /\-/ and n > 0 and name[n-1]
104
- @last = "#{name[n-1].gsub(/\-/, '')}-#{@last}"
105
- name[n-1] = nil
105
+ elsif name[n] =~ /\-/ && n > 0 && name[n - 1]
106
+ @last = "#{name[n - 1].delete('-')}-#{@last}"
107
+ name[n - 1] = nil
106
108
  else
107
109
  @middle = @middle ? "#{name[n]} #{@middle}" : name[n]
108
110
  end
@@ -110,21 +112,21 @@ module Nameable
110
112
  name.delete_at(n)
111
113
  end
112
114
 
113
- @middle.capitalize! if @middle and !(@middle =~ /[a-z]/ and @middle =~ /[A-Z]/)
114
- @middle = "#{@middle}." if @middle and @middle.size == 1
115
+ @middle.capitalize! if @middle && !(@middle =~ /[a-z]/ && @middle =~ /[A-Z]/)
116
+ @middle = "#{@middle}." if @middle && @middle.size == 1
115
117
  end
116
118
 
117
119
  def parse(name)
118
120
  raise InvalidNameError unless name
119
121
  if name.class == String
120
122
  if name.index(',')
121
- name = "#{$2} #{$1}" if name =~ /^([a-z]+)\s*,\s*,*([^,]*)/i
123
+ name = "#{Regexp.last_match(2)} #{Regexp.last_match(1)}" if name =~ /^([a-z]+)\s*,\s*,*([^,]*)/i
122
124
  end
123
125
 
124
126
  name = name.strip.split(/\s+/)
125
127
  end
126
128
 
127
- name = name.first.split(/[^[:alnum:]]+/) if name.size == 1 and name.first.split(/[^[:alnum:]]+/)
129
+ name = name.first.split(/[^[:alnum:]]+/) if name.size == 1 && name.first.split(/[^[:alnum:]]+/)
128
130
 
129
131
  extract_prefix(name)
130
132
  extract_suffix(name)
@@ -138,7 +140,7 @@ module Nameable
138
140
  end
139
141
 
140
142
  # http://www.ssa.gov/oact/babynames/limits.html
141
- def load_huge_gender_table(gender_table=Nameable::Assets::GENDER_TABLE)
143
+ def load_huge_gender_table(gender_table = Nameable::Assets::GENDER_TABLE)
142
144
  ranked = {}
143
145
 
144
146
  CSV.read(gender_table).each do |first, gender, rank|
@@ -161,45 +163,45 @@ module Nameable
161
163
 
162
164
  # http://www.census.gov/genealogy/www/data/2000surnames/index.html
163
165
  def load_huge_ethnicity_table
164
- CSV.read(File.expand_path(File.join('..', '..', '..', 'data', 'app_c.csv'), __FILE__)).each do |name, rank, count, prop100k, cum_prop100k, pctwhite, pctblack, pctapi, pctaian, pct2prace, pcthispanic|
166
+ CSV.read(File.expand_path(File.join('..', '..', '..', 'data', 'app_c.csv'), __FILE__)).each do |name, rank, count, _prop100k, _cum_prop100k, pctwhite, pctblack, pctapi, pctaian, pct2prace, pcthispanic|
165
167
  next if name == 'name'
166
168
  @@last_names[name.downcase] = {
167
- rank:rank.to_i,
168
- count:count.to_i,
169
- percent_white:pctwhite.to_f,
170
- percent_black:pctblack.to_f,
171
- percent_asian_pacific_islander:pctapi.to_f,
172
- percent_american_indian_alaska_native:pctaian.to_f,
173
- percent_two_or_more_races:pct2prace.to_f,
174
- percent_hispanic:pcthispanic.to_f
169
+ rank: rank.to_i,
170
+ count: count.to_i,
171
+ percent_white: pctwhite.to_f,
172
+ percent_black: pctblack.to_f,
173
+ percent_asian_pacific_islander: pctapi.to_f,
174
+ percent_american_indian_alaska_native: pctaian.to_f,
175
+ percent_two_or_more_races: pct2prace.to_f,
176
+ percent_hispanic: pcthispanic.to_f
175
177
  }
176
178
  end
177
179
  end
178
180
 
179
181
  def gender
180
182
  return @gender if @gender
181
- load_huge_gender_table unless @@first_names && @@first_names.size > 0
183
+ load_huge_gender_table unless @@first_names && !@@first_names.empty?
182
184
  @gender = @@first_names[@first.to_s.downcase] ? @@first_names[@first.to_s.downcase] : :unknown
183
185
  @gender
184
186
  end
185
187
 
186
188
  def ethnicity
187
189
  return @ethnicity if @ethnicity
188
- load_huge_ethnicity_table unless @@last_names && @@last_names.size > 0
189
- @ethnicity = (@last && @@last_names[@last.downcase]) ? @@last_names[@last.downcase] : :unknown
190
+ load_huge_ethnicity_table unless @@last_names && !@@last_names.empty?
191
+ @ethnicity = @last && @@last_names[@last.downcase] ? @@last_names[@last.downcase] : :unknown
190
192
  @ethnicity
191
193
  end
192
194
 
193
195
  def male?
194
- self.gender == :male
196
+ gender == :male
195
197
  end
196
198
 
197
199
  def female?
198
- self.gender == :female
200
+ gender == :female
199
201
  end
200
202
 
201
203
  def to_s
202
- [@prefix, @first, @middle, @last].compact.join(' ') + (@suffix ? ", #{@suffix}" : "")
204
+ [@prefix, @first, @middle, @last].compact.join(' ') + (@suffix ? ", #{@suffix}" : '')
203
205
  end
204
206
 
205
207
  def to_name
@@ -235,12 +237,12 @@ module Nameable
235
237
  end
236
238
 
237
239
  def to_hash
238
- return {
239
- :prefix => @prefix,
240
- :first => @first,
241
- :middle => @middle,
242
- :last => @last,
243
- :suffix => @suffix
240
+ {
241
+ prefix: @prefix,
242
+ first: @first,
243
+ middle: @middle,
244
+ last: @last,
245
+ suffix: @suffix
244
246
  }
245
247
  end
246
248
  end
@@ -1,30 +1,35 @@
1
1
  module Nameable
2
2
  class Latin
3
- ##
4
3
  # Regex's to match the detritus that people add to their names
5
4
  module Patterns
6
5
  PREFIX = {
7
- "Mr." => /^\(*(mr\.*|mister)\)*$/i,
8
- "Mrs." => /^\(*(mrs\.*|misses)\)*$/i,
9
- "Ms." => /^\(*(ms\.*|miss)\)*$/i,
10
- "Dr." => /^\(*(dr\.*|doctor)\)*$/i,
11
- "Rev." => /^\(*(rev\.*|reverend)\)*$/i,
12
- "Fr." => /^\(*(fr\.*|friar)\)*$/i,
13
- "Master" => /^\(*(master)\)*$/i,
14
- "Sir" => /^\(*(sir)\)*$/i
15
- }
6
+ 'Capt.' => /^\(*(capt\.*|captain)\)*$/i,
7
+ 'Dame' => /^\(*(dame)\)*$/i,
8
+ 'Dr.' => /^\(*(dr\.*|doctor)\)*$/i,
9
+ 'Fr.' => /^\(*(fr\.*|friar|father)\)*$/i,
10
+ 'Hon.' => /^\(*(hon\.*|honorable)\)*$/i,
11
+ 'Imam' => /^\(*(imam)\)*$/i,
12
+ 'Ofc.' => /^\(*(ofc\.*|officer)\)*$/i,
13
+ 'Mr.' => /^\(*(mr\.*|mister)\)*$/i,
14
+ 'Mrs.' => /^\(*(mrs\.*|misses)\)*$/i,
15
+ 'Ms.' => /^\(*(ms\.*|miss)\)*$/i,
16
+ 'Rev.' => /^\(*(rev\.*|reverend)\)*$/i,
17
+ 'Master' => /^\(*(master)\)*$/i,
18
+ 'Rabbi' => /^\(*(rabbi)\)*$/i,
19
+ 'Sir' => /^\(*(sir)\)*$/i
20
+ }.freeze
16
21
 
17
22
  SUFFIX = {
18
- "Sr." => /^\(*(sr\.?|senior)\)*$/i,
19
- "Jr." => /^\(*(jr\.?|junior)\)*$/i,
20
- "Esq." => /^\(*(esq\.?|esquire)\)*$/i,
21
- "Ph.D." => /^\(*(p\.?h\.?d\.?)\)*$/i
22
- }
23
+ 'Sr.' => /^\(*(sr\.?|senior)\)*$/i,
24
+ 'Jr.' => /^\(*(jr\.?|junior)\)*$/i,
25
+ 'Esq.' => /^\(*(esq\.?|esquire)\)*$/i,
26
+ 'Ph.D.' => /^\(*(p\.?h\.?d\.?)\)*$/i
27
+ }.freeze
23
28
 
24
29
  SUFFIX_GENERATIONAL_ROMAN = /^\(*[IVX.]+\)*$/i
25
30
  SUFFIX_ACADEMIC = /^(APR|RPh|MD|MA|DMD|DDS|PharmD|EngD|DPhil|JD|DD|DO|BA|BS|BSc|BE|BFA|MA|MS|MSc|MFA|MLA|MBA)$/i
26
- SUFFIX_PROFESSIONAL = /^(PE|CSA|CPA|CPL|CME|CEng|OFM|CSV|Douchebag)$/i
27
- SUFFIX_ABBREVIATION = /^[A-Z.]+[A-Z.]+$/ # It should be at least 2 letters
31
+ SUFFIX_PROFESSIONAL = /^(PE|CSA|CPA|CPL|CME|CEng|OFM|CSV)$/i
32
+ SUFFIX_ABBREVIATION = /^[A-Z]\.?[A-Z]\.?[A-Z]?\.?$/ # 2-3 characters, possibly separated with '.'
28
33
 
29
34
  # http://www.onlineaspect.com/2009/08/17/splitting-names/
30
35
  LAST_NAME_PRE_DANGLERS = /^(mc|vere|von|van|da|de|del|della|di|da|pietro|vanden|du|st|la|ter|ten)$/i
@@ -1,3 +1,3 @@
1
1
  module Nameable
2
- VERSION = "1.1.3"
2
+ VERSION = '1.1.4'.freeze
3
3
  end
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+
2
3
  lib = File.expand_path('../lib', __FILE__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require 'nameable/version'
@@ -12,20 +13,21 @@ Gem::Specification.new do |spec|
12
13
  spec.description = 'A library that provides parsing and output of person names, as well as Gender & Ethnicity matching.'
13
14
  spec.homepage = 'https://github.com/chorn/nameable'
14
15
  spec.license = 'MIT'
15
-
16
16
  spec.files = `git ls-files -z`.split("\x0")
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
19
+ spec.require_paths = ['lib']
20
+ spec.required_ruby_version = '>= 1.9'
20
21
 
21
- signing_key = File.expand_path("~/.certs/chorn@chorn.com-rubygems.key")
22
+ signing_key = File.expand_path '~/.certs/chorn@chorn.com-rubygems.key'
22
23
  if File.file?(signing_key)
23
24
  spec.signing_key = signing_key
24
25
  spec.cert_chain = ['certs/chorn.pem']
25
26
  end
26
27
 
27
- spec.add_development_dependency 'bundler', '~> 1.6'
28
- spec.add_development_dependency 'codeclimate-test-reporter', '~> 0.4'
29
- spec.add_development_dependency 'rake', '~> 10.4'
30
- spec.add_development_dependency 'rspec', '~> 3.3'
28
+ spec.add_development_dependency 'bundler'
29
+ spec.add_development_dependency 'rake'
30
+ spec.add_development_dependency 'rspec', '~> 3.6'
31
+ spec.add_development_dependency 'simplecov'
32
+ spec.add_development_dependency 'codeclimate-test-reporter'
31
33
  end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Object do
4
+ it 'returns a string' do
5
+ expect(Nameable('Chris Horn')).to be_a(String)
6
+ end
7
+
8
+ it 'raises an exception' do
9
+ expect { Nameable(nil) }.to raise_error Nameable::InvalidNameError
10
+ end
11
+ end
@@ -1,5 +1,17 @@
1
1
  require 'spec_helper'
2
2
 
3
+ shared_examples :generalized_parsing do |input, outputs|
4
+ let(:nameable) { Nameable::Latin.new.parse(input) }
5
+
6
+ it "#parse ``#{input}''" do
7
+ expect(nameable.prefix).to eq outputs[0]
8
+ expect(nameable.first).to eq outputs[1]
9
+ expect(nameable.middle).to eq outputs[2]
10
+ expect(nameable.last).to eq outputs[3]
11
+ expect(nameable.suffix).to eq outputs[4]
12
+ end
13
+ end
14
+
3
15
  describe Nameable::Latin do
4
16
  describe '.new' do
5
17
  it "doesn't raise" do
@@ -7,318 +19,166 @@ describe Nameable::Latin do
7
19
  end
8
20
  end
9
21
 
10
- context('with a single word name') do
11
- subject(:n) { Nameable::Latin.new.parse("Chris") }
12
- it '.parse' do
13
- expect(n.prefix).to be_nil
14
- expect(n.first).to eq('Chris')
15
- expect(n.middle).to be_nil
16
- expect(n.last).to be_nil
17
- expect(n.suffix).to be_nil
22
+ describe '#parse' do
23
+ context 'with a single word name' do
24
+ it_behaves_like :generalized_parsing, 'Chris', [nil, 'Chris', nil, nil, nil]
18
25
  end
19
- end
20
26
 
21
- context('with a simple name') do
22
- subject(:n) { Nameable::Latin.new.parse("Chris Horn") }
23
- it '.prefix' do
24
- expect(n.prefix).to be_nil
27
+ context 'with a simple first and last name' do
28
+ it_behaves_like :generalized_parsing, 'Chris Horn', [nil, 'Chris', nil, 'Horn', nil]
25
29
  end
26
- it '.first' do
27
- expect(n.first).to eq('Chris')
28
- end
29
- it '.middle' do
30
- expect(n.middle).to be_nil
31
- end
32
- it '.last' do
33
- expect(n.last).to eq('Horn')
34
- end
35
- it '.suffix' do
36
- expect(n.suffix).to be_nil
37
- end
38
- end
39
30
 
40
- context('with an all uppercase name') do
41
- subject(:n) { Nameable::Latin.new.parse("CHRIS HORN") }
42
- it '.first' do
43
- expect(n.first).to eq('Chris')
31
+ context 'with an uppercase first and last name' do
32
+ it_behaves_like :generalized_parsing, 'CHRIS HORN', [nil, 'Chris', nil, 'Horn', nil]
44
33
  end
45
- it '.last' do
46
- expect(n.last).to eq('Horn')
47
- end
48
- end
49
34
 
50
- context('with an all lowercase name') do
51
- subject(:n) { Nameable::Latin.new.parse("chris horn") }
52
- it '.first' do
53
- expect(n.first).to eq('Chris')
54
- end
55
- it '.last' do
56
- expect(n.last).to eq('Horn')
35
+ context 'with a lowercase first and last name' do
36
+ it_behaves_like :generalized_parsing, 'chris horn', [nil, 'Chris', nil, 'Horn', nil]
57
37
  end
58
- end
59
38
 
60
- context('with a mixed case name') do
61
- subject(:n) { Nameable::Latin.new.parse("DeChris HORN") }
62
- it '.first' do
63
- expect(n.first).to eq('DeChris')
39
+ context 'with a mixed case first and last name' do
40
+ it_behaves_like :generalized_parsing, 'DeChris Horn', [nil, 'DeChris', nil, 'Horn', nil]
64
41
  end
65
- end
66
42
 
67
- context('last_name, first_name') do
68
- subject(:n) { Nameable::Latin.new.parse("Horn, Chris") }
69
- it '.prefix' do
70
- expect(n.prefix).to be_nil
43
+ context 'with last name, first name' do
44
+ it_behaves_like :generalized_parsing, 'Horn, Chris', [nil, 'Chris', nil, 'Horn', nil]
71
45
  end
72
- it '.first' do
73
- expect(n.first).to eq('Chris')
74
- end
75
- it '.middle' do
76
- expect(n.middle).to be_nil
77
- end
78
- it '.last' do
79
- expect(n.last).to eq('Horn')
80
- end
81
- it '.suffix' do
82
- expect(n.suffix).to be_nil
83
- end
84
- end
85
46
 
86
- context('last_name, first_name,') do
87
- subject(:n) { Nameable::Latin.new.parse("Horn, Chris,") }
88
- it '.prefix' do
89
- expect(n.prefix).to be_nil
47
+ context 'with last name, first name,' do
48
+ it_behaves_like :generalized_parsing, 'Horn, Chris,', [nil, 'Chris', nil, 'Horn', nil]
90
49
  end
91
- it '.first' do
92
- expect(n.first).to eq('Chris')
93
- end
94
- it '.middle' do
95
- expect(n.middle).to be_nil
96
- end
97
- it '.last' do
98
- expect(n.last).to eq('Horn')
99
- end
100
- it '.suffix' do
101
- expect(n.suffix).to be_nil
102
- end
103
- end
104
50
 
105
- context('with a simple middle name') do
106
- subject(:n) { Nameable::Latin.new.parse("Chris Derp Horn") }
107
- it '.prefix' do
108
- expect(n.prefix).to be_nil
51
+ context 'with first middle last name' do
52
+ it_behaves_like :generalized_parsing, 'Chris Derp Horn', [nil, 'Chris', 'Derp', 'Horn', nil]
109
53
  end
110
- it '.first' do
111
- expect(n.first).to eq('Chris')
112
- end
113
- it '.middle' do
114
- expect(n.middle).to eq('Derp')
115
- end
116
- it '.last' do
117
- expect(n.last).to eq('Horn')
118
- end
119
- it '.suffix' do
120
- expect(n.suffix).to be_nil
121
- end
122
- end
123
54
 
124
- context('with a simple prefix') do
125
- subject(:n) { Nameable::Latin.new.parse("Sir Chris Horn") }
126
- it '.prefix' do
127
- expect(n.prefix).to eq('Sir')
55
+ context 'with all uppercase first middle last name' do
56
+ it_behaves_like :generalized_parsing, 'CHRIS DERP HORN', [nil, 'Chris', 'Derp', 'Horn', nil]
128
57
  end
129
- it '.first' do
130
- expect(n.first).to eq('Chris')
131
- end
132
- it '.middle' do
133
- expect(n.middle).to be_nil
134
- end
135
- it '.last' do
136
- expect(n.last).to eq('Horn')
137
- end
138
- it '.suffix' do
139
- expect(n.suffix).to be_nil
140
- end
141
- end
142
58
 
143
- context('with a simple suffix') do
144
- subject(:n) { Nameable::Latin.new.parse("Chris Horn PhD") }
145
- it '.prefix' do
146
- expect(n.prefix).to be_nil
147
- end
148
- it '.first' do
149
- expect(n.first).to eq('Chris')
150
- end
151
- it '.middle' do
152
- expect(n.middle).to be_nil
153
- end
154
- it '.last' do
155
- expect(n.last).to eq('Horn')
156
- end
157
- it '.suffix' do
158
- expect(n.suffix).to eq('Ph.D.')
59
+ context 'with all lowercase first middle last name' do
60
+ it_behaves_like :generalized_parsing, 'chris derp horn', [nil, 'Chris', 'Derp', 'Horn', nil]
159
61
  end
160
- end
161
62
 
162
- context('prefix patterns') do
163
- %w{Mr Mr. Mister}.each do |prefix|
164
- it prefix do
165
- expect(Nameable::Latin.new.parse("#{prefix} Chris Horn").prefix).to eq('Mr.')
166
- end
63
+ context 'with all mixed case first middle last name' do
64
+ it_behaves_like :generalized_parsing, 'DeChris LeDerp ZeHorn', [nil, 'DeChris', 'LeDerp', 'ZeHorn', nil]
167
65
  end
168
66
 
169
- %w{Mrs Mrs. Misses}.each do |prefix|
170
- it prefix do
171
- expect(Nameable::Latin.new.parse("#{prefix} Chris Horn").prefix).to eq('Mrs.')
172
- end
67
+ context 'with first last suffix' do
68
+ it_behaves_like :generalized_parsing, 'Chris Horn DRP', [nil, 'Chris', nil, 'Horn', 'DRP']
173
69
  end
174
70
 
175
- %w{Ms Ms. Miss}.each do |prefix|
176
- it prefix do
177
- expect(Nameable::Latin.new.parse("#{prefix} Chris Horn").prefix).to eq('Ms.')
178
- end
71
+ context 'with prefix first last suffix' do
72
+ it_behaves_like :generalized_parsing, 'Mr. Chris Horn DRP', ['Mr.', 'Chris', nil, 'Horn', 'DRP']
179
73
  end
180
74
 
181
- %w{Dr Dr. Doctor}.each do |prefix|
182
- it prefix do
183
- expect(Nameable::Latin.new.parse("#{prefix} Chris Horn").prefix).to eq('Dr.')
184
- end
75
+ %w[Dame Rabbi Imam Master Sir].each do |prefix|
76
+ it_behaves_like :generalized_parsing, "#{prefix} Chris Horn", [prefix, 'Chris', nil, 'Horn', nil]
185
77
  end
186
78
 
187
- %w{Rev Rev. Reverend}.each do |prefix|
188
- it prefix do
189
- expect(Nameable::Latin.new.parse("#{prefix} Chris Horn").prefix).to eq('Rev.')
79
+ context 'with a normalizing prefix' do
80
+ %w[Mr Mr. Mister].each do |prefix|
81
+ it_behaves_like :generalized_parsing, "#{prefix} Chris Horn", ['Mr.', 'Chris', nil, 'Horn', nil]
190
82
  end
191
- end
192
83
 
193
- %w{Fr Fr. Friar}.each do |prefix|
194
- it prefix do
195
- expect(Nameable::Latin.new.parse("#{prefix} Chris Horn").prefix).to eq('Fr.')
84
+ %w[Mrs Mrs. Misses].each do |prefix|
85
+ it_behaves_like :generalized_parsing, "#{prefix} Chris Horn", ['Mrs.', 'Chris', nil, 'Horn', nil]
196
86
  end
197
- end
198
87
 
199
- %w{Master Sir}.each do |prefix|
200
- it prefix do
201
- expect(Nameable::Latin.new.parse("#{prefix} Chris Horn").prefix).to eq(prefix)
88
+ %w[Ms Ms. Miss].each do |prefix|
89
+ it_behaves_like :generalized_parsing, "#{prefix} Chris Horn", ['Ms.', 'Chris', nil, 'Horn', nil]
202
90
  end
203
- end
204
-
205
- end
206
91
 
207
- context('suffix patterns (formatted)') do
208
- %w{Sr Sr. Senior}.each do |suffix|
209
- it suffix do
210
- expect(Nameable::Latin.new.parse("Chris Horn #{suffix}").suffix).to eq('Sr.')
92
+ %w[Dr Dr. Doctor].each do |prefix|
93
+ it_behaves_like :generalized_parsing, "#{prefix} Chris Horn", ['Dr.', 'Chris', nil, 'Horn', nil]
211
94
  end
212
- end
213
95
 
214
- %w{Jr Jr. Junior}.each do |suffix|
215
- it suffix do
216
- expect(Nameable::Latin.new.parse("Chris Horn #{suffix}").suffix).to eq('Jr.')
96
+ %w[Rev Rev. Reverend].each do |prefix|
97
+ it_behaves_like :generalized_parsing, "#{prefix} Chris Horn", ['Rev.', 'Chris', nil, 'Horn', nil]
217
98
  end
218
- end
219
99
 
220
- %w{Esq Esq. Esquire}.each do |suffix|
221
- it suffix do
222
- expect(Nameable::Latin.new.parse("Chris Horn #{suffix}").suffix).to eq('Esq.')
100
+ %w[Fr Fr. Friar Father].each do |prefix|
101
+ it_behaves_like :generalized_parsing, "#{prefix} Chris Horn", ['Fr.', 'Chris', nil, 'Horn', nil]
223
102
  end
224
- end
225
103
 
226
- %w{PHD PhD Ph.D Ph.D. P.H.D.}.each do |suffix|
227
- it suffix do
228
- expect(Nameable::Latin.new.parse("Chris Horn #{suffix}").suffix).to eq('Ph.D.')
104
+ %w[Hon Hon. Honorable].each do |prefix|
105
+ it_behaves_like :generalized_parsing, "#{prefix} Chris Horn", ['Hon.', 'Chris', nil, 'Horn', nil]
229
106
  end
230
- end
231
107
 
232
- end
233
-
234
- context('suffix patterns (generational)') do
235
- %w{ii III iv V VI ix Xiii}.each do |suffix|
236
- it suffix do
237
- expect(Nameable::Latin.new.parse("Chris Horn #{suffix}").suffix).to eq(suffix.upcase)
108
+ %w[Capt Capt. Captain].each do |prefix|
109
+ it_behaves_like :generalized_parsing, "#{prefix} Chris Horn", ['Capt.', 'Chris', nil, 'Horn', nil]
238
110
  end
239
- end
240
- end
241
111
 
242
- context('suffix patterns (common)') do
243
- %w{APR RPh MD MA DMD DDS PharmD EngD DPhil JD DD DO BA BS BSc BE BFA MA MS MSc MFA MLA MBA PE CSA CPA CPL CME CEng OFM CSV}.each do |suffix|
244
- it suffix do
245
- expect(Nameable::Latin.new.parse("Chris Horn #{suffix}").suffix).to eq(suffix.upcase)
112
+ %w[Ofc Ofc. Officer].each do |prefix|
113
+ it_behaves_like :generalized_parsing, "#{prefix} Chris Horn", ['Ofc.', 'Chris', nil, 'Horn', nil]
246
114
  end
247
115
  end
248
- end
249
-
250
- context('suffix patterns (generic uppercase)') do
251
- it 'generic DERP suffix' do
252
- expect(Nameable::Latin.new.parse("Chris Horn DERP").suffix).to eq('DERP')
253
- end
254
-
255
- it 'no generic DERP suffix when all uppercase name' do
256
- expect(Nameable::Latin.new.parse("CHRIS HORN DERP").suffix).to be_nil
257
- end
258
- end
259
116
 
260
- context('multi word last names') do
261
- %w{mc vere von van da de del della di da pietro vanden du st la ter ten}.each do |prefix|
262
- it "#{prefix} Last" do
263
- expect(Nameable::Latin.new.parse("Chris #{prefix} Last").last).to eq("#{prefix.downcase.capitalize} Last")
117
+ context 'with a normalizing suffix' do
118
+ %w[Sr Sr. Senior].each do |suffix|
119
+ it_behaves_like :generalized_parsing, "Chris Horn #{suffix}", [nil, 'Chris', nil, 'Horn', 'Sr.']
264
120
  end
265
- end
266
- end
267
121
 
268
- context("o'last-name") do
269
- it "O'Horn" do
270
- expect(Nameable::Latin.new.parse("Chris O'Horn").last).to eq("O'Horn")
271
- end
122
+ %w[Jr Jr. Junior].each do |suffix|
123
+ it_behaves_like :generalized_parsing, "Chris Horn #{suffix}", [nil, 'Chris', nil, 'Horn', 'Jr.']
124
+ end
272
125
 
273
- it "O`Horn" do
274
- expect(Nameable::Latin.new.parse("Chris O`Horn").last).to eq("O'Horn")
275
- end
126
+ %w[Esq Esq. Esquire].each do |suffix|
127
+ it_behaves_like :generalized_parsing, "Chris Horn #{suffix}", [nil, 'Chris', nil, 'Horn', 'Esq.']
128
+ end
276
129
 
277
- it "O' Horn" do
278
- expect(Nameable::Latin.new.parse("Chris O' Horn").last).to eq("O'Horn")
279
- end
280
- end
130
+ %w[PHD PhD Ph.D Ph.D. P.H.D.].each do |suffix|
131
+ it_behaves_like :generalized_parsing, "Chris Horn #{suffix}", [nil, 'Chris', nil, 'Horn', 'Ph.D.']
132
+ end
281
133
 
282
- context("hyphenated last names") do
283
- it "Horn - Derp" do
284
- expect(Nameable::Latin.new.parse("Chris Horn - Derp").last).to eq("Horn-Derp")
134
+ %w[
135
+ ii III iv V VI ix Xiii APR RPh MD MA DMD DDS PharmD EngD DPhil
136
+ JD DD DO BA BS BSc BE BFA MA MS MSc MFA MLA MBA PE CSA CPA CPL CME CEng OFM CSV
137
+ ].each do |suffix|
138
+ it_behaves_like :generalized_parsing, "Chris Horn #{suffix}", [nil, 'Chris', nil, 'Horn', suffix.upcase]
139
+ end
285
140
  end
286
141
 
287
- it "Horn-Derp" do
288
- expect(Nameable::Latin.new.parse("Chris Horn-Derp").last).to eq("Horn-Derp")
142
+ context 'with a multi word last name' do
143
+ %w[mc vere von van da de del della di da pietro vanden du st la ter ten].each do |prefix|
144
+ it_behaves_like :generalized_parsing, "Chris #{prefix} Horn", [nil, 'Chris', nil, "#{prefix.downcase.capitalize} Horn", nil]
145
+ end
289
146
  end
290
147
 
291
- it "Horn--Derp" do
292
- expect(Nameable::Latin.new.parse("Chris Horn--Derp").last).to eq("Horn-Derp")
148
+ context "with an o'last-name" do
149
+ ["O'Horn", 'O`Horn', "O' Horn"].each do |last|
150
+ it_behaves_like :generalized_parsing, "Chris #{last}", [nil, 'Chris', nil, "O'Horn", nil]
151
+ end
293
152
  end
294
153
 
295
- it "Horn -- Derp" do
296
- expect(Nameable::Latin.new.parse("Chris Horn--Derp").last).to eq("Horn-Derp")
154
+ context 'with a hyphenated last name' do
155
+ ['Horn - Derp', 'Horn-Derp', 'Horn--Derp', 'Horn -- Derp'].each do |last|
156
+ it_behaves_like :generalized_parsing, "Chris #{last}", [nil, 'Chris', nil, 'Horn-Derp', nil]
157
+ end
297
158
  end
298
159
  end
299
160
 
300
- context("gender") do
301
- it "Chris is more likely to be male" do
302
- expect(Nameable::Latin.new.parse("Chris Horn").male?).to be true
161
+ context 'gender' do
162
+ it 'Chris is more likely to be male' do
163
+ expect(Nameable::Latin.new.parse('Chris Horn').male?).to be true
303
164
  end
304
165
 
305
- it "Janine is more likely to be female" do
306
- expect(Nameable::Latin.new.parse("Janine Horn").female?).to be true
166
+ it 'Janine is more likely to be female' do
167
+ expect(Nameable::Latin.new.parse('Janine Horn').female?).to be true
307
168
  end
308
169
 
309
- it "Derp has :unknown gender" do
310
- expect(Nameable::Latin.new.parse("Derp Horn").gender).to eq(:unknown)
170
+ it 'Derp has :unknown gender' do
171
+ expect(Nameable::Latin.new.parse('Derp Horn').gender).to eq(:unknown)
311
172
  end
312
173
  end
313
174
 
314
- context("ethnicity") do
315
- it "Horn has a hash of ethnicity results" do
316
- expect(Nameable::Latin.new.parse("Chris Horn").ethnicity).to be_a Hash
175
+ context 'ethnicity' do
176
+ it 'Horn has a hash of ethnicity results' do
177
+ expect(Nameable::Latin.new.parse('Chris Horn').ethnicity).to be_a Hash
317
178
  end
318
179
 
319
180
  it "Horn's census :percent_white > 80% " do
320
- expect(Nameable::Latin.new.parse("Chris Horn").ethnicity[:percent_white]).to be >= 80
181
+ expect(Nameable::Latin.new.parse('Chris Horn').ethnicity[:percent_white]).to be >= 80
321
182
  end
322
183
  end
323
-
324
184
  end