nameable 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Chris Horn http://chorn.com/
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,13 @@
1
+
2
+ A person's name is trivial when you validate the input at data entry
3
+ time. That is not always possible, and for my enterprise it is almost
4
+ never possible.
5
+
6
+ References: http://www.onlineaspect.com/2009/08/17/splitting-names/
7
+
8
+ require "nameable"
9
+
10
+
11
+
12
+
13
+ -chorn
data/README.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ == nameable
2
+
3
+ A gem that provides parsing and output of people's names.
data/Rakefile ADDED
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+ require 'spec/rake/spectask'
6
+
7
+ GEM = "nameable"
8
+ GEM_VERSION = "0.1.0"
9
+ AUTHOR = "Chris Horn"
10
+ EMAIL = "chorn@chorn.com"
11
+ HOMEPAGE = "http://github.com/chorn/nameable"
12
+ SUMMARY = "A gem that provides parsing and output of phone numbers according to NANPA standards."
13
+
14
+ spec = Gem::Specification.new do |s|
15
+ s.name = GEM
16
+ s.version = GEM_VERSION
17
+ s.platform = Gem::Platform::RUBY
18
+ s.has_rdoc = true
19
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
20
+ s.summary = SUMMARY
21
+ s.description = s.summary
22
+ s.author = AUTHOR
23
+ s.email = EMAIL
24
+ s.homepage = HOMEPAGE
25
+
26
+ # Uncomment this to add a dependency
27
+ # s.add_dependency "foo"
28
+
29
+ s.require_path = 'lib'
30
+ s.autorequire = GEM
31
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
32
+ end
33
+
34
+ task :default => :spec
35
+
36
+ desc "Run specs"
37
+ Spec::Rake::SpecTask.new do |t|
38
+ t.spec_files = FileList['spec/**/*_spec.rb']
39
+ t.spec_opts = %w(-fs --color)
40
+ end
41
+
42
+
43
+ Rake::GemPackageTask.new(spec) do |pkg|
44
+ pkg.gem_spec = spec
45
+ end
46
+
47
+ desc "install the gem locally"
48
+ task :install => [:package] do
49
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
50
+ end
51
+
52
+ desc "create a gemspec file"
53
+ task :make_spec do
54
+ File.open("#{GEM}.gemspec", "w") do |file|
55
+ file.puts spec.to_ruby
56
+ end
57
+ end
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+ TODO:
2
+ Make rspec actually test some stuff.
3
+
data/lib/nameable.rb ADDED
@@ -0,0 +1,185 @@
1
+ # Copyright (c) 2010 Chris Horn http://chorn.com/
2
+ # See MIT-LICENSE.txt
3
+
4
+ # TODO: Make this less sucky.
5
+
6
+ module Nameable
7
+ class Latin
8
+
9
+ ##
10
+ # Raised if something other than a valid Name is supplied
11
+ class InvalidNameError < StandardError
12
+ end
13
+
14
+ ##
15
+ # Regex's to match the detritus that people add to their names
16
+ module Patterns
17
+ PREFIX = {
18
+ "Mr." => /^\(*(mr\.*|mister)\)*$/i,
19
+ "Mrs." => /^\(*(mrs\.*|misses)\)*$/i,
20
+ "Ms." => /^\(*(ms\.*|miss)\)*$/i,
21
+ "Dr." => /^\(*(dr\.*|doctor)\)*$/i,
22
+ "Rev." => /^\(*(rev\.*|reverand)\)*$/i,
23
+ "Fr." => /^\(*(fr\.*|friar)\)*$/i,
24
+ "Master" => /^\(*(master)\)*$/i,
25
+ "Sir" => /^\(*(sir)\)*$/i
26
+ }
27
+
28
+ SUFFIX = {
29
+ "Sr." => /^\(*(sr\.|senior)\)*$/i,
30
+ "Jr." => /^\(*(jr\.|junior)\)*$/i,
31
+ "Esq." => /^\(*(esq\.|esquire)\)*$/i,
32
+ "PhD." => /^\(*(phd\.)\)*$/i
33
+ }
34
+
35
+ SUFFIX_GENERATIONAL_ROMAN = /^\(*[IVX\.]+\)*$/i
36
+ 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
37
+ SUFFIX_PROFESSIONAL = /^(PE|CSA|CPA|CPL|CME|CEng|OFM|CSV|Douchebag)$/i
38
+ SUFFIX_ABBREVIATION = /^[A-Z\.]+$/
39
+
40
+ LAST_NAME_PRE_DANGLERS = /^(vere|von|van|de|del|della|di|da|pietro|vanden|du|st|la|ter|ten)$/i
41
+ LAST_NAME_PRE_CONCATS = /^(o'|o`|mc)$/i
42
+ end
43
+
44
+ attr_accessor :prefix, :first, :middle, :last, :suffix
45
+
46
+ ##
47
+ #
48
+ def initialize(parts={})
49
+ self.prefix = parts[:prefix] ? parts[:prefix] : nil
50
+ self.first = parts[:first] ? parts[:first] : nil
51
+ self.middle = parts[:middle] ? parts[:middle] : nil
52
+ self.last = parts[:last] ? parts[:last] : nil
53
+ self.suffix = parts[:suffix] ? parts[:suffix] : nil
54
+ end
55
+
56
+ ##
57
+ # name is an Array
58
+ def extract_prefix(name)
59
+ return unless name and name.size > 1 and @prefix.nil? and @first.nil?
60
+ Patterns::PREFIX.each_pair do |pretty, regex|
61
+ if name.first =~ regex
62
+ @prefix = pretty
63
+ name.delete(name.first)
64
+ return
65
+ end
66
+ end
67
+ end
68
+
69
+ ##
70
+ # name is an Array
71
+ def extract_suffix(name)
72
+ return unless name and name.size >= 3
73
+
74
+ (name.size - 1).downto(2) do |n|
75
+ suff = nil
76
+
77
+ Patterns::SUFFIX.each_pair do |pretty, regex|
78
+ suff = pretty if name[n] =~ regex
79
+ end
80
+
81
+ if name[n] =~ Patterns::SUFFIX_ACADEMIC or name[n] =~ Patterns::SUFFIX_PROFESSIONAL or name[n] =~ Patterns::SUFFIX_GENERATIONAL_ROMAN or name[n] =~ Patterns::SUFFIX_ABBREVIATION
82
+ suff = name[n].upcase.gsub(/\./,'')
83
+ end
84
+
85
+ if suff
86
+ @suffix = @suffix ? "#{suff}, #{@suffix}" : suff
87
+ name.delete_at(n)
88
+ end
89
+
90
+ end
91
+ end
92
+
93
+ ##
94
+ # name is an Array
95
+ def extract_first(name)
96
+ return unless name and name.size >= 1
97
+
98
+ @first = name.first
99
+ name.delete_at(0)
100
+
101
+ @first.capitalize! unless @first =~ /[a-z]/ and @first =~ /[A-Z]/
102
+ end
103
+
104
+ ##
105
+ # name is an Array
106
+ def extract_last(name)
107
+ return unless name and name.size >= 1
108
+
109
+ @last = name.last
110
+ name.delete_at(name.size - 1)
111
+
112
+ @last.capitalize! unless @last =~ /[a-z]/ and @last =~ /[A-Z]/
113
+ end
114
+
115
+ ##
116
+ # name is an Array
117
+ def extract_middle(name)
118
+ return unless name and name.size >= 1
119
+
120
+ (name.size - 1).downto(0) do |n|
121
+ next unless name[n]
122
+
123
+ if name[n] =~ Patterns::LAST_NAME_PRE_DANGLERS
124
+ @last = "#{name[n]} #{@last}"
125
+ elsif name[n] =~ Patterns::LAST_NAME_PRE_CONCATS
126
+ @last = "O'#{@last}"
127
+ elsif name[n] =~ /-+/ and n > 0 and name[n-1]
128
+ @last = "#{name[n-1]}-#{@last}"
129
+ name[n-1] = nil
130
+ else
131
+ @middle = name[n]
132
+ end
133
+
134
+ name.delete_at(n)
135
+ end
136
+
137
+ @middle.capitalize! if @middle and !(@middle =~ /[a-z]/ and @middle =~ /[A-Z]/)
138
+ @middle = "#{@middle}." if @middle and @middle.size == 1
139
+ end
140
+
141
+ def parse(name)
142
+ if name.class == String
143
+ name = name.split(/\s+/)
144
+ end
145
+
146
+ name = name.first.split(/[^[:alnum:]]+/) if name.size == 1 and name.first.split(/[^[:alnum:]]+/)
147
+
148
+ extract_prefix(name)
149
+ extract_suffix(name)
150
+ extract_first(name)
151
+ extract_last(name)
152
+ extract_middle(name)
153
+
154
+ raise InvalidNameError, "A parseable name was not found. #{name.inspect}" unless @first
155
+
156
+ self
157
+ end
158
+
159
+ def to_s
160
+ [@prefix, @first, @middle, @last, @suffix].compact.join(' ')
161
+ end
162
+
163
+ def to_name
164
+ to_nameable
165
+ end
166
+
167
+ def to_fullname
168
+ [@prefix, @first, @middle, @last, @suffix].compact.join(' ')
169
+ end
170
+
171
+ def to_nameable
172
+ [@first, @last].compact.join(' ')
173
+ end
174
+
175
+ def to_hash
176
+ return {
177
+ :prefix => @prefix,
178
+ :first => @first,
179
+ :middle => @middle,
180
+ :last => @last,
181
+ :suffix => @suffix
182
+ }
183
+ end
184
+ end
185
+ end
data/nameable.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "nameable"
3
+ s.version = "0.1"
4
+ s.date = "2010-06-23"
5
+ s.summary = "Provides parsing and output of person names."
6
+ s.email = "chorn@chorn.com"
7
+ s.homepage = "http://github.com/chorn/nameable"
8
+ s.description = "A gem that provides parsing and output of person names."
9
+ s.has_rdoc = true
10
+ s.authors = ["Chris Horn"]
11
+ s.files = [ "LICENSE",
12
+ "README",
13
+ "README.rdoc",
14
+ "Rakefile",
15
+ "TODO",
16
+ "nameable.gemspec",
17
+ "lib/nameable.rb",
18
+ "script/destroy",
19
+ "script/generate",
20
+ "spec/nameable_spec.rb",
21
+ "spec/spec_helper.rb"
22
+ ]
23
+ s.test_files = []
24
+ s.rdoc_options = []
25
+ end
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:newgem_simple, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:newgem_simple, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "nameable" do
4
+ it "should do nothing" do
5
+ true.should == true
6
+ end
7
+ end
@@ -0,0 +1,2 @@
1
+ $TESTING=true
2
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nameable
3
+ version: !ruby/object:Gem::Version
4
+ hash: 9
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ version: "0.1"
10
+ platform: ruby
11
+ authors:
12
+ - Chris Horn
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-06-23 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: A gem that provides parsing and output of person names.
22
+ email: chorn@chorn.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - LICENSE
31
+ - README
32
+ - README.rdoc
33
+ - Rakefile
34
+ - TODO
35
+ - nameable.gemspec
36
+ - lib/nameable.rb
37
+ - script/destroy
38
+ - script/generate
39
+ - spec/nameable_spec.rb
40
+ - spec/spec_helper.rb
41
+ has_rdoc: true
42
+ homepage: http://github.com/chorn/nameable
43
+ licenses: []
44
+
45
+ post_install_message:
46
+ rdoc_options: []
47
+
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ hash: 3
56
+ segments:
57
+ - 0
58
+ version: "0"
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ hash: 3
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ requirements: []
69
+
70
+ rubyforge_project:
71
+ rubygems_version: 1.3.7
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: Provides parsing and output of person names.
75
+ test_files: []
76
+