nameable 0.5.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,34 @@
1
+ module Nameable
2
+ class Latin
3
+ ##
4
+ # Regex's to match the detritus that people add to their names
5
+ module Patterns
6
+ PREFIX = {
7
+ "Mr." => /^\(*(mr\.*|mister)\)*$/i,
8
+ "Mrs." => /^\(*(mrs\.*|misses)\)*$/i,
9
+ "Ms." => /^\(*(ms\.*|miss)\)*$/i,
10
+ "Dr." => /^\(*(dr\.*|doctor)\)*$/i,
11
+ "Rev." => /^\(*(rev\.*|reverand)\)*$/i,
12
+ "Fr." => /^\(*(fr\.*|friar)\)*$/i,
13
+ "Master" => /^\(*(master)\)*$/i,
14
+ "Sir" => /^\(*(sir)\)*$/i
15
+ }
16
+
17
+ 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
+
24
+ SUFFIX_GENERATIONAL_ROMAN = /^\(*[IVX.]+\)*$/i
25
+ 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
28
+
29
+ # http://www.onlineaspect.com/2009/08/17/splitting-names/
30
+ LAST_NAME_PRE_DANGLERS = /^(mc|vere|von|van|da|de|del|della|di|da|pietro|vanden|du|st|la|ter|ten)$/i
31
+ O_LAST_NAME_PRE_CONCATS = /^(o'|o`|o")$/i
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module Nameable
2
+ VERSION = "1.0.0"
3
+ end
data/nameable.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'nameable/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'nameable'
8
+ spec.version = Nameable::VERSION
9
+ spec.authors = ['Chris Horn']
10
+ spec.email = ['chorn@chorn.com']
11
+ spec.summary = 'Parse names into components.'
12
+ spec.description = 'A library that provides parsing and output of person names.'
13
+ spec.homepage = 'https://github.com/chorn/nameable'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
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.6.2'
22
+ spec.add_development_dependency 'rake'
23
+ spec.add_development_dependency 'rspec', '~> 3.0.0'
24
+ end
@@ -0,0 +1,284 @@
1
+ require 'spec_helper'
2
+
3
+ describe '.new' do
4
+ it "doesn't raise" do
5
+ expect { Nameable::Latin.new }.to_not raise_error
6
+ end
7
+ end
8
+
9
+ context('with a single word name') do
10
+ subject(:n) { Nameable::Latin.new.parse("Chris") }
11
+ it '.parse' do
12
+ expect(n.prefix).to be_nil
13
+ expect(n.first).to eq('Chris')
14
+ expect(n.middle).to be_nil
15
+ expect(n.last).to be_nil
16
+ expect(n.suffix).to be_nil
17
+ end
18
+ end
19
+
20
+ context('with a simple name') do
21
+ subject(:n) { Nameable::Latin.new.parse("Chris Horn") }
22
+ it '.prefix' do
23
+ expect(n.prefix).to be_nil
24
+ end
25
+ it '.first' do
26
+ expect(n.first).to eq('Chris')
27
+ end
28
+ it '.middle' do
29
+ expect(n.middle).to be_nil
30
+ end
31
+ it '.last' do
32
+ expect(n.last).to eq('Horn')
33
+ end
34
+ it '.suffix' do
35
+ expect(n.suffix).to be_nil
36
+ end
37
+ end
38
+
39
+ context('with an all uppercase name') do
40
+ subject(:n) { Nameable::Latin.new.parse("CHRIS HORN") }
41
+ it '.first' do
42
+ expect(n.first).to eq('Chris')
43
+ end
44
+ it '.last' do
45
+ expect(n.last).to eq('Horn')
46
+ end
47
+ end
48
+
49
+ context('with an all lowercase name') do
50
+ subject(:n) { Nameable::Latin.new.parse("chris horn") }
51
+ it '.first' do
52
+ expect(n.first).to eq('Chris')
53
+ end
54
+ it '.last' do
55
+ expect(n.last).to eq('Horn')
56
+ end
57
+ end
58
+
59
+ context('with a mixed case name') do
60
+ subject(:n) { Nameable::Latin.new.parse("DeChris HORN") }
61
+ it '.first' do
62
+ expect(n.first).to eq('DeChris')
63
+ end
64
+ end
65
+
66
+ context('with a simple middle name') do
67
+ subject(:n) { Nameable::Latin.new.parse("Chris Derp Horn") }
68
+ it '.prefix' do
69
+ expect(n.prefix).to be_nil
70
+ end
71
+ it '.first' do
72
+ expect(n.first).to eq('Chris')
73
+ end
74
+ it '.middle' do
75
+ expect(n.middle).to eq('Derp')
76
+ end
77
+ it '.last' do
78
+ expect(n.last).to eq('Horn')
79
+ end
80
+ it '.suffix' do
81
+ expect(n.suffix).to be_nil
82
+ end
83
+ end
84
+
85
+ context('with a simple prefix') do
86
+ subject(:n) { Nameable::Latin.new.parse("Sir Chris Horn") }
87
+ it '.prefix' do
88
+ expect(n.prefix).to eq('Sir')
89
+ end
90
+ it '.first' do
91
+ expect(n.first).to eq('Chris')
92
+ end
93
+ it '.middle' do
94
+ expect(n.middle).to be_nil
95
+ end
96
+ it '.last' do
97
+ expect(n.last).to eq('Horn')
98
+ end
99
+ it '.suffix' do
100
+ expect(n.suffix).to be_nil
101
+ end
102
+ end
103
+
104
+ context('with a simple suffix') do
105
+ subject(:n) { Nameable::Latin.new.parse("Chris Horn PhD") }
106
+ it '.prefix' do
107
+ expect(n.prefix).to be_nil
108
+ end
109
+ it '.first' do
110
+ expect(n.first).to eq('Chris')
111
+ end
112
+ it '.middle' do
113
+ expect(n.middle).to be_nil
114
+ end
115
+ it '.last' do
116
+ expect(n.last).to eq('Horn')
117
+ end
118
+ it '.suffix' do
119
+ expect(n.suffix).to eq('Ph.D.')
120
+ end
121
+ end
122
+
123
+ context('prefix patterns') do
124
+ %w{Mr Mr. Mister}.each do |prefix|
125
+ it prefix do
126
+ expect(Nameable::Latin.new.parse("#{prefix} Chris Horn").prefix).to eq('Mr.')
127
+ end
128
+ end
129
+
130
+ %w{Mrs Mrs. Misses}.each do |prefix|
131
+ it prefix do
132
+ expect(Nameable::Latin.new.parse("#{prefix} Chris Horn").prefix).to eq('Mrs.')
133
+ end
134
+ end
135
+
136
+ %w{Ms Ms. Miss}.each do |prefix|
137
+ it prefix do
138
+ expect(Nameable::Latin.new.parse("#{prefix} Chris Horn").prefix).to eq('Ms.')
139
+ end
140
+ end
141
+
142
+ %w{Dr Dr. Doctor}.each do |prefix|
143
+ it prefix do
144
+ expect(Nameable::Latin.new.parse("#{prefix} Chris Horn").prefix).to eq('Dr.')
145
+ end
146
+ end
147
+
148
+ %w{Rev Rev. Reverand}.each do |prefix|
149
+ it prefix do
150
+ expect(Nameable::Latin.new.parse("#{prefix} Chris Horn").prefix).to eq('Rev.')
151
+ end
152
+ end
153
+
154
+ %w{Fr Fr. Friar}.each do |prefix|
155
+ it prefix do
156
+ expect(Nameable::Latin.new.parse("#{prefix} Chris Horn").prefix).to eq('Fr.')
157
+ end
158
+ end
159
+
160
+ %w{Master Sir}.each do |prefix|
161
+ it prefix do
162
+ expect(Nameable::Latin.new.parse("#{prefix} Chris Horn").prefix).to eq(prefix)
163
+ end
164
+ end
165
+
166
+ end
167
+
168
+ context('suffix patterns (formatted)') do
169
+ %w{Sr Sr. Senior}.each do |suffix|
170
+ it suffix do
171
+ expect(Nameable::Latin.new.parse("Chris Horn #{suffix}").suffix).to eq('Sr.')
172
+ end
173
+ end
174
+
175
+ %w{Jr Jr. Junior}.each do |suffix|
176
+ it suffix do
177
+ expect(Nameable::Latin.new.parse("Chris Horn #{suffix}").suffix).to eq('Jr.')
178
+ end
179
+ end
180
+
181
+ %w{Esq Esq. Esquire}.each do |suffix|
182
+ it suffix do
183
+ expect(Nameable::Latin.new.parse("Chris Horn #{suffix}").suffix).to eq('Esq.')
184
+ end
185
+ end
186
+
187
+ %w{PHD PhD Ph.D Ph.D. P.H.D.}.each do |suffix|
188
+ it suffix do
189
+ expect(Nameable::Latin.new.parse("Chris Horn #{suffix}").suffix).to eq('Ph.D.')
190
+ end
191
+ end
192
+
193
+ end
194
+
195
+ context('suffix patterns (generational)') do
196
+ %w{ii III iv V VI ix Xiii}.each do |suffix|
197
+ it suffix do
198
+ expect(Nameable::Latin.new.parse("Chris Horn #{suffix}").suffix).to eq(suffix.upcase)
199
+ end
200
+ end
201
+ end
202
+
203
+ context('suffix patterns (common)') do
204
+ %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|
205
+ it suffix do
206
+ expect(Nameable::Latin.new.parse("Chris Horn #{suffix}").suffix).to eq(suffix.upcase)
207
+ end
208
+ end
209
+ end
210
+
211
+ context('suffix patterns (generic uppercase)') do
212
+ it 'generic DERP suffix' do
213
+ expect(Nameable::Latin.new.parse("Chris Horn DERP").suffix).to eq('DERP')
214
+ end
215
+
216
+ it 'no generic DERP suffix when all uppercase name' do
217
+ expect(Nameable::Latin.new.parse("CHRIS HORN DERP").suffix).to be_nil
218
+ end
219
+ end
220
+
221
+ context('multi word last names') do
222
+ %w{mc vere von van da de del della di da pietro vanden du st la ter ten}.each do |prefix|
223
+ it "#{prefix} Last" do
224
+ expect(Nameable::Latin.new.parse("Chris #{prefix} Last").last).to eq("#{prefix.downcase.capitalize} Last")
225
+ end
226
+ end
227
+ end
228
+
229
+ context("o'last-name") do
230
+ it "O'Horn" do
231
+ expect(Nameable::Latin.new.parse("Chris O'Horn").last).to eq("O'Horn")
232
+ end
233
+
234
+ it "O`Horn" do
235
+ expect(Nameable::Latin.new.parse("Chris O`Horn").last).to eq("O'Horn")
236
+ end
237
+
238
+ it "O' Horn" do
239
+ expect(Nameable::Latin.new.parse("Chris O' Horn").last).to eq("O'Horn")
240
+ end
241
+ end
242
+
243
+ context("hyphenated last names") do
244
+ it "Horn - Derp" do
245
+ expect(Nameable::Latin.new.parse("Chris Horn - Derp").last).to eq("Horn-Derp")
246
+ end
247
+
248
+ it "Horn-Derp" do
249
+ expect(Nameable::Latin.new.parse("Chris Horn-Derp").last).to eq("Horn-Derp")
250
+ end
251
+
252
+ it "Horn--Derp" do
253
+ expect(Nameable::Latin.new.parse("Chris Horn--Derp").last).to eq("Horn-Derp")
254
+ end
255
+
256
+ it "Horn -- Derp" do
257
+ expect(Nameable::Latin.new.parse("Chris Horn--Derp").last).to eq("Horn-Derp")
258
+ end
259
+ end
260
+
261
+ context("gender") do
262
+ it "Chris is more likely to be male" do
263
+ expect(Nameable::Latin.new.parse("Chris Horn").male?).to be true
264
+ end
265
+
266
+ it "Janine is more likely to be female" do
267
+ expect(Nameable::Latin.new.parse("Janine Horn").female?).to be true
268
+ end
269
+
270
+ it "Derp has :unknown gender" do
271
+ expect(Nameable::Latin.new.parse("Derp Horn").gender).to eq(:unknown)
272
+ end
273
+ end
274
+
275
+ context("ethnicity") do
276
+ it "Horn has a hash of ethnicity results" do
277
+ expect(Nameable::Latin.new.parse("Chris Horn").ethnicity).to be_a Hash
278
+ end
279
+
280
+ it "Horn's census :percent_white > 80% " do
281
+ expect(Nameable::Latin.new.parse("Chris Horn").ethnicity[:percent_white]).to be >= 80
282
+ end
283
+ end
284
+
@@ -1,21 +1,9 @@
1
- require File.dirname(__FILE__) + '/spec_helper'
2
-
3
- describe Nameable::Latin do
4
- describe "with 'Mr. Chris Horn PhD" do
5
- subject { Nameable::Latin.new.parse("Mr. Chris Horn PhD") }
6
-
7
- it("should extract prefix") { subject.prefix.should == "Mr." }
8
- it("should extract first name") { subject.first.should == "Chris" }
9
- it("should extract last name") { subject.last.should == "Horn" }
10
- it("should extract and normalize suffix") { subject.suffix.should == "Ph.D." }
1
+ context("convenience") do
2
+ it 'to_s' do
3
+ expect(Nameable("Chris Horn")).to be_a(String)
11
4
  end
12
5
 
13
- describe "with 'Chris Old Biscuit Barrel Horn'" do
14
- subject { Nameable::Latin.new.parse("Chris Old Biscuit Barrel Horn") }
15
-
16
- it("should extract first name") { subject.first.should == "Chris" }
17
- it("should extract middle name") { subject.middle.should == "Old Biscuit Barrel" }
18
- it("should extract last name") { subject.last.should == "Horn" }
6
+ it 'parse' do
7
+ expect(Nameable.parse("Chris Horn")).to be_a(Nameable::Latin)
19
8
  end
20
-
21
9
  end
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,8 @@
1
- $LOAD_PATH.push File.join(File.dirname(__FILE__), '..', 'lib')
2
-
3
- require "rubygems"
4
- require "spec"
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require "bundler/setup"
4
+ Bundler.require(:test)
5
5
  require "nameable"
6
6
 
7
- Spec::Runner.configure do |config|
8
- # config.mock_with :mocha
7
+ RSpec.configure do |config|
9
8
  end
metadata CHANGED
@@ -1,97 +1,111 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nameable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
5
- prerelease:
4
+ version: 1.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Chris Horn
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-08-10 00:00:00.000000000 Z
11
+ date: 2014-07-01 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
- version: '0'
19
+ version: 1.6.2
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
- version: '0'
26
+ version: 1.6.2
30
27
  - !ruby/object:Gem::Dependency
31
- name: jeweler
28
+ name: rake
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
- description: A gem that provides parsing and output of person names.
47
- email: chorn@chorn.com
48
- executables: []
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.0.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.0.0
55
+ description: A library that provides parsing and output of person names.
56
+ email:
57
+ - chorn@chorn.com
58
+ executables:
59
+ - nameable_web_service
49
60
  extensions: []
50
- extra_rdoc_files:
51
- - LICENSE
52
- - README.rdoc
53
- - TODO
61
+ extra_rdoc_files: []
54
62
  files:
63
+ - ".gitignore"
55
64
  - Gemfile
56
65
  - Gemfile.lock
57
- - History.txt
58
- - LICENSE
59
- - README.rdoc
66
+ - LICENSE.txt
67
+ - README.md
60
68
  - Rakefile
61
- - TODO
62
- - VERSION
63
- - examples/nameable_web_service.rb
64
- - examples/test.rb
69
+ - bin/nameable_web_service
70
+ - data/app_c.csv
71
+ - data/yob2013.txt
65
72
  - lib/nameable.rb
73
+ - lib/nameable/error.rb
74
+ - lib/nameable/extensions.rb
75
+ - lib/nameable/latin.rb
76
+ - lib/nameable/latin/patterns.rb
77
+ - lib/nameable/version.rb
78
+ - nameable.gemspec
79
+ - spec/nameable/latin_spec.rb
66
80
  - spec/nameable_spec.rb
67
81
  - spec/spec.opts
68
82
  - spec/spec_helper.rb
69
83
  homepage: https://github.com/chorn/nameable
70
84
  licenses:
71
85
  - MIT
86
+ metadata: {}
72
87
  post_install_message:
73
88
  rdoc_options: []
74
89
  require_paths:
75
90
  - lib
76
91
  required_ruby_version: !ruby/object:Gem::Requirement
77
- none: false
78
92
  requirements:
79
- - - ! '>='
93
+ - - ">="
80
94
  - !ruby/object:Gem::Version
81
95
  version: '0'
82
- segments:
83
- - 0
84
- hash: -172521366074820921
85
96
  required_rubygems_version: !ruby/object:Gem::Requirement
86
- none: false
87
97
  requirements:
88
- - - ! '>='
98
+ - - ">="
89
99
  - !ruby/object:Gem::Version
90
100
  version: '0'
91
101
  requirements: []
92
102
  rubyforge_project:
93
- rubygems_version: 1.8.23
103
+ rubygems_version: 2.2.2
94
104
  signing_key:
95
- specification_version: 3
96
- summary: Provides parsing and output of person names.
97
- test_files: []
105
+ specification_version: 4
106
+ summary: Parse names into components.
107
+ test_files:
108
+ - spec/nameable/latin_spec.rb
109
+ - spec/nameable_spec.rb
110
+ - spec/spec.opts
111
+ - spec/spec_helper.rb