person-name 0.2.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/Gemfile +10 -0
- data/Gemfile.lock +101 -0
- data/MIT-LICENSE +21 -0
- data/README.markdown +98 -0
- data/Rakefile +51 -0
- data/VERSION +1 -0
- data/lib/person_name/migration_support.rb +12 -0
- data/lib/person_name/name.rb +202 -0
- data/lib/person_name.rb +78 -0
- data/rails/init.rb +5 -0
- data/spec/database.yml +17 -0
- data/spec/database.yml.sample +17 -0
- data/spec/models.rb +4 -0
- data/spec/person_name/has_person_name_spec.rb +96 -0
- data/spec/schema.rb +11 -0
- data/spec/spec_helper.rb +59 -0
- metadata +85 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
GEM
|
|
2
|
+
remote: http://rubygems.org/
|
|
3
|
+
specs:
|
|
4
|
+
abstract (1.0.0)
|
|
5
|
+
actionmailer (3.0.0)
|
|
6
|
+
actionpack (= 3.0.0)
|
|
7
|
+
mail (~> 2.2.5)
|
|
8
|
+
actionpack (3.0.0)
|
|
9
|
+
activemodel (= 3.0.0)
|
|
10
|
+
activesupport (= 3.0.0)
|
|
11
|
+
builder (~> 2.1.2)
|
|
12
|
+
erubis (~> 2.6.6)
|
|
13
|
+
i18n (~> 0.4.1)
|
|
14
|
+
rack (~> 1.2.1)
|
|
15
|
+
rack-mount (~> 0.6.12)
|
|
16
|
+
rack-test (~> 0.5.4)
|
|
17
|
+
tzinfo (~> 0.3.23)
|
|
18
|
+
activemodel (3.0.0)
|
|
19
|
+
activesupport (= 3.0.0)
|
|
20
|
+
builder (~> 2.1.2)
|
|
21
|
+
i18n (~> 0.4.1)
|
|
22
|
+
activerecord (3.0.0)
|
|
23
|
+
activemodel (= 3.0.0)
|
|
24
|
+
activesupport (= 3.0.0)
|
|
25
|
+
arel (~> 1.0.0)
|
|
26
|
+
tzinfo (~> 0.3.23)
|
|
27
|
+
activeresource (3.0.0)
|
|
28
|
+
activemodel (= 3.0.0)
|
|
29
|
+
activesupport (= 3.0.0)
|
|
30
|
+
activesupport (3.0.0)
|
|
31
|
+
arel (1.0.1)
|
|
32
|
+
activesupport (~> 3.0.0)
|
|
33
|
+
builder (2.1.2)
|
|
34
|
+
diff-lcs (1.1.2)
|
|
35
|
+
erubis (2.6.6)
|
|
36
|
+
abstract (>= 1.0.0)
|
|
37
|
+
gemcutter (0.6.1)
|
|
38
|
+
git (1.2.5)
|
|
39
|
+
i18n (0.4.1)
|
|
40
|
+
jeweler (1.4.0)
|
|
41
|
+
gemcutter (>= 0.1.0)
|
|
42
|
+
git (>= 1.2.5)
|
|
43
|
+
rubyforge (>= 2.0.0)
|
|
44
|
+
json_pure (1.4.6)
|
|
45
|
+
mail (2.2.6.1)
|
|
46
|
+
activesupport (>= 2.3.6)
|
|
47
|
+
mime-types
|
|
48
|
+
treetop (>= 1.4.5)
|
|
49
|
+
mime-types (1.16)
|
|
50
|
+
mysql (2.8.1)
|
|
51
|
+
pg (0.9.0)
|
|
52
|
+
polyglot (0.3.1)
|
|
53
|
+
rack (1.2.1)
|
|
54
|
+
rack-mount (0.6.13)
|
|
55
|
+
rack (>= 1.0.0)
|
|
56
|
+
rack-test (0.5.5)
|
|
57
|
+
rack (>= 1.0)
|
|
58
|
+
rails (3.0.0)
|
|
59
|
+
actionmailer (= 3.0.0)
|
|
60
|
+
actionpack (= 3.0.0)
|
|
61
|
+
activerecord (= 3.0.0)
|
|
62
|
+
activeresource (= 3.0.0)
|
|
63
|
+
activesupport (= 3.0.0)
|
|
64
|
+
bundler (~> 1.0.0)
|
|
65
|
+
railties (= 3.0.0)
|
|
66
|
+
railties (3.0.0)
|
|
67
|
+
actionpack (= 3.0.0)
|
|
68
|
+
activesupport (= 3.0.0)
|
|
69
|
+
rake (>= 0.8.4)
|
|
70
|
+
thor (~> 0.14.0)
|
|
71
|
+
rake (0.8.7)
|
|
72
|
+
rcov (0.9.9)
|
|
73
|
+
rspec (2.0.0.beta.22)
|
|
74
|
+
rspec-core (= 2.0.0.beta.22)
|
|
75
|
+
rspec-expectations (= 2.0.0.beta.22)
|
|
76
|
+
rspec-mocks (= 2.0.0.beta.22)
|
|
77
|
+
rspec-core (2.0.0.beta.22)
|
|
78
|
+
rspec-expectations (2.0.0.beta.22)
|
|
79
|
+
diff-lcs (>= 1.1.2)
|
|
80
|
+
rspec-mocks (2.0.0.beta.22)
|
|
81
|
+
rspec-core (= 2.0.0.beta.22)
|
|
82
|
+
rspec-expectations (= 2.0.0.beta.22)
|
|
83
|
+
rubyforge (2.0.4)
|
|
84
|
+
json_pure (>= 1.1.7)
|
|
85
|
+
sqlite3-ruby (1.3.1)
|
|
86
|
+
thor (0.14.1)
|
|
87
|
+
treetop (1.4.8)
|
|
88
|
+
polyglot (>= 0.3.1)
|
|
89
|
+
tzinfo (0.3.23)
|
|
90
|
+
|
|
91
|
+
PLATFORMS
|
|
92
|
+
ruby
|
|
93
|
+
|
|
94
|
+
DEPENDENCIES
|
|
95
|
+
jeweler
|
|
96
|
+
mysql
|
|
97
|
+
pg
|
|
98
|
+
rails (= 3.0.0)
|
|
99
|
+
rcov
|
|
100
|
+
rspec (= 2.0.0.beta.22)
|
|
101
|
+
sqlite3-ruby
|
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Copyright (c) 2010 Matthijs Groen
|
|
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.
|
|
21
|
+
|
data/README.markdown
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Person Name
|
|
2
|
+
===========
|
|
3
|
+
Person name is an active record plugin to add support for full names.
|
|
4
|
+
A persons name consists of the following parts: prefix, first_name, middle_name, intercalation, last_name and suffix
|
|
5
|
+
|
|
6
|
+
If you have to fill in a name for somebody, you have to display all those fields, and fill them in.
|
|
7
|
+
The goal is to make one field that can split up the name and assign it to the correct fields automatically.
|
|
8
|
+
You can also still use the more precise input if necessary.
|
|
9
|
+
|
|
10
|
+
Usage
|
|
11
|
+
=====
|
|
12
|
+
|
|
13
|
+
Small gem to insert easy person name behaviour into rails models
|
|
14
|
+
|
|
15
|
+
migration:
|
|
16
|
+
|
|
17
|
+
create_table :people do |t|
|
|
18
|
+
t.person_name :name
|
|
19
|
+
t.person_name :birth_name
|
|
20
|
+
t.boolean :female, :null => true
|
|
21
|
+
|
|
22
|
+
t.timestamps
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
In this case the following fields are created:
|
|
26
|
+
|
|
27
|
+
name_prefix
|
|
28
|
+
name_first_name
|
|
29
|
+
name_middle_name
|
|
30
|
+
name_intercalation
|
|
31
|
+
name_last_name
|
|
32
|
+
name_suffix
|
|
33
|
+
|
|
34
|
+
birth_name_prefix
|
|
35
|
+
birth_name_first_name
|
|
36
|
+
birth_name_middle_name
|
|
37
|
+
birth_name_intercalation
|
|
38
|
+
birth_name_last_name
|
|
39
|
+
birth_name_suffix
|
|
40
|
+
|
|
41
|
+
female
|
|
42
|
+
created_at
|
|
43
|
+
updated_at
|
|
44
|
+
|
|
45
|
+
model:
|
|
46
|
+
|
|
47
|
+
class Person < ActiveRecord::Base
|
|
48
|
+
|
|
49
|
+
has_person_name :name, :birth_name
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
Now put this thing to use:
|
|
55
|
+
|
|
56
|
+
p = Person.new
|
|
57
|
+
p.name = "Matthijs Jacobus Groen"
|
|
58
|
+
p.name.first_name # Matthijs
|
|
59
|
+
p.name.middle_name # Jacobus
|
|
60
|
+
p.name.last_name # Groen
|
|
61
|
+
p.name.short_name # M.J. Groen
|
|
62
|
+
|
|
63
|
+
p = Person.new
|
|
64
|
+
p.name = "Ariejan de Vroom"
|
|
65
|
+
p.name.first_name # Ariejan
|
|
66
|
+
p.name.intercalation # de
|
|
67
|
+
p.name.last_name # Vroom
|
|
68
|
+
p.name.full_last_name # de Vroom
|
|
69
|
+
|
|
70
|
+
p = Person.new
|
|
71
|
+
p.name = "Cornelia Maria Hendrika Damen-van Valkenberg"
|
|
72
|
+
p.name.first_name # Cornelia
|
|
73
|
+
p.name.middle_name # Maria Hendrika
|
|
74
|
+
p.name.last_name # Damen-van Valkenberg
|
|
75
|
+
|
|
76
|
+
Sometimes, things can go wrong:
|
|
77
|
+
|
|
78
|
+
p = Person.new
|
|
79
|
+
p.name = "Yolanthe Cabau van Kasbergen"
|
|
80
|
+
p.name.first_name # Yolanthe
|
|
81
|
+
p.name.middle_name # Cabau
|
|
82
|
+
p.name.intercalation # van
|
|
83
|
+
p.name.last_name # Kasbergen
|
|
84
|
+
|
|
85
|
+
But, if you correct it, it will remember it:
|
|
86
|
+
|
|
87
|
+
p.name.intercalation = nil
|
|
88
|
+
p.name.middle_name = nil
|
|
89
|
+
p.name.last_name = "Cabau van Kasbergen"
|
|
90
|
+
|
|
91
|
+
# and now change something:
|
|
92
|
+
|
|
93
|
+
p.name = "Yolanthe Truuske Cabau van Kasbergen"
|
|
94
|
+
p.name.first_name # Yolanthe
|
|
95
|
+
p.name.middle_name # Truuske
|
|
96
|
+
p.name.intercalation # nil
|
|
97
|
+
p.name.last_name # Cabau van Kasbergen
|
|
98
|
+
|
data/Rakefile
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
begin
|
|
2
|
+
# Rspec 1.3.0
|
|
3
|
+
require 'spec/rake/spectask'
|
|
4
|
+
|
|
5
|
+
desc 'Default: run specs'
|
|
6
|
+
task :default => :spec
|
|
7
|
+
Spec::Rake::SpecTask.new do |t|
|
|
8
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
Spec::Rake::SpecTask.new('rcov') do |t|
|
|
12
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
|
13
|
+
t.rcov = true
|
|
14
|
+
t.rcov_opts = ['--exclude', 'spec']
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
rescue LoadError
|
|
18
|
+
# Rspec 2.0
|
|
19
|
+
require 'rspec/core/rake_task'
|
|
20
|
+
|
|
21
|
+
desc 'Default: run specs'
|
|
22
|
+
task :default => :spec
|
|
23
|
+
Rspec::Core::RakeTask.new do |t|
|
|
24
|
+
t.pattern = "spec/**/*_spec.rb"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Rspec::Core::RakeTask.new('rcov') do |t|
|
|
28
|
+
t.pattern = "spec/**/*_spec.rb"
|
|
29
|
+
t.rcov = true
|
|
30
|
+
t.rcov_opts = ['--exclude', 'spec']
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
rescue LoadError
|
|
34
|
+
puts "Rspec not available. Install it with: gem install rspec"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
begin
|
|
38
|
+
require 'jeweler'
|
|
39
|
+
Jeweler::Tasks.new do |gemspec|
|
|
40
|
+
gemspec.name = "person-name"
|
|
41
|
+
gemspec.summary = "Easy editing of person names."
|
|
42
|
+
gemspec.description = "Manages all person name fields (prefix, first name, middle name, intercalation, last name, suffix)"
|
|
43
|
+
gemspec.email = "matthijs.groen@gmail.com"
|
|
44
|
+
gemspec.homepage = "http://github.com/matthijsgroen/person-name"
|
|
45
|
+
gemspec.authors = ["Matthijs Groen"]
|
|
46
|
+
gemspec.files = FileList["[A-Z]*", "{generators,lib,spec,rails}/**/*"] - FileList["**/*.log"]
|
|
47
|
+
end
|
|
48
|
+
Jeweler::GemcutterTasks.new
|
|
49
|
+
rescue LoadError
|
|
50
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
|
51
|
+
end
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.2.0
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
module PersonName::MigrationSupport
|
|
3
|
+
|
|
4
|
+
def person_name(name, *args)
|
|
5
|
+
options = args.extract_options!
|
|
6
|
+
name_parts = PersonName::Name::NAME_PARTS
|
|
7
|
+
name_parts.each do |part|
|
|
8
|
+
column("#{name}_#{part}".to_sym, :string, :null => true)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
end
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
class PersonName::Name
|
|
2
|
+
|
|
3
|
+
NAME_PARTS = %w(prefix first_name middle_name intercalation last_name suffix)
|
|
4
|
+
|
|
5
|
+
def initialize(naming_prefix, record)
|
|
6
|
+
@naming_prefix = naming_prefix
|
|
7
|
+
@record = record
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def full_name
|
|
11
|
+
NAME_PARTS.collect { |p| self.send(p) }.compact.join " "
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def full_name= new_name
|
|
15
|
+
# Matthijs Jacobus Groen
|
|
16
|
+
# Patricia Jose Huisman
|
|
17
|
+
# Thijs van de Biggelaar
|
|
18
|
+
# Michael Thijssens
|
|
19
|
+
# Maria Cornelia Hendrina Damen-van Valenberg
|
|
20
|
+
# Dirk Jan van den Abeele
|
|
21
|
+
# Yolanthe Cabau van Kasbergen
|
|
22
|
+
# Yolanthe Sneijder-Cabau
|
|
23
|
+
return if full_name == new_name # no changes
|
|
24
|
+
|
|
25
|
+
parts = new_name.split " "
|
|
26
|
+
names = []
|
|
27
|
+
stage = :prefix
|
|
28
|
+
remember = nil
|
|
29
|
+
parts.each_with_index do |part, index|
|
|
30
|
+
is_upcase = part.first == part.first.upcase
|
|
31
|
+
has_dash = part.include? "-"
|
|
32
|
+
is_last = (parts.length - 1) == index
|
|
33
|
+
|
|
34
|
+
fp = [remember, part].compact.join(" ")
|
|
35
|
+
remember = nil
|
|
36
|
+
did_remember = (fp != part)
|
|
37
|
+
if valid_prefix?(part) and stage == :prefix # if the part is a valid prefix, mark it as such
|
|
38
|
+
names = add_to_last_if :prefix, fp, names
|
|
39
|
+
elsif valid_suffix?(part) and stage == :name # if the part is a valid suffix, mark it as such
|
|
40
|
+
names = add_to_last_if :suffix, fp, names
|
|
41
|
+
elsif part == "-" # if the part is a dash
|
|
42
|
+
if last_stored = names.pop # retrieve the previous name part (if any) and store it with the dash
|
|
43
|
+
# for the part to come (remember)
|
|
44
|
+
remember = [last_stored[0], fp].compact.join(" ")
|
|
45
|
+
else
|
|
46
|
+
# if there is no previous part, just store the current part for later
|
|
47
|
+
remember = fp
|
|
48
|
+
end
|
|
49
|
+
elsif !is_upcase and !did_remember # intercalation words are never with a capital
|
|
50
|
+
names = add_to_last_if :intercalation, fp, names
|
|
51
|
+
stage = :name
|
|
52
|
+
elsif !is_upcase and did_remember
|
|
53
|
+
remember = fp
|
|
54
|
+
elsif is_upcase and !has_dash
|
|
55
|
+
names << [fp, :name]
|
|
56
|
+
stage = :name
|
|
57
|
+
elsif is_upcase and has_dash
|
|
58
|
+
if fp.ends_with? "-"
|
|
59
|
+
if is_last
|
|
60
|
+
names << [fp, :name]
|
|
61
|
+
stage = :name
|
|
62
|
+
else
|
|
63
|
+
remember = fp
|
|
64
|
+
end
|
|
65
|
+
else
|
|
66
|
+
if fp.starts_with?("-") and last_stored = names.pop
|
|
67
|
+
fp = [last_stored[0], fp].compact.join(" ")
|
|
68
|
+
end
|
|
69
|
+
dash_parts = fp.split "-"
|
|
70
|
+
if dash_parts.last.first == dash_parts.last.first.upcase
|
|
71
|
+
names << [fp, :name]
|
|
72
|
+
stage = :name
|
|
73
|
+
elsif is_last
|
|
74
|
+
names << [fp, :name]
|
|
75
|
+
stage = :name
|
|
76
|
+
else
|
|
77
|
+
remember = fp
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
new_name = {}
|
|
84
|
+
stage = O[:prefix]
|
|
85
|
+
|
|
86
|
+
names.each_with_index do |value, index|
|
|
87
|
+
name, name_type = *value
|
|
88
|
+
stage = recheck_stage(name, stage)
|
|
89
|
+
|
|
90
|
+
if name_type == :prefix and stage == O[:prefix]
|
|
91
|
+
elsif name_type == :suffix and (index == names.length - 1)
|
|
92
|
+
stage = [O[:suffix], stage].max
|
|
93
|
+
elsif name_type == :suffix and (index != names.length - 1)
|
|
94
|
+
name_type = :name
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
if name_type == :name
|
|
98
|
+
if (index == names.length - 1) or new_name[:intercalation]
|
|
99
|
+
stage = [O[:last_name], stage].max
|
|
100
|
+
else
|
|
101
|
+
if !new_name[:first_name]
|
|
102
|
+
stage = [O[:first_name], stage].max
|
|
103
|
+
else
|
|
104
|
+
stage = [O[:middle_name], stage].max
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
elsif name_type == :intercalation
|
|
108
|
+
stage = [O[:intercalation], stage].max
|
|
109
|
+
end
|
|
110
|
+
new_name = add_part(new_name, stage, name)
|
|
111
|
+
end
|
|
112
|
+
# assignments
|
|
113
|
+
NAME_PARTS.each do |part|
|
|
114
|
+
self.send "#{part}=", (new_name[part.to_sym] || "").blank? ? nil : new_name[part.to_sym]
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def full_last_name
|
|
119
|
+
[:intercalation, :last_name, :suffix].collect { |p| self.send(p) }.compact.join " "
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def short_name include_middle_names = true
|
|
123
|
+
parts = []
|
|
124
|
+
parts << "#{self.first_name.first.upcase}." if self.first_name
|
|
125
|
+
if include_middle_names and self.middle_name
|
|
126
|
+
names = self.middle_name.split(" ")
|
|
127
|
+
names.each do |name|
|
|
128
|
+
parts << "#{name.first.upcase}."
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
[parts.join, full_last_name] * " "
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
NAME_PARTS.each do |part|
|
|
135
|
+
define_method part do
|
|
136
|
+
@record.send("#{@naming_prefix}_#{part}")
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
define_method "#{part}=" do |value|
|
|
140
|
+
@record.send("#{@naming_prefix}_#{part}=", value)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def to_s
|
|
145
|
+
full_name
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
|
|
150
|
+
O = {
|
|
151
|
+
:prefix => 0,
|
|
152
|
+
:first_name => 1,
|
|
153
|
+
:middle_name => 2,
|
|
154
|
+
:intercalation => 3,
|
|
155
|
+
:last_name => 4,
|
|
156
|
+
:suffix => 5
|
|
157
|
+
}.freeze
|
|
158
|
+
OR = O.invert
|
|
159
|
+
|
|
160
|
+
def add_part new_name, part_score, part
|
|
161
|
+
part_name = OR[part_score]
|
|
162
|
+
new_name[part_name.to_sym] = [new_name[part_name.to_sym], part].compact.join(" ")
|
|
163
|
+
new_name
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def recheck_stage value, stage
|
|
167
|
+
# test if the given value is already stored in the name right now
|
|
168
|
+
new_stage = stage
|
|
169
|
+
NAME_PARTS.each do |part|
|
|
170
|
+
part_values = (self.send(part) || "").split(" ")
|
|
171
|
+
|
|
172
|
+
part_score = O[part.to_sym]
|
|
173
|
+
if part_values.include? value
|
|
174
|
+
part_score = O[:first_name] if stage == O[:prefix] and part = :middle_name
|
|
175
|
+
new_stage = part_score if part_score > new_stage
|
|
176
|
+
return new_stage
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
stage
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def add_to_last_if part, value, list
|
|
183
|
+
if list.last and list.last[1] == part
|
|
184
|
+
last_part = list.pop
|
|
185
|
+
list << [[last_part[0], value].compact.join(" "), part]
|
|
186
|
+
else
|
|
187
|
+
list << [value, part]
|
|
188
|
+
end
|
|
189
|
+
list
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
attr_reader :naming_prefix, :record
|
|
193
|
+
|
|
194
|
+
def valid_prefix? name_part
|
|
195
|
+
false
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def valid_suffix? name_part
|
|
199
|
+
false
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
end
|
data/lib/person_name.rb
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module PersonName
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
|
|
5
|
+
def self.included(base) # :nodoc:
|
|
6
|
+
base.extend ClassMethods
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
|
|
11
|
+
def has_person_names?
|
|
12
|
+
false
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def has_person_name(*name_types)
|
|
16
|
+
name_types = name_types.to_a.flatten.compact.map(&:to_sym)
|
|
17
|
+
name_types << :name if name_types.empty?
|
|
18
|
+
|
|
19
|
+
if has_person_names?
|
|
20
|
+
write_inheritable_attribute(:name_types, (self.name_types + name_types).uniq)
|
|
21
|
+
else
|
|
22
|
+
write_inheritable_attribute(:name_types, name_types)
|
|
23
|
+
class_inheritable_reader(:name_types)
|
|
24
|
+
|
|
25
|
+
class_eval do
|
|
26
|
+
def self.has_person_names?
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
include PersonName::ActiveRecord::Core
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
module Core
|
|
38
|
+
|
|
39
|
+
def self.included(base)
|
|
40
|
+
base.send :include, PersonName::ActiveRecord::Core::InstanceMethods
|
|
41
|
+
base.extend PersonName::ActiveRecord::Core::ClassMethods
|
|
42
|
+
base.initialize_person_names
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
module ClassMethods
|
|
46
|
+
def initialize_person_names
|
|
47
|
+
name_types.map(&:to_s).each do |name_type|
|
|
48
|
+
class_eval %(
|
|
49
|
+
def #{name_type}
|
|
50
|
+
person_name_for('#{name_type}')
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def #{name_type}= new_name
|
|
54
|
+
set_person_name_for('#{name_type}', new_name)
|
|
55
|
+
end
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
module InstanceMethods
|
|
62
|
+
|
|
63
|
+
def person_name_for field
|
|
64
|
+
@person_names ||= {}
|
|
65
|
+
@person_names[field] ||= PersonName::Name.new(field, self)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def set_person_name_for field, new_name
|
|
69
|
+
person_name_for(field).full_name = new_name
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
data/rails/init.rb
ADDED
data/spec/database.yml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
sqlite3:
|
|
2
|
+
adapter: sqlite3
|
|
3
|
+
database: has_person_name.sqlite3
|
|
4
|
+
|
|
5
|
+
mysql:
|
|
6
|
+
adapter: mysql
|
|
7
|
+
hostname: localhost
|
|
8
|
+
username: root
|
|
9
|
+
password:
|
|
10
|
+
database: has_person_name
|
|
11
|
+
|
|
12
|
+
postgresql:
|
|
13
|
+
adapter: postgresql
|
|
14
|
+
hostname: localhost
|
|
15
|
+
username: postgres
|
|
16
|
+
password:
|
|
17
|
+
database: has_person_name
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
sqlite3:
|
|
2
|
+
adapter: sqlite3
|
|
3
|
+
database: has_person_name.sqlite3
|
|
4
|
+
|
|
5
|
+
mysql:
|
|
6
|
+
adapter: mysql
|
|
7
|
+
hostname: localhost
|
|
8
|
+
username: root
|
|
9
|
+
password:
|
|
10
|
+
database: has_person_name
|
|
11
|
+
|
|
12
|
+
postgresql:
|
|
13
|
+
adapter: postgresql
|
|
14
|
+
hostname: localhost
|
|
15
|
+
username: postgres
|
|
16
|
+
password:
|
|
17
|
+
database: has_person_name
|
data/spec/models.rb
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
|
2
|
+
|
|
3
|
+
describe "Has Person Name" do
|
|
4
|
+
before(:each) do
|
|
5
|
+
clean_database!
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe "Automatic name assignment" do
|
|
9
|
+
before(:each) do
|
|
10
|
+
clean_database!
|
|
11
|
+
@person = Person.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "should have an accessor for the defined name fields" do
|
|
15
|
+
@person.should respond_to(:name)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "Automatic name assignment" do
|
|
21
|
+
before(:each) do
|
|
22
|
+
clean_database!
|
|
23
|
+
@person = Person.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "should assign name parts to the correct fields" do
|
|
27
|
+
@person.name = "Matthijs Groen"
|
|
28
|
+
@person.name.first_name.should == "Matthijs"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# it "should provide a class method 'taggable?' that is false for untaggable models" do
|
|
34
|
+
# UntaggableModel.should_not be_taggable
|
|
35
|
+
# end
|
|
36
|
+
|
|
37
|
+
# describe "Taggable Method Generation" do
|
|
38
|
+
# before(:each) do
|
|
39
|
+
# clean_database!
|
|
40
|
+
# TaggableModel.write_inheritable_attribute(:tag_types, [])
|
|
41
|
+
# TaggableModel.acts_as_taggable_on(:tags, :languages, :skills, :needs, :offerings)
|
|
42
|
+
# @taggable = TaggableModel.new(:name => "Bob Jones")
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# it "should respond 'true' to taggable?" do
|
|
46
|
+
# @taggable.class.should be_taggable
|
|
47
|
+
# end
|
|
48
|
+
#
|
|
49
|
+
# it "should create a class attribute for tag types" do
|
|
50
|
+
# @taggable.class.should respond_to(:tag_types)
|
|
51
|
+
# end
|
|
52
|
+
#
|
|
53
|
+
# it "should create an instance attribute for tag types" do
|
|
54
|
+
# @taggable.should respond_to(:tag_types)
|
|
55
|
+
# end
|
|
56
|
+
#
|
|
57
|
+
# it "should have all tag types" do
|
|
58
|
+
# @taggable.tag_types.should == [:tags, :languages, :skills, :needs, :offerings]
|
|
59
|
+
# end
|
|
60
|
+
#
|
|
61
|
+
# it "should generate an association for each tag type" do
|
|
62
|
+
# @taggable.should respond_to(:tags, :skills, :languages)
|
|
63
|
+
# end
|
|
64
|
+
#
|
|
65
|
+
# it "should add tagged_with and tag_counts to singleton" do
|
|
66
|
+
# TaggableModel.should respond_to(:tagged_with, :tag_counts)
|
|
67
|
+
# end
|
|
68
|
+
#
|
|
69
|
+
# it "should generate a tag_list accessor/setter for each tag type" do
|
|
70
|
+
# @taggable.should respond_to(:tag_list, :skill_list, :language_list)
|
|
71
|
+
# @taggable.should respond_to(:tag_list=, :skill_list=, :language_list=)
|
|
72
|
+
# end
|
|
73
|
+
#
|
|
74
|
+
# it "should generate a tag_list accessor, that includes owned tags, for each tag type" do
|
|
75
|
+
# @taggable.should respond_to(:all_tags_list, :all_skills_list, :all_languages_list)
|
|
76
|
+
# end
|
|
77
|
+
# end
|
|
78
|
+
|
|
79
|
+
# describe "Single Table Inheritance" do
|
|
80
|
+
# before do
|
|
81
|
+
# @taggable = TaggableModel.new(:name => "taggable")
|
|
82
|
+
# @inherited_same = InheritingTaggableModel.new(:name => "inherited same")
|
|
83
|
+
# @inherited_different = AlteredInheritingTaggableModel.new(:name => "inherited different")
|
|
84
|
+
# end
|
|
85
|
+
#
|
|
86
|
+
# it "should pass on tag contexts to STI-inherited models" do
|
|
87
|
+
# @inherited_same.should respond_to(:tag_list, :skill_list, :language_list)
|
|
88
|
+
# @inherited_different.should respond_to(:tag_list, :skill_list, :language_list)
|
|
89
|
+
# end
|
|
90
|
+
#
|
|
91
|
+
# it "should have tag contexts added in altered STI models" do
|
|
92
|
+
# @inherited_different.should respond_to(:part_list)
|
|
93
|
+
# end
|
|
94
|
+
# end
|
|
95
|
+
|
|
96
|
+
end
|
data/spec/schema.rb
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
ActiveRecord::Schema.define :version => 0 do
|
|
2
|
+
create_table "people", :force => true do |t|
|
|
3
|
+
t.string "name_prefix"
|
|
4
|
+
t.string "name_first_name"
|
|
5
|
+
t.string "name_middle_name"
|
|
6
|
+
t.string "name_intercalation"
|
|
7
|
+
t.string "name_last_name"
|
|
8
|
+
t.string "name_suffix"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
$LOAD_PATH << "." unless $LOAD_PATH.include?(".")
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require "rubygems"
|
|
5
|
+
require "bundler"
|
|
6
|
+
|
|
7
|
+
if Gem::Version.new(Bundler::VERSION) <= Gem::Version.new("0.9.5")
|
|
8
|
+
raise RuntimeError, "Your bundler version is too old." +
|
|
9
|
+
"Run `gem install bundler` to upgrade."
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Set up load paths for all bundled gems
|
|
13
|
+
Bundler.setup
|
|
14
|
+
rescue Bundler::GemNotFound
|
|
15
|
+
raise RuntimeError, "Bundler couldn't find some gems." +
|
|
16
|
+
"Did you run `bundle install`?"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
Bundler.require
|
|
20
|
+
require File.expand_path('../../lib/person_name', __FILE__)
|
|
21
|
+
|
|
22
|
+
unless [].respond_to?(:freq)
|
|
23
|
+
class Array
|
|
24
|
+
def freq
|
|
25
|
+
k=Hash.new(0)
|
|
26
|
+
each {|e| k[e]+=1}
|
|
27
|
+
k
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
ENV['DB'] ||= 'sqlite3'
|
|
33
|
+
|
|
34
|
+
database_yml = File.expand_path('../database.yml', __FILE__)
|
|
35
|
+
if File.exists?(database_yml)
|
|
36
|
+
active_record_configuration = YAML.load_file(database_yml)[ENV['DB']]
|
|
37
|
+
|
|
38
|
+
ActiveRecord::Base.establish_connection(active_record_configuration)
|
|
39
|
+
ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), "debug.log"))
|
|
40
|
+
|
|
41
|
+
ActiveRecord::Base.silence do
|
|
42
|
+
ActiveRecord::Migration.verbose = false
|
|
43
|
+
|
|
44
|
+
load(File.dirname(__FILE__) + '/schema.rb')
|
|
45
|
+
load(File.dirname(__FILE__) + '/models.rb')
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
else
|
|
49
|
+
raise "Please create #{database_yml} first to configure your database. Take a look at: #{database_yml}.sample"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def clean_database!
|
|
53
|
+
models = [Person]
|
|
54
|
+
models.each do |model|
|
|
55
|
+
ActiveRecord::Base.connection.execute "DELETE FROM #{model.table_name}"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
clean_database!
|
metadata
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: person-name
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
hash: 23
|
|
5
|
+
prerelease: false
|
|
6
|
+
segments:
|
|
7
|
+
- 0
|
|
8
|
+
- 2
|
|
9
|
+
- 0
|
|
10
|
+
version: 0.2.0
|
|
11
|
+
platform: ruby
|
|
12
|
+
authors:
|
|
13
|
+
- Matthijs Groen
|
|
14
|
+
autorequire:
|
|
15
|
+
bindir: bin
|
|
16
|
+
cert_chain: []
|
|
17
|
+
|
|
18
|
+
date: 2010-09-24 00:00:00 +02:00
|
|
19
|
+
default_executable:
|
|
20
|
+
dependencies: []
|
|
21
|
+
|
|
22
|
+
description: Manages all person name fields (prefix, first name, middle name, intercalation, last name, suffix)
|
|
23
|
+
email: matthijs.groen@gmail.com
|
|
24
|
+
executables: []
|
|
25
|
+
|
|
26
|
+
extensions: []
|
|
27
|
+
|
|
28
|
+
extra_rdoc_files:
|
|
29
|
+
- README.markdown
|
|
30
|
+
files:
|
|
31
|
+
- Gemfile
|
|
32
|
+
- Gemfile.lock
|
|
33
|
+
- MIT-LICENSE
|
|
34
|
+
- README.markdown
|
|
35
|
+
- Rakefile
|
|
36
|
+
- VERSION
|
|
37
|
+
- lib/person_name.rb
|
|
38
|
+
- lib/person_name/migration_support.rb
|
|
39
|
+
- lib/person_name/name.rb
|
|
40
|
+
- rails/init.rb
|
|
41
|
+
- spec/database.yml
|
|
42
|
+
- spec/database.yml.sample
|
|
43
|
+
- spec/models.rb
|
|
44
|
+
- spec/person_name/has_person_name_spec.rb
|
|
45
|
+
- spec/schema.rb
|
|
46
|
+
- spec/spec_helper.rb
|
|
47
|
+
has_rdoc: true
|
|
48
|
+
homepage: http://github.com/matthijsgroen/person-name
|
|
49
|
+
licenses: []
|
|
50
|
+
|
|
51
|
+
post_install_message:
|
|
52
|
+
rdoc_options:
|
|
53
|
+
- --charset=UTF-8
|
|
54
|
+
require_paths:
|
|
55
|
+
- lib
|
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
hash: 3
|
|
62
|
+
segments:
|
|
63
|
+
- 0
|
|
64
|
+
version: "0"
|
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
|
+
none: false
|
|
67
|
+
requirements:
|
|
68
|
+
- - ">="
|
|
69
|
+
- !ruby/object:Gem::Version
|
|
70
|
+
hash: 3
|
|
71
|
+
segments:
|
|
72
|
+
- 0
|
|
73
|
+
version: "0"
|
|
74
|
+
requirements: []
|
|
75
|
+
|
|
76
|
+
rubyforge_project:
|
|
77
|
+
rubygems_version: 1.3.7
|
|
78
|
+
signing_key:
|
|
79
|
+
specification_version: 3
|
|
80
|
+
summary: Easy editing of person names.
|
|
81
|
+
test_files:
|
|
82
|
+
- spec/person_name/has_person_name_spec.rb
|
|
83
|
+
- spec/spec_helper.rb
|
|
84
|
+
- spec/models.rb
|
|
85
|
+
- spec/schema.rb
|