person-name 0.2.2 → 0.2.3

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/README.markdown CHANGED
@@ -7,6 +7,12 @@ If you have to fill in a name for somebody, you have to display all those fields
7
7
  The goal is to make one field that can split up the name and assign it to the correct fields automatically.
8
8
  You can also still use the more precise input if necessary.
9
9
 
10
+ Installation
11
+ ============
12
+ in your Gemfile:
13
+
14
+ gem "person-name"
15
+
10
16
  Usage
11
17
  =====
12
18
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.2
1
+ 0.2.3
data/lib/person-name.rb CHANGED
@@ -2,9 +2,10 @@ require "active_record"
2
2
 
3
3
  $LOAD_PATH.unshift(File.dirname(__FILE__))
4
4
 
5
+ require "person_name/name_splitter"
5
6
  require "person_name/name"
6
- require "person_name/migration_support"
7
7
  require "person_name/has_person_name"
8
+ require "person_name/migration_support"
8
9
 
9
10
  $LOAD_PATH.shift
10
11
 
@@ -1,51 +1,51 @@
1
1
  module PersonName
2
2
 
3
- module ActiveRecord
3
+ module ActiveRecord
4
4
 
5
- def self.included(base) # :nodoc:
6
- base.extend ClassMethods
5
+ def self.included(base) # :nodoc:
6
+ base.extend ClassMethods
7
7
  end
8
8
 
9
- module ClassMethods
9
+ module ClassMethods
10
10
 
11
- def has_person_names?
12
- false
13
- end
11
+ def has_person_names?
12
+ false
13
+ end
14
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?
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
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)
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
24
 
25
- class_eval do
26
- def self.has_person_names?
27
- true
28
- end
25
+ class_eval do
26
+ def self.has_person_names?
27
+ true
28
+ end
29
29
 
30
- include PersonName::ActiveRecord::Core
31
- end
32
- end
33
- end
30
+ include PersonName::ActiveRecord::Core
31
+ end
32
+ end
33
+ end
34
34
 
35
- end
35
+ end
36
36
 
37
- module Core
37
+ module Core
38
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
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
44
 
