Module: Utilities::AuthorNames
- Defined in:
- lib/utilities/author_names.rb
Overview
Author name strings: split into surnames, and folded for comparison.
Usage:
Utilities::AuthorNames.surnames('Ritzi, C.M. & J.O. Whitaker, Jr.')
# => ['Ritzi', 'Whitaker']
Utilities::AuthorNames.fold('Creão-Duarte') # => 'creaoduarte'
Utilities::AuthorNames.('(Walker, 1851)')
# => { surnames: ['walker'], year: 1851, parenthesized: true }
Constant Summary collapse
- AUTHOR_SEPARATOR_PATTERN =
/\s*(?:&|;|\band\b|\bund\b|\bet\b)\s*/i- INITIALS_PATTERN =
R,g.,R.,C.M.,F.G.A.M.,J.-P.,J-M.,Y-L,Ch.,KB. /\A(?: [[:alpha:]](?:-[[:upper:]])*\.*| (?:[[:upper:]][[:lower:]]?\.-?)+\.*| [[:upper:]]{2}\. )\z/x- NAME_SUFFIX_PATTERN =
/\A(?:jr|sr|ii|iii|iv)\.?\z/i- YEAR_PATTERN =
/\b(1[5-9]\d{2}|20\d{2})\b/
Class Method Summary collapse
-
.authorship_key(authorship) ⇒ Hash?
The comparison key of a taxon name's authorship string, e.g.
-
.fold(string) ⇒ String
For comparing names: no diacritics, case, spaces, or punctuation.
-
.same_authorship?(a, b, parentheses: false) ⇒ Boolean
False when either key is nil.
- .surname_from_token(token) ⇒ Object private
-
.surnames(author_string) ⇒ Array<String>
Surnames in author order, initials and name suffixes removed.
Class Method Details
.authorship_key(authorship) ⇒ Hash?
The comparison key of a taxon name's authorship string, e.g. TaxonWorks #cached_author_year or CoL's #authorship:
* surnames - folded (.fold), in order
* year - the name's own: a "non Author, year" (homonym) suffix is
dropped first
* parenthesized - sensu ICZN;
nil when either surnames or year can't be found (e.g. "Lam.") - an incomplete key compares with nothing.
58 59 60 61 62 63 64 65 66 67 |
# File 'lib/utilities/author_names.rb', line 58 def self.() s = .to_s.sub(/\s+non\s.*\z/i, '').squish year = s.scan(YEAR_PATTERN).last&.first&.to_i surnames = surnames(s.delete('()').gsub(YEAR_PATTERN, '')) .map { |surname| fold(surname) } .reject(&:empty?) return nil if year.nil? || surnames.empty? { surnames:, year:, parenthesized: s.start_with?('(') } end |
.fold(string) ⇒ String
Returns for comparing names: no diacritics, case, spaces, or punctuation.
39 40 41 |
# File 'lib/utilities/author_names.rb', line 39 def self.fold(string) I18n.transliterate(string.to_s).downcase.gsub(/[^a-z]/, '') end |
.same_authorship?(a, b, parentheses: false) ⇒ Boolean
Returns false when either key is nil.
73 74 75 76 77 78 |
# File 'lib/utilities/author_names.rb', line 73 def self.(a, b, parentheses: false) return false if a.nil? || b.nil? a[:surnames] == b[:surnames] && a[:year] == b[:year] && (!parentheses || a[:parenthesized] == b[:parenthesized]) end |
.surname_from_token(token) ⇒ Object (private)
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/utilities/author_names.rb', line 80 def self.surname_from_token(token) words = token .sub(/\A[^[:alpha:]]+/, '') # remove leading junk # The second pattern here matches the position between '.' and any letter, # like 'KB.Agwanda' (uncommon). .split(/\s+|(?<=\.)(?=[[:alpha:]])/) .map(&:strip) .reject { |w| !w.match?(/[[:alpha:]]/) || w.match?(INITIALS_PATTERN) || w.match?(NAME_SUFFIX_PATTERN) } name = words.join(' ').sub(/[.\s]+\z/, '') name.presence end |
.surnames(author_string) ⇒ Array<String>
Returns surnames in author order, initials and name suffixes removed.
25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/utilities/author_names.rb', line 25 def self.surnames() s = .to_s .gsub(/<[^>]*>/, ' ') # remove <...> .gsub(/\([^)]*\)/, ' ') # remove (...) .gsub(/\bet\.?\s*al\b\.?/i, ' ') # remove 'et al' .gsub(%r{/\s*\d{4}\b}, ' ') # remove years s.split(AUTHOR_SEPARATOR_PATTERN).flat_map { |chunk| chunk.split(',').filter_map { |token| surname_from_token(token) } } end |