nameable_record 0.2.0 → 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.
- data/.gitignore +4 -21
- data/.rspec +4 -0
- data/.rvmrc +2 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +134 -0
- data/Guardfile +7 -0
- data/README.rdoc +0 -25
- data/Rakefile +1 -45
- data/lib/nameable_record/active_record_extensions.rb +16 -24
- data/lib/nameable_record/data/given-names.txt +5678 -0
- data/lib/nameable_record/data/surnames.txt +9527 -0
- data/lib/nameable_record/name.rb +56 -32
- data/lib/nameable_record/name_recognition.rb +119 -0
- data/lib/nameable_record/name_recognizer.rb +10 -0
- data/lib/nameable_record/railtie.rb +14 -0
- data/lib/nameable_record/version.rb +4 -0
- data/lib/nameable_record.rb +8 -6
- data/nameable_record.gemspec +23 -48
- data/script/environment.rb +17 -0
- data/spec/database.yml +4 -0
- data/spec/lib/nameable_record/active_record_extensions_spec.rb +43 -0
- data/spec/lib/nameable_record/name_recognition_sharedspec.rb +182 -0
- data/spec/lib/nameable_record/name_recognition_spec.rb +17 -0
- data/spec/lib/nameable_record/name_recognizer_spec.rb +17 -0
- data/spec/lib/nameable_record/name_spec.rb +239 -0
- data/spec/lib/nameable_record_spec.rb +8 -0
- data/spec/rails_spec_helper.rb +3 -0
- data/spec/spec_helper.rb +26 -6
- metadata +76 -27
- data/LICENSE +0 -20
- data/VERSION +0 -1
- data/spec/nameable_record_spec.rb +0 -7
- data/spec/spec.opts +0 -1
data/lib/nameable_record/name.rb
CHANGED
@@ -1,31 +1,28 @@
|
|
1
1
|
module NameableRecord
|
2
|
+
|
2
3
|
class Name
|
4
|
+
|
3
5
|
attr_reader :first, :middle, :last, :prefix, :suffix
|
4
6
|
|
5
|
-
def initialize(
|
6
|
-
@
|
7
|
-
|
8
|
-
@name_pattern_map = {
|
9
|
-
/%l/ => last || "",
|
10
|
-
/%f/ => first || "",
|
11
|
-
/%m/ => middle || "",
|
12
|
-
/%p/ => prefix || "",
|
13
|
-
/%s/ => suffix || "",
|
14
|
-
}
|
15
|
-
|
16
|
-
@@predefined_patterns = {
|
17
|
-
:full => " %l, %f %s",
|
18
|
-
:full_with_middle => " %l, %f %m %s",
|
19
|
-
:full_with_prefix => " %l, %p %f %s",
|
20
|
-
:full_sentence => "%p %f %l %s",
|
21
|
-
:full_sentence_with_middle => "%p %f %m %l %s"
|
22
|
-
}
|
7
|
+
def initialize( *args )
|
8
|
+
@last, @first, @prefix, @middle, @suffix = args
|
23
9
|
|
24
10
|
self.freeze
|
25
11
|
end
|
26
12
|
|
27
|
-
|
28
|
-
|
13
|
+
def ==( another_name )
|
14
|
+
return false unless another_name.is_a?( self.class )
|
15
|
+
|
16
|
+
%w(last first middle suffix prefix).map do |attr|
|
17
|
+
another_name.send( attr ) == send( attr )
|
18
|
+
end.all? { |r| r == true }
|
19
|
+
end
|
20
|
+
|
21
|
+
def eql?( another_name )
|
22
|
+
self == another_name
|
23
|
+
end
|
24
|
+
|
25
|
+
# Creates a name based on pattern provided. Defaults to last, first.
|
29
26
|
#
|
30
27
|
# Symbols:
|
31
28
|
# %l - last name
|
@@ -34,19 +31,46 @@ module NameableRecord
|
|
34
31
|
# %p - prefix
|
35
32
|
# %s - suffix
|
36
33
|
#
|
37
|
-
def to_s( pattern=
|
38
|
-
if pattern.is_a?( Symbol )
|
39
|
-
to_return = @@predefined_patterns[pattern]
|
40
|
-
else
|
41
|
-
to_return = pattern
|
42
|
-
end
|
43
|
-
to_return = @@predefined_patterns[:full] if to_return.empty?
|
34
|
+
def to_s( pattern='%l, %f' )
|
35
|
+
pattern = PREDEFINED_PATTERNS[pattern] if pattern.is_a?( Symbol )
|
44
36
|
|
45
|
-
|
46
|
-
|
37
|
+
PATTERN_MAP.inject( pattern ) do |name, mapping|
|
38
|
+
name = name.gsub( mapping.first,
|
39
|
+
(send( mapping.last ) || '') )
|
47
40
|
end
|
48
|
-
|
49
|
-
to_return.strip
|
50
41
|
end
|
42
|
+
|
43
|
+
PREDEFINED_PATTERNS = {
|
44
|
+
:full => "%l, %f %s",
|
45
|
+
:full_with_middle => "%l, %f %m %s",
|
46
|
+
:full_with_prefix => "%l, %p %f %s",
|
47
|
+
:full_sentence => "%p %f %l %s",
|
48
|
+
:full_sentence_with_middle => "%p %f %m %l %s"
|
49
|
+
}.freeze
|
50
|
+
|
51
|
+
PATTERN_MAP = {
|
52
|
+
/%l/ => :last,
|
53
|
+
/%f/ => :first,
|
54
|
+
/%m/ => :middle,
|
55
|
+
/%p/ => :prefix,
|
56
|
+
/%s/ => :suffix
|
57
|
+
}.freeze
|
58
|
+
|
59
|
+
PREFIX_BASE = %w(Mr Mrs Miss Dr General) # The order of this matters because of PREFIXES_CORRECTIONS
|
60
|
+
SUFFIX_BASE = %w(Jr III V IV Esq) # The order of this matters because of SUFFIXES_CORRECTIONS
|
61
|
+
|
62
|
+
PREFIXES = PREFIX_BASE.map { |p| [p, "#{p}.", p.upcase, "#{p.upcase}.", p.downcase, "#{p.downcase}."] }.flatten.sort
|
63
|
+
SUFFIXES = SUFFIX_BASE.map { |p| [p, "#{p}.", p.upcase, "#{p.upcase}.", p.downcase, "#{p.downcase}."] }.flatten.sort
|
64
|
+
|
65
|
+
PREFIXES_CORRECTIONS = Hash[*PREFIX_BASE.map do |base|
|
66
|
+
PREFIXES.grep( /#{base}/i ).map { |p| [p,base] }
|
67
|
+
end.flatten]
|
68
|
+
|
69
|
+
SUFFIXES_CORRECTIONS = Hash[*SUFFIX_BASE.map do |base|
|
70
|
+
SUFFIXES.grep( /#{base}/i ).map { |p| [p,base] }
|
71
|
+
end.flatten]
|
72
|
+
|
51
73
|
end
|
52
|
-
|
74
|
+
|
75
|
+
end
|
76
|
+
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module NameableRecord::NameRecognition
|
2
|
+
|
3
|
+
def surnames
|
4
|
+
@surnames ||= surnames_from_file
|
5
|
+
end
|
6
|
+
|
7
|
+
def given_names
|
8
|
+
@given_names ||= given_names_from_file
|
9
|
+
end
|
10
|
+
|
11
|
+
%w(downcase upcase).each do |desired_case|
|
12
|
+
define_method "surnames_all_#{desired_case}" do
|
13
|
+
surnames.map( &desired_case.to_sym )
|
14
|
+
end
|
15
|
+
|
16
|
+
define_method "given_names_all_#{desired_case}" do
|
17
|
+
given_names.map( &desired_case.to_sym )
|
18
|
+
end
|
19
|
+
|
20
|
+
define_method "all_name_words_#{desired_case}" do
|
21
|
+
(surnames + given_names + prefixes + suffixes + initials_downcase).map { |n| n.send( desired_case ) }.uniq
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def human_name?( name, lowest_affirmative_probabilty=100, disqualifying_words=[] )
|
26
|
+
probability_is_human_name( name, disqualifying_words ) >= lowest_affirmative_probabilty
|
27
|
+
end
|
28
|
+
|
29
|
+
def probability_is_human_name( name, disqualifying_words=[] )
|
30
|
+
if name.match( /^[a-zA-Z]*\s*[a-zA-Z]{2}$/ )
|
31
|
+
return probability_from_last_and_intials( name, :last_name_first => true )
|
32
|
+
elsif name.match( /^[a-zA-Z]{2}\s*[a-zA-Z]*$/ )
|
33
|
+
return probability_from_last_and_intials( name, :last_name_first => false )
|
34
|
+
end
|
35
|
+
|
36
|
+
name_parts = split_and_clean_name( name )
|
37
|
+
|
38
|
+
return 0 if ((default_disqualifying_words + disqualifying_words) & name_parts).size > 0
|
39
|
+
|
40
|
+
score = (100 - ((name_parts.size - (name_parts & all_name_words_downcase).size) * points_per_additional_word))
|
41
|
+
score < 0 ? 0 : score
|
42
|
+
end
|
43
|
+
|
44
|
+
def default_disqualifying_words
|
45
|
+
%w(
|
46
|
+
corporation
|
47
|
+
corp
|
48
|
+
co
|
49
|
+
llc
|
50
|
+
ltd
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def points_per_additional_word
|
57
|
+
20
|
58
|
+
end
|
59
|
+
|
60
|
+
def probability_from_last_and_intials( name, options )
|
61
|
+
name_parts = split_and_clean_name( name )
|
62
|
+
|
63
|
+
last_name = options[:last_name_first] ? name_parts.first : name_parts.last
|
64
|
+
|
65
|
+
return ([last_name] & surnames_all_downcase).size == 1 ?
|
66
|
+
100 :
|
67
|
+
50
|
68
|
+
end
|
69
|
+
|
70
|
+
def split_and_clean_name( name )
|
71
|
+
name.split( ' ' ).compact.map { |p| p.strip.downcase }
|
72
|
+
end
|
73
|
+
|
74
|
+
def prefixes
|
75
|
+
NameableRecord::Name::PREFIXES
|
76
|
+
end
|
77
|
+
|
78
|
+
def suffixes
|
79
|
+
NameableRecord::Name::SUFFIXES
|
80
|
+
end
|
81
|
+
|
82
|
+
def initials_downcase
|
83
|
+
alphabet_downcase + alphabet_downcase.map { |l| "#{l}." }
|
84
|
+
end
|
85
|
+
|
86
|
+
def alphabet_downcase
|
87
|
+
('a'..'z').to_a
|
88
|
+
end
|
89
|
+
|
90
|
+
def surnames_from_file
|
91
|
+
File.open( surnames_file_path, 'r' ) { |f| f.readlines }.map { |n| n.strip }
|
92
|
+
end
|
93
|
+
|
94
|
+
def surnames_file_path
|
95
|
+
File.join File.dirname(__FILE__),
|
96
|
+
'data',
|
97
|
+
surnames_file_name
|
98
|
+
end
|
99
|
+
|
100
|
+
def surnames_file_name
|
101
|
+
'surnames.txt'
|
102
|
+
end
|
103
|
+
|
104
|
+
def given_names_from_file
|
105
|
+
File.open( given_names_file_path, 'r' ) { |f| f.readlines }.map { |n| n.strip }
|
106
|
+
end
|
107
|
+
|
108
|
+
def given_names_file_path
|
109
|
+
File.join File.dirname(__FILE__),
|
110
|
+
'data',
|
111
|
+
given_names_file_name
|
112
|
+
end
|
113
|
+
|
114
|
+
def given_names_file_name
|
115
|
+
'given-names.txt'
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rails'
|
2
|
+
|
3
|
+
module NameableRecord
|
4
|
+
|
5
|
+
class Railtie < ::Rails::Railtie
|
6
|
+
|
7
|
+
initializer "nameable_record.initialize" do
|
8
|
+
ActiveRecord::Base.send( :include, NameableRecord::ActiveRecordExtensions ) if defined?( ActiveRecord::Base )
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
data/lib/nameable_record.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'nameable_record/active_record_extensions'
|
4
|
-
require 'nameable_record/name'
|
1
|
+
require "nameable_record/railtie" if defined?( ::Rails )
|
2
|
+
require "nameable_record/version"
|
5
3
|
|
6
4
|
module NameableRecord
|
7
|
-
|
5
|
+
|
6
|
+
autoload :ActiveRecordExtensions, 'nameable_record/active_record_extensions'
|
7
|
+
autoload :Name, 'nameable_record/name'
|
8
|
+
autoload :NameRecognition, 'nameable_record/name_recognition'
|
9
|
+
autoload :NameRecognizer, 'nameable_record/name_recognizer'
|
10
|
+
|
8
11
|
end
|
9
12
|
|
10
|
-
ActiveRecord::Base.send( :include, NameableRecord::ActiveRecordExtensions ) if defined?( ActiveRecord::Base )
|
data/nameable_record.gemspec
CHANGED
@@ -1,57 +1,32 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "nameable_record/version"
|
5
4
|
|
6
5
|
Gem::Specification.new do |s|
|
7
|
-
s.name
|
8
|
-
s.version
|
6
|
+
s.name = "nameable_record"
|
7
|
+
s.version = NameableRecord::VERSION
|
8
|
+
s.authors = ["Jason Harrelson"]
|
9
|
+
s.email = ["jason@lookforwardenterprises.com"]
|
10
|
+
s.homepage = "https://github.com/midas/nameable_record"
|
11
|
+
s.summary = %q{Abstracts the ActiveRecord composed_of pattern for names.}
|
12
|
+
s.description = %q{Abstracts the ActiveRecord composed_of pattern for names. Also provides other convenience utilieis for working with human names.}
|
9
13
|
|
10
|
-
s.
|
11
|
-
s.authors = ["C. Jason Harrelson"]
|
12
|
-
s.date = %q{2010-10-02}
|
13
|
-
s.description = %q{Encapsulates the composed of pattern for names into any easy to use library.}
|
14
|
-
s.email = %q{jason@lookforwardenterprises.com}
|
15
|
-
s.extra_rdoc_files = [
|
16
|
-
"LICENSE",
|
17
|
-
"README.rdoc"
|
18
|
-
]
|
19
|
-
s.files = [
|
20
|
-
".document",
|
21
|
-
".gitignore",
|
22
|
-
"LICENSE",
|
23
|
-
"README.rdoc",
|
24
|
-
"Rakefile",
|
25
|
-
"VERSION",
|
26
|
-
"lib/nameable_record.rb",
|
27
|
-
"lib/nameable_record/active_record_extensions.rb",
|
28
|
-
"lib/nameable_record/name.rb",
|
29
|
-
"nameable_record.gemspec",
|
30
|
-
"spec/nameable_record_spec.rb",
|
31
|
-
"spec/spec.opts",
|
32
|
-
"spec/spec_helper.rb"
|
33
|
-
]
|
34
|
-
s.homepage = %q{http://github.com/midas/nameable_record}
|
35
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
36
|
-
s.require_paths = ["lib"]
|
37
|
-
s.rubygems_version = %q{1.3.7}
|
38
|
-
s.summary = %q{Encapsulates the composed of pattern for names into any easy to use library.}
|
39
|
-
s.test_files = [
|
40
|
-
"spec/nameable_record_spec.rb",
|
41
|
-
"spec/spec_helper.rb"
|
42
|
-
]
|
14
|
+
s.rubyforge_project = "nameable_record"
|
43
15
|
|
44
|
-
|
45
|
-
|
46
|
-
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
47
20
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
s.
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
%w(
|
23
|
+
gem-dandy
|
24
|
+
rspec
|
25
|
+
rails
|
26
|
+
).each do |development_dependency|
|
27
|
+
s.add_development_dependency development_dependency
|
55
28
|
end
|
29
|
+
|
30
|
+
# s.add_runtime_dependency "rest-client"
|
56
31
|
end
|
57
32
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
ActiveRecord::Base.configurations = YAML::load( IO.read( File.dirname(__FILE__) + '/../spec/database.yml' ) )
|
2
|
+
ActiveRecord::Base.establish_connection( 'test' )
|
3
|
+
|
4
|
+
silence_stream STDOUT do
|
5
|
+
|
6
|
+
ActiveRecord::Schema.define :version => 1 do
|
7
|
+
create_table :users, :force => true do |t|
|
8
|
+
t.string :name_first, :anem_last, :name_middle, :name_prefix, :name_suffix
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
class User < ActiveRecord::Base
|
15
|
+
has_name :name
|
16
|
+
end
|
17
|
+
|
data/spec/database.yml
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rails_spec_helper'
|
3
|
+
|
4
|
+
describe NameableRecord::ActiveRecordExtensions do
|
5
|
+
|
6
|
+
let :user do
|
7
|
+
User.new
|
8
|
+
end
|
9
|
+
|
10
|
+
let :name do
|
11
|
+
NameableRecord::Name.new *name_parts
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'setting the composed of fields from a NameableRecord::Name instance' do
|
15
|
+
|
16
|
+
before :each do
|
17
|
+
user.name = name
|
18
|
+
end
|
19
|
+
|
20
|
+
it '#name_last' do
|
21
|
+
user.name_last.should == 'Smith'
|
22
|
+
end
|
23
|
+
|
24
|
+
it '#name_first' do
|
25
|
+
user.name_first.should == 'John'
|
26
|
+
end
|
27
|
+
|
28
|
+
it '#name_middle' do
|
29
|
+
user.name_middle.should == 'Jacob'
|
30
|
+
end
|
31
|
+
|
32
|
+
it '#name_prefix' do
|
33
|
+
user.name_prefix.should == 'Mr.'
|
34
|
+
end
|
35
|
+
|
36
|
+
it '#name_suffix' do
|
37
|
+
user.name_suffix.should == 'III'
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples_for 'any name recognition' do
|
4
|
+
|
5
|
+
context '#surnames' do
|
6
|
+
|
7
|
+
subject { recognition_instance.surnames.size }
|
8
|
+
|
9
|
+
it { should == 9527 }
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
context '#surnames_all_downcase' do
|
14
|
+
|
15
|
+
subject { recognition_instance.surnames_all_downcase.first }
|
16
|
+
|
17
|
+
it { should == 'aaron' }
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
context '#surnames_all_upcase' do
|
22
|
+
|
23
|
+
subject { recognition_instance.surnames_all_upcase.first }
|
24
|
+
|
25
|
+
it { should == 'AARON' }
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
context '#human_name?' do
|
30
|
+
|
31
|
+
context 'when the name matches the pattern {last name} {first initial}{middle initial}' do
|
32
|
+
|
33
|
+
subject { recognition_instance.human_name?( 'HOMER SA' ) }
|
34
|
+
|
35
|
+
it { should be_true }
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when the name matches the pattern {first initial}{middle initial} {last name}' do
|
40
|
+
|
41
|
+
subject { recognition_instance.human_name?( 'SA HOMER' ) }
|
42
|
+
|
43
|
+
it { should be_true }
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when the middle initial has no .' do
|
48
|
+
|
49
|
+
subject { recognition_instance.human_name?( 'HOMER STEPHEN A' ) }
|
50
|
+
|
51
|
+
it { should be_true }
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when the middle initial has a .' do
|
56
|
+
|
57
|
+
subject { recognition_instance.human_name?( 'HOMER STEPHEN A.' ) }
|
58
|
+
|
59
|
+
it { should be_true }
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when the name is an 80% match' do
|
64
|
+
|
65
|
+
subject { recognition_instance.human_name?( 'CUP STEPHEN A' ) }
|
66
|
+
|
67
|
+
it { should be_false }
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when the name is less an 80% match with a 70% threshold' do
|
72
|
+
|
73
|
+
subject { recognition_instance.human_name?( 'CUP STEPHEN A', 80 ) }
|
74
|
+
|
75
|
+
it { should be_true }
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
context '#given_names' do
|
82
|
+
|
83
|
+
subject { recognition_instance.given_names.size }
|
84
|
+
|
85
|
+
it { should == 5678 }
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
context '#given_names_all_downcase' do
|
90
|
+
|
91
|
+
subject { recognition_instance.given_names_all_downcase.first }
|
92
|
+
|
93
|
+
it { should == 'aj' }
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
context '#given_names_all_upcase' do
|
98
|
+
|
99
|
+
subject { recognition_instance.given_names_all_upcase.first }
|
100
|
+
|
101
|
+
it { should == 'AJ' }
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
context '#all_name_words_downcase' do
|
106
|
+
|
107
|
+
subject { recognition_instance.all_name_words_downcase.size }
|
108
|
+
|
109
|
+
it { should == 14297 }
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
context '#all_name_words_upcase' do
|
114
|
+
|
115
|
+
subject { recognition_instance.all_name_words_upcase.size }
|
116
|
+
|
117
|
+
it { should == 14297 }
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
context '#prefixes' do
|
122
|
+
|
123
|
+
subject { recognition_instance.send( :prefixes ).sort }
|
124
|
+
|
125
|
+
it { should == ["DR", "DR.", "Dr", "Dr.", "GENERAL", "GENERAL.", "General", "General.", "MISS", "MISS.", "MR", "MR.", "MRS", "MRS.", "Miss", "Miss.", "Mr", "Mr.", "Mrs", "Mrs.", "dr", "dr.", "general", "general.", "miss", "miss.", "mr", "mr.", "mrs", "mrs."] }
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
context '#suffixes' do
|
130
|
+
|
131
|
+
subject { recognition_instance.send( :suffixes ).sort }
|
132
|
+
|
133
|
+
it { should == ["ESQ", "ESQ.", "Esq", "Esq.", "III", "III", "III.", "III.", "IV", "IV", "IV.", "IV.", "JR", "JR.", "Jr", "Jr.", "V", "V", "V.", "V.", "esq", "esq.", "iii", "iii.", "iv", "iv.", "jr", "jr.", "v", "v."] }
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
context '#probability_is_human_name' do
|
138
|
+
|
139
|
+
context 'when all words are a name part' do
|
140
|
+
|
141
|
+
subject { recognition_instance.probability_is_human_name( 'Mr. Charles Langford III' ) }
|
142
|
+
|
143
|
+
it { should == 100 }
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'when there is one word that is not a name part' do
|
148
|
+
|
149
|
+
subject { recognition_instance.probability_is_human_name( 'Introducing Mr. Charles Langford III' ) }
|
150
|
+
|
151
|
+
it { should == 80 }
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when there are two words that are not a name part' do
|
156
|
+
|
157
|
+
subject { recognition_instance.probability_is_human_name( 'Home of Mr. Charles Langford III' ) }
|
158
|
+
|
159
|
+
it { should == 60 }
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'when there are five words that are not a name part' do
|
164
|
+
|
165
|
+
subject { recognition_instance.probability_is_human_name( 'This is the home of Mr. Charles Langford III' ) }
|
166
|
+
|
167
|
+
it { should == 0 }
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
context 'when there are six words that are not a name part' do
|
172
|
+
|
173
|
+
subject { recognition_instance.probability_is_human_name( 'It is at the home of Mr. Charles Langford III' ) }
|
174
|
+
|
175
|
+
it { should == 0 }
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require File.expand_path( "#{File.dirname __FILE__}/name_recognition_sharedspec" )
|
3
|
+
|
4
|
+
describe NameableRecord::NameRecognition do
|
5
|
+
|
6
|
+
class SomeClass
|
7
|
+
include NameableRecord::NameRecognition
|
8
|
+
end
|
9
|
+
|
10
|
+
let :recognition_instance do
|
11
|
+
SomeClass.new
|
12
|
+
end
|
13
|
+
|
14
|
+
it_should_behave_like 'any name recognition'
|
15
|
+
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require File.expand_path( "#{File.dirname __FILE__}/name_recognition_sharedspec" )
|
3
|
+
|
4
|
+
describe NameableRecord::NameRecognizer do
|
5
|
+
|
6
|
+
let :recognition_instance do
|
7
|
+
described_class.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should include the NameRecognition module' do
|
11
|
+
described_class.should include NameableRecord::NameRecognition
|
12
|
+
end
|
13
|
+
|
14
|
+
it_should_behave_like 'any name recognition'
|
15
|
+
|
16
|
+
end
|
17
|
+
|