Module: Bible270::Names

Defined in:
lib/bible270/names.rb

Overview

Readers are known to each other by name beside their reflections, so a first and last name are both required wherever a name is set: at email sign-in, when a reader edits their own, and when an admin edits someone else's.

Kept free of Rails so the rules can be tested on their own.

Class Method Summary collapse

Class Method Details

.first_with_last_initial(first, last) ⇒ Object

"Andrew vonderLuft" -> "Andrew v." Particles are kept out of the initial: "von der Luft" gives "L.", not "v.", since the last word is the one people are known by.



39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/bible270/names.rb', line 39

def first_with_last_initial(first, last)
  first_name = squish(first)
  surname    = squish(last)
  return first_name if surname.empty?

  initial = surname.split.last[0]
  return first_name if initial.nil?

  # Not upcased: a lowercase surname is usually deliberate (vonderLuft), and
  # forcing "V." would override how someone writes their own name.
  "#{first_name} #{initial}.".strip
end

.normalize(first, last) ⇒ Object

A first and last name, or nil when either is missing. Returns the pieces plus the display name built from them, so every caller derives it the same way rather than assembling it locally.



21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/bible270/names.rb', line 21

def normalize(first, last)
  first_name = squish(first)
  last_name  = squish(last)
  return nil if first_name.empty? || last_name.empty?

  # Only persisted columns belong here — this hash is assigned straight onto
  # the model. Anything derived (see first_with_last_initial) is computed on
  # demand, so it can't go stale when a name is edited.
  {
    first_name: first_name,
    last_name: last_name,
    display_name: "#{first_name} #{last_name}"
  }
end

.split_display_name(display_name) ⇒ Object

Best effort at splitting a single name, for readers who arrived through OmniAuth with only a display name. Everything after the first word is the surname, so "Andrew von der Luft" keeps its particles together.

Deliberately not called split: a module method with the same name as String#split invites a bare split(...) inside this module to resolve here instead, and RuboCop's Style/StringChars autocorrect has been known to rewrite split calls into a receiverless chars, which then resolves against the module and fails confusingly.



65
66
67
68
69
70
# File 'lib/bible270/names.rb', line 65

def split_display_name(display_name)
  parts = squish(display_name).split
  return nil if parts.size < 2

  { first_name: parts.first, last_name: parts[1..].join(' ') }
end

.squish(value) ⇒ Object

Collapse runs of whitespace, including the non-breaking space that arrives from copy-paste, and trim.



14
15
16
# File 'lib/bible270/names.rb', line 14

def squish(value)
  value.to_s.tr("\u00A0", ' ').gsub(%r{\s+}, ' ').strip
end

.valid?(first, last) ⇒ Boolean

Returns:

  • (Boolean)


52
53
54
# File 'lib/bible270/names.rb', line 52

def valid?(first, last)
  !normalize(first, last).nil?
end