person-name 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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