45
- module ClassMethods
46
- def initialize_person_names
47
- name_types.map(&:to_s).each do |name_type|
48
- class_eval %(
45
+ module ClassMethods
46
+ def initialize_person_names
47
+ name_types.map(&:to_s).each do |name_type|
48
+ class_eval %(
49
49
  def #{name_type}
50
50
  person_name_for('#{name_type}')
51
51
  end
@@ -54,25 +54,25 @@ module PersonName
54
54
  set_person_name_for('#{name_type}', new_name)
55
55
  end
56
56
  )
57
- end
58
- end
59
- end
57
+ end
58
+ end
59
+ end
60
60
 
61
- module InstanceMethods
61
+ module InstanceMethods
62
62
 
63
- def person_name_for field
64
- @person_names ||= {}
65
- @person_names[field] ||= PersonName::Name.new(field, self)
66
- end
63
+ def person_name_for field
64
+ @person_names ||= {}
65
+ @person_names[field] ||= PersonName::ActiveRecordPersonName.new(field, self)
66
+ end
67
67
 
68
- def set_person_name_for field, new_name
69
- person_name_for(field).full_name = new_name
70
- end
68
+ def set_person_name_for field, new_name
69
+ person_name_for(field).full_name = new_name
70
+ end
71
71
 
72
- end
72
+ end
73
73
 
74
- end
74
+ end
75
75
 
76
- end
76
+ end
77
77
 
78
78
  end
@@ -1,12 +1,16 @@
1
1
 
2
2
  module PersonName::MigrationSupport
3
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
4
+ def person_name(name, *args)
5
+ self.add_name_columns(self, name, *args)
6
+ end
7
+
8
+ def self.add_name_columns(table, prefix, *args)
9
+ options = args.extract_options!
10
+ name_parts = PersonName::NameSplitter::NAME_PARTS
11
+ name_parts.each do |part|
12
+ table.column("#{prefix}_#{part}".to_sym, :string, :null => true)
13
+ end
14
+ end
11
15
 
12
16
  end
@@ -1,7 +1,5 @@
1
1
  module PersonName
2
- class Name
3
-
4
- NAME_PARTS = %w(prefix first_name middle_name intercalation last_name suffix)
2
+ class ActiveRecordPersonName
5
3
 
6
4
  def initialize(naming_prefix, record)
7
5
  @naming_prefix = naming_prefix
@@ -9,101 +7,17 @@ module PersonName
9
7
  end
10
8
 
11
9
  def full_name
12
- NAME_PARTS.collect { |p| self.send(p) }.compact.join " "
10
+ NameSplitter::NAME_PARTS.collect { |p| self.send(p) }.compact.join " "
13
11
  end
14
12
 
15
13
  def full_name= new_name
16
14
  return if full_name == new_name # no changes
15
+ old_values = {}
16
+ NameSplitter::NAME_PARTS.collect { |p| old_values[p.to_sym] = self.send(p) }
17
+ new_name = NameSplitter.split(new_name, old_values)
17
18
 
18
- parts = new_name.split " "
19
- names = []
20
- stage = :prefix
21
- remember = nil
22
- parts.each_with_index do |part, index|
23
- is_upcase = (part[0,1] == part[0,1].upcase)
24
- has_dash = part.include? "-"
25
- is_last = (parts.length - 1) == index
26
-
27
- fp = [remember, part].compact.join(" ")
28
- remember = nil
29
- did_remember = (fp != part)
30
- if valid_prefix?(part) and stage == :prefix # if the part is a valid prefix, mark it as such
31
- names = add_to_last_if :prefix, fp, names
32
- elsif valid_suffix?(part) and stage == :name # if the part is a valid suffix, mark it as such
33
- names = add_to_last_if :suffix, fp, names
34
- elsif part == "-" # if the part is a dash
35
- if last_stored = names.pop # retrieve the previous name part (if any) and store it with the dash
36
- # for the part to come (remember)
37
- remember = [last_stored[0], fp].compact.join(" ")
38
- else
39
- # if there is no previous part, just store the current part for later
40
- remember = fp
41
- end
42
- elsif !is_upcase and !did_remember # intercalation words are never with a capital
43
- names = add_to_last_if :intercalation, fp, names
44
- stage = :name
45
- elsif !is_upcase and did_remember
46
- remember = fp
47
- elsif is_upcase and !has_dash
48
- names << [fp, :name]
49
- stage = :name
50
- elsif is_upcase and has_dash
51
- if fp.ends_with? "-"
52
- if is_last
53
- names << [fp, :name]
54
- stage = :name
55
- else
56
- remember = fp
57
- end
58
- else
59
- if fp.starts_with?("-") and last_stored = names.pop
60
- fp = [last_stored[0], fp].compact.join(" ")
61
- end
62
- dash_parts = fp.split "-"
63
- if dash_parts.last.first == dash_parts.last.first.upcase
64
- names << [fp, :name]
65
- stage = :name
66
- elsif is_last
67
- names << [fp, :name]
68
- stage = :name
69
- else
70
- remember = fp
71
- end
72
- end
73
- end
74
- end
75
-
76
- new_name = {}
77
- stage = O[:prefix]
78
-
79
- names.each_with_index do |value, index|
80
- name, name_type = *value
81
- stage = recheck_stage(name, stage)
82
-
83
- if name_type == :prefix and stage == O[:prefix]
84
- elsif name_type == :suffix and (index == names.length - 1)
85
- stage = [O[:suffix], stage].max
86
- elsif name_type == :suffix and (index != names.length - 1)
87
- name_type = :name
88
- end
89
-
90
- if name_type == :name
91
- if (index == names.length - 1) or new_name[:intercalation]
92
- stage = [O[:last_name], stage].max
93
- else
94
- if !new_name[:first_name]
95
- stage = [O[:first_name], stage].max
96
- else
97
- stage = [O[:middle_name], stage].max
98
- end
99
- end
100
- elsif name_type == :intercalation
101
- stage = [O[:intercalation], stage].max
102
- end
103
- new_name = add_part(new_name, stage, name)
104
- end
105
19
  # assignments
106
- NAME_PARTS.each do |part|
20
+ NameSplitter::NAME_PARTS.each do |part|
107
21
  self.send "#{part}=", (new_name[part.to_sym] || "").blank? ? nil : new_name[part.to_sym]
108
22
  end
109
23
  end
@@ -114,17 +28,17 @@ module PersonName
114
28
 
115
29
  def short_name include_middle_names = true
116
30
  parts = []
117
- parts << "#{self.first_name.first.upcase}." if self.first_name
31
+ parts << "#{self.first_name[0,1].upcase}." if self.first_name
118
32
  if include_middle_names and self.middle_name
119
33
  names = self.middle_name.split(" ")
120
34
  names.each do |name|
121
- parts << "#{name.first.upcase}."
35
+ parts << "#{name[0,1].upcase}."
122
36
  end
123
37
  end
124
38
  [parts.join, full_last_name] * " "
125
39
  end
126
40
 
127
- NAME_PARTS.each do |part|
41
+ NameSplitter::NAME_PARTS.each do |part|
128
42
  define_method part do
129
43
  @record.send("#{@naming_prefix}_#{part}")
130
44
  end
@@ -140,57 +54,6 @@ module PersonName
140
54
 
141
55
  private
142
56
 
143
- O = {
144
- :prefix => 0,
145
- :first_name => 1,
146
- :middle_name => 2,
147
- :intercalation => 3,
148
- :last_name => 4,
149
- :suffix => 5
150
- }.freeze
151
- OR = O.invert
152
-
153
- def add_part new_name, part_score, part
154
- part_name = OR[part_score]
155
- new_name[part_name.to_sym] = [new_name[part_name.to_sym], part].compact.join(" ")
156
- new_name
157
- end
158
-
159
- def recheck_stage value, stage
160
- # test if the given value is already stored in the name right now
161
- new_stage = stage
162
- NAME_PARTS.each do |part|
163
- part_values = (self.send(part) || "").split(" ")
164
-
165
- part_score = O[part.to_sym]
166
- if part_values.include? value
167
- part_score = O[:first_name] if stage == O[:prefix] and part = :middle_name
168
- new_stage = part_score if part_score > new_stage
169
- return new_stage
170
- end
171
- end
172
- stage
173
- end
174
-
175
- def add_to_last_if part, value, list
176
- if list.last and list.last[1] == part
177
- last_part = list.pop
178
- list << [[last_part[0], value].compact.join(" "), part]
179
- else
180
- list << [value, part]
181
- end
182
- list
183
- end
184
-
185
57
  attr_reader :naming_prefix, :record
186
-
187
- def valid_prefix? name_part
188
- false
189
- end
190
-
191
- def valid_suffix? name_part
192
- false
193
- end
194
-
195
58
  end
196
- end
59
+ end
@@ -0,0 +1,150 @@
1
+ module PersonName
2
+ class NameSplitter
3
+
4
+ NAME_PARTS = %w(prefix first_name middle_name intercalation last_name suffix)
5
+
6
+ def self.split(new_name_str, existing_values = {})
7
+ parts = new_name_str.split " "
8
+ names = []
9
+ stage = :prefix
10
+ remember = nil
11
+ parts.each_with_index do |part, index|
12
+ is_upcase = (part[0,1] == part[0,1].upcase)
13
+ has_dash = part.include? "-"
14
+ is_last = (parts.length - 1) == index
15
+
16
+ fp = [remember, part].compact.join(" ")
17
+ remember = nil
18
+ did_remember = (fp != part)
19
+ if valid_prefix?(part) and stage == :prefix # if the part is a valid prefix, mark it as such
20
+ names = add_to_last_if :prefix, fp, names
21
+ elsif valid_suffix?(part) and stage == :name # if the part is a valid suffix, mark it as such
22
+ names = add_to_last_if :suffix, fp, names
23
+ elsif part == "-" # if the part is a dash
24
+ if last_stored = names.pop # retrieve the previous name part (if any) and store it with the dash
25
+ # for the part to come (remember)
26
+ remember = [last_stored[0], fp].compact.join(" ")
27
+ else
28
+ # if there is no previous part, just store the current part for later
29
+ remember = fp
30
+ end
31
+ elsif !is_upcase and !did_remember # intercalation words are never with a capital
32
+ names = add_to_last_if :intercalation, fp, names
33
+ stage = :name
34
+ elsif !is_upcase and did_remember
35
+ remember = fp
36
+ elsif is_upcase and !has_dash
37
+ names << [fp, :name]
38
+ stage = :name
39
+ elsif is_upcase and has_dash
40
+ if fp.ends_with? "-"
41
+ if is_last
42
+ names << [fp, :name]
43
+ stage = :name
44
+ else
45
+ remember = fp
46
+ end
47
+ else
48
+ if fp.starts_with?("-") and last_stored = names.pop
49
+ fp = [last_stored[0], fp].compact.join(" ")
50
+ end
51
+ dash_parts = fp.split "-"
52
+ if dash_parts.last.first == dash_parts.last.first.upcase
53
+ names << [fp, :name]
54
+ stage = :name
55
+ elsif is_last
56
+ names << [fp, :name]
57
+ stage = :name
58
+ else
59
+ remember = fp
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ new_name = {}
66
+ stage = O[:prefix]
67
+
68
+ names.each_with_index do |value, index|
69
+ name, name_type = *value
70
+ stage = recheck_stage(name, stage, existing_values)
71
+
72
+ if name_type == :prefix and stage == O[:prefix]
73
+ elsif name_type == :suffix and (index == names.length - 1)
74
+ stage = [O[:suffix], stage].max
75
+ elsif name_type == :suffix and (index != names.length - 1)
76
+ name_type = :name
77
+ end
78
+
79
+ if name_type == :name
80
+ if (index == names.length - 1) or new_name[:intercalation]
81
+ stage = [O[:last_name], stage].max
82
+ else
83
+ if !new_name[:first_name]
84
+ stage = [O[:first_name], stage].max
85
+ else
86
+ stage = [O[:middle_name], stage].max
87
+ end
88
+ end
89
+ elsif name_type == :intercalation
90
+ stage = [O[:intercalation], stage].max
91
+ end
92
+ new_name = add_part(new_name, stage, name)
93
+ end
94
+ new_name
95
+ end
96
+
97
+ private
98
+
99
+ O = {
100
+ :prefix => 0,
101
+ :first_name => 1,
102
+ :middle_name => 2,
103
+ :intercalation => 3,
104
+ :last_name => 4,
105
+ :suffix => 5
106
+ }.freeze
107
+ OR = O.invert
108
+
109
+ def self.add_part new_name, part_score, part
110
+ part_name = OR[part_score]
111
+ new_name[part_name.to_sym] = [new_name[part_name.to_sym], part].compact.join(" ")
112
+ new_name
113
+ end
114
+
115
+ def self.recheck_stage value, stage, old_values
116
+ # test if the given value is already stored in the name right now
117
+ new_stage = stage
118
+ NAME_PARTS.each do |part|
119
+ part_values = (old_values[part.to_sym] || "").split(" ")
120
+
121
+ part_score = O[part.to_sym]
122
+ if part_values.include? value
123
+ part_score = O[:first_name] if stage == O[:prefix] and part = :middle_name
124
+ new_stage = part_score if part_score > new_stage
125
+ return new_stage
126
+ end
127
+ end
128
+ stage
129
+ end
130
+
131
+ def self.add_to_last_if part, value, list
132
+ if list.last and list.last[1] == part
133
+ last_part = list.pop
134
+ list << [[last_part[0], value].compact.join(" "), part]
135
+ else
136
+ list << [value, part]
137
+ end
138
+ list
139
+ end
140
+
141
+ def self.valid_prefix? name_part
142
+ false
143
+ end
144
+
145
+ def self.valid_suffix? name_part
146
+ false
147
+ end
148
+
149
+ end
150
+ end
data/spec/models.rb CHANGED
@@ -2,3 +2,10 @@ class Person < ActiveRecord::Base
2
2
  has_person_name
3
3
  end
4
4
 
5
+ class PersonWithoutName < ActiveRecord::Base
6
+ end
7
+
8
+ class NamePerson < ActiveRecord::Base
9
+ has_person_name
10
+ has_person_name :birth_name
11
+ end
@@ -5,6 +5,18 @@ describe "Has Person Name" do
5
5
  clean_database!
6
6
  end
7
7
 
8
+ describe "Some model without names" do
9
+ it "should not have person names" do
10
+ PersonWithoutName.should_not have_person_names
11
+ end
12
+ end
13
+
14
+ describe "Some model with names" do
15
+ it "should have person names" do
16
+ Person.should have_person_names
17
+ end
18
+ end
19
+
8
20
  describe "Automatic name assignment" do
9
21
  before(:each) do
10
22
  clean_database!
@@ -33,6 +45,17 @@ describe "Has Person Name" do
33
45
  @person.name_last_name.should == "Groen"
34
46
  end
35
47
 
48
+ it "should be able to show a short name" do
49
+ @person.name = "Matthijs Jacobus Groen"
50
+ @person.name.short_name.should == "M.J. Groen"
51
+ @person.name.short_name(false).should == "M. Groen"
52
+ end
53
+
54
+ it "should be able to show a full last name" do
55
+ @person.name = "Frans van der Sluis"
56
+ @person.name.full_last_name.should == "van der Sluis"
57
+ end
58
+
36
59
  it "should split up name parts and assign to correct fields" do
37
60
  test_fields = %w(prefix first_name middle_name intercalation last_name suffix)
38
61
  test_cases = [
@@ -40,6 +63,9 @@ describe "Has Person Name" do
40
63
  [nil, "Matthijs", "Jacobus", nil, "Groen", nil],
41
64
  [nil, "Frans", nil, "van der", "Sluis", nil],
42
65
  [nil, "Maria", "Cornelia Hendrina", nil, "Damen-van Valenberg", nil],
66
+ [nil, "Maria", "Cornelia Hendrina", nil, "Damen - van Valenberg", nil],
67
+ [nil, "Maria", "Cornelia Hendrina", nil, "Damen- van Valenberg", nil],
68
+ [nil, "Maria", "Cornelia Hendrina", nil, "Damen -van Valenberg", nil],
43
69
  [nil, "Dirk", "Jan", "van de", "Abeele", nil],
44
70
  [nil, "Yolanthe", "Cabau", "van", "Kasbergen", nil],
45
71
  ]
data/spec/schema.rb CHANGED
@@ -1,11 +1,16 @@
1
1
  ActiveRecord::Schema.define :version => 0 do
2
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"
3
+ PersonName::MigrationSupport.add_name_columns(t, :name)
4
+ end
5
+
6
+ create_table "person_without_names", :force => true do |t|
7
+ t.boolean :female
8
+ end
9
+
10
+ create_table "name_people", :force => true do |t|
11
+ PersonName::MigrationSupport.add_name_columns(t, :name)
12
+ PersonName::MigrationSupport.add_name_columns(t, :birth_name)
13
+ t.boolean :female
9
14
  end
10
15
 
11
16
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: person-name
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 17
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 2
10
- version: 0.2.2
9
+ - 3
10
+ version: 0.2.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matthijs Groen
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-09-25 00:00:00 +02:00
18
+ date: 2010-09-27 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -38,6 +38,7 @@ files:
38
38
  - lib/person_name/has_person_name.rb
39
39
  - lib/person_name/migration_support.rb
40
40
  - lib/person_name/name.rb
41
+ - lib/person_name/name_splitter.rb
41
42
  - rails/init.rb
42
43
  - spec/database.yml
43
44
  - spec/database.yml.sample