Module: Iriq::Inflector::BuiltinAdapter

Defined in:
lib/iriq/inflector.rb

Overview

Rule-based English singularizer. Rules are ordered most-specific-first and adapted from ActiveSupport’s default inflections.

Constant Summary collapse

IRREGULARS =
{
  "people"   => "person",
  "children" => "child",
  "men"      => "man",
  "women"    => "woman",
  "mice"     => "mouse",
  "geese"    => "goose",
  "oxen"     => "ox",
  "feet"     => "foot",
  "teeth"    => "tooth",
  "lives"    => "life",
  "wives"    => "wife",
  "moves"    => "move",
  "zombies"  => "zombie",
  # latin/greek plurals that don't fit a clean suffix rule
  "indices"  => "index",
  "vertices" => "vertex",
  # -f/-fe words where the stem doesn't end in l/r/i
  "leaves"   => "leaf",
  "calves"   => "calf",
  "halves"   => "half",
  "loaves"   => "loaf",
  "hooves"   => "hoof",
}.freeze
UNCOUNTABLE =
Set.new(%w[
  news fish sheep deer series species equipment information
  money rice jeans police data media
]).freeze
RULES =
pattern, replacement

— first match wins.

[
  [/(quiz)zes$/i,                       '\1'],
  [/(matri|appendi)ces$/i,              '\1x'],
  [/(ox)en$/i,                          '\1'],
  [/(alias|status)(es)?$/i,             '\1'],
  [/(octop|vir)(us|i)$/i,               '\1us'],
  [/(cris|ax|test)es$/i,                '\1is'],
  [/(shoe)s$/i,                         '\1'],
  [/(bus)(es)?$/i,                      '\1'],
  [/([ml])ice$/i,                       '\1ouse'],
  [/(x|ch|ss|sh)es$/i,                  '\1'],
  [/(m)ovies$/i,                        '\1ovie'],
  [/(s)eries$/i,                        '\1eries'],
  [/([^aeiouy]|qu)ies$/i,               '\1y'],
  [/([lr])ves$/i,                       '\1f'],
  [/(tive)s$/i,                         '\1'],
  [/(hive)s$/i,                         '\1'],
  [/([^f])ves$/i,                       '\1fe'],
  [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '\1sis'],
  [/([ti])a$/i,                         '\1um'],
  [/(n)ews$/i,                          '\1ews'],
  [/(o)es$/i,                           '\1'],
  [/(ss)$/i,                            '\1'],
  [/s$/i,                               ''],
].freeze

Class Method Summary collapse

Class Method Details

.preserve_case(original, lowered) ⇒ Object



134
135
136
137
138
139
140
141
142
# File 'lib/iriq/inflector.rb', line 134

def self.preserve_case(original, lowered)
  if original == original.upcase
    lowered.upcase
  elsif original[0] == original[0].upcase
    lowered.sub(/\A./, &:upcase)
  else
    lowered
  end
end

.singularize(word) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/iriq/inflector.rb', line 115

def self.singularize(word)
  return word if word.nil? || word.empty?

  lower = word.downcase
  return word if UNCOUNTABLE.include?(lower)

  if (irr = IRREGULARS[lower])
    return preserve_case(word, irr)
  end

  RULES.each do |pattern, replacement|
    if word.match?(pattern)
      return word.sub(pattern, replacement)
    end
  end

  word
end