diff --git a/app/helpers/contact_helper.rb b/app/helpers/contact_helper.rb new file mode 100644 index 000000000..2bd86937f --- /dev/null +++ b/app/helpers/contact_helper.rb @@ -0,0 +1,83 @@ +module ContactHelper + def parse_name(full_name) + # If the input is nil or not a string, return a hash with all values set to nil + return default_name_hash if invalid_name?(full_name) + + # If the input is a number, return a hash with the number as the first name + return numeric_name_hash(full_name) if valid_number?(full_name) + + full_name = full_name.squish + + # If full name consists of only one word, consider it as the first name + return single_word_name_hash(full_name) if single_word?(full_name) + + parts = split_name(full_name) + parts = handle_conjunction(parts) + build_name_hash(parts) + end + + private + + def default_name_hash + { first_name: nil, last_name: nil, middle_name: nil, prefix: nil, suffix: nil } + end + + def invalid_name?(full_name) + !full_name.is_a?(String) || full_name.empty? + end + + def numeric_name_hash(full_name) + { first_name: full_name, last_name: nil, middle_name: nil, prefix: nil, suffix: nil } + end + + def valid_number?(full_name) + full_name.gsub(/\s+/, '').match?(/\A\+?\d+\z/) + end + + def single_word_name_hash(full_name) + { first_name: full_name, last_name: nil, middle_name: nil, prefix: nil, suffix: nil } + end + + def single_word?(full_name) + full_name.split.size == 1 + end + + def split_name(full_name) + full_name.split + end + + def handle_conjunction(parts) + conjunctions = ['and', '&'] + parts.each_index do |i| + next unless conjunctions.include?(parts[i]) && i.positive? + + parts[i - 1] = [parts[i - 1], parts[i + 1]].join(' ') + parts.delete_at(i) + parts.delete_at(i) + end + parts + end + + def build_name_hash(parts) + suffix = parts.pop if parts.last.match?(/(\w+\.|[IVXLM]+|[A-Z]+)$/) + last_name = parts.pop + prefix = parts.shift if parts.first.match?(/^\w+\./) + first_name = parts.shift + middle_name = parts.join(' ') + + hash = { + first_name: first_name, + last_name: last_name, + prefix: prefix, + middle_name: middle_name, + suffix: suffix + } + + # Reverse name if "," was used in Last, First notation. + if hash[:first_name] =~ /,$/ + hash[:first_name] = hash[:last_name] + hash[:last_name] = Regexp.last_match.pre_match + end + hash + end +end diff --git a/spec/helpers/contact_helper_spec.rb b/spec/helpers/contact_helper_spec.rb new file mode 100644 index 000000000..41953fb8d --- /dev/null +++ b/spec/helpers/contact_helper_spec.rb @@ -0,0 +1,107 @@ +require 'rails_helper' + +RSpec.describe ContactHelper do + describe '#parse_name' do + it 'correctly splits a full name into first and last name' do + full_name = 'John Doe Smith' + expected_result = { first_name: 'John', last_name: 'Smith', middle_name: 'Doe', prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'handles single-word names correctly' do + full_name = 'Cher' + expected_result = { first_name: 'Cher', last_name: nil, middle_name: nil, prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'handles an empty string correctly' do + full_name = '' + expected_result = { first_name: nil, last_name: nil, middle_name: nil, prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'handles multiple consecutive spaces correctly' do + full_name = 'John Doe Smith' + expected_result = { last_name: 'Smith', first_name: 'John', middle_name: 'Doe', prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'returns nil for first and last name when input is nil' do + full_name = nil + expected_result = { first_name: nil, last_name: nil, middle_name: nil, prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'handles names with special characters correctly' do + full_name = 'John Doe-Smith' + expected_result = { first_name: 'John', last_name: 'Doe-Smith', middle_name: '', prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'handles non-Latin script names correctly' do + full_name = '李 小龙' + expected_result = { first_name: '李', last_name: '小龙', middle_name: '', prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'handle name with trailing spaces correctly' do + full_name = 'John Doe Smith ' + expected_result = { first_name: 'John', last_name: 'Smith', middle_name: 'Doe', prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'handle name with leading spaces correctly' do + full_name = ' John Doe Smith' + expected_result = { first_name: 'John', last_name: 'Smith', middle_name: 'Doe', prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'handle name with phone number correctly' do + full_name = '+1234567890' + expected_result = { first_name: '+1234567890', last_name: nil, middle_name: nil, prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'handle name with mobile number with spaces correctly' do + full_name = '+1 234 567 890' + expected_result = { first_name: '+1 234 567 890', last_name: nil, middle_name: nil, prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'correctly splits a full name with middle name' do + full_name = 'John Quincy Adams' + expected_result = { first_name: 'John', last_name: 'Adams', middle_name: 'Quincy', prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'handles names with multiple spaces between first and last name' do + full_name = 'John Quincy Adams' + expected_result = { first_name: 'John', last_name: 'Adams', middle_name: 'Quincy', prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'handles names with leading and trailing whitespaces' do + full_name = ' John Quincy Adams ' + expected_result = { first_name: 'John', last_name: 'Adams', middle_name: 'Quincy', prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'handles names with leading and trailing whitespaces and a middle initial' do + full_name = ' John Q. Adams ' + expected_result = { first_name: 'John', last_name: 'Adams', middle_name: 'Q.', prefix: nil, suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'handles names with a prefix' do + full_name = 'Mr. John Doe' + expected_result = { first_name: 'John', last_name: 'Doe', middle_name: '', prefix: 'Mr.', suffix: nil } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + + it 'handles names with a suffix' do + full_name = 'John Doe Jr.' + expected_result = { first_name: 'John', last_name: 'Doe', middle_name: '', prefix: nil, suffix: 'Jr.' } + expect(helper.parse_name(full_name)).to eq(expected_result) + end + end +end