diff --git a/lib/inflex/pluralize.ex b/lib/inflex/pluralize.ex index f3b981d..e3b540f 100644 --- a/lib/inflex/pluralize.ex +++ b/lib/inflex/pluralize.ex @@ -1,6 +1,5 @@ defmodule Inflex.Pluralize do @moduledoc false - @default true @uncountable [ "aircraft", @@ -31,161 +30,179 @@ defmodule Inflex.Pluralize do ] @irregular [ - {~r/(alumn|cact|fung|radi|stimul|syllab)i/i, "\\1us"}, - {~r/(alg|antenn|amoeb|larv|vertebr)ae/i, "\\1a"}, - {~r/^(gen)era$/i, "\\1us"}, - {~r/(pe)ople/i, "\\1rson"}, - {~r/^(zombie)s$/i, "\\1"}, - {~r/(g)eese/i, "\\1oose"}, - {~r/(criteri)a/i, "\\1on"}, - {~r/^(m)en$/i, "\\1an"}, - {~r/^(echo)es/i, "\\1"}, - {~r/^(hero)es/i, "\\1"}, - {~r/^(potato)es/i, "\\1"}, - {~r/^(tomato)es/i, "\\1"}, - {~r/^(t)eeth/i, "\\1ooth"}, - {~r/^(l)ice$/i, "\\1ouse"}, - {~r/^(addend|bacteri|curricul|dat|memorand|quant)a$/i, "\\1um"}, - {~r/^(di)ce/i, "\\1e"}, - {~r/^(f)eet/i, "\\1oot"}, - {~r/^(phenomen)a/i, "\\1on"} + {~s/(alumn|cact|fung|radi|stimul|syllab)i/, "i", "\\1us"}, + {~s/(alg|antenn|amoeb|larv|vertebr)ae/, "i", "\\1a"}, + {~s/^(gen)era$/, "i", "\\1us"}, + {~s/(pe)ople/, "i", "\\1rson"}, + {~s/^(zombie)s$/, "i", "\\1"}, + {~s/(g)eese/, "i", "\\1oose"}, + {~s/(criteri)a/, "i", "\\1on"}, + {~s/^(m)en$/, "i", "\\1an"}, + {~s/^(echo)es/, "i", "\\1"}, + {~s/^(hero)es/, "i", "\\1"}, + {~s/^(potato)es/, "i", "\\1"}, + {~s/^(tomato)es/, "i", "\\1"}, + {~s/^(t)eeth/, "i", "\\1ooth"}, + {~s/^(l)ice$/, "i", "\\1ouse"}, + {~s/^(addend|bacteri|curricul|dat|memorand|quant)a$/, "i", "\\1um"}, + {~s/^(di)ce/, "i", "\\1e"}, + {~s/^(f)eet/, "i", "\\1oot"}, + {~s/^(phenomen)a/, "i", "\\1on"} ] @plural_irregular [ - {~r/(alumn|cact|fung|radi|stimul|syllab)us/i, "\\1i"}, - {~r/(alg|antenn|amoeb|larv|vertebr)a/i, "\\1ae"}, - {~r/^(gen)us$/i, "\\1era"}, - {~r/(pe)rson$/i, "\\1ople"}, - {~r/^(zombie)s$/i, "\\1"}, - {~r/(g)oose$/i, "\\1eese"}, - {~r/(criteri)on/i, "\\1a"}, - {~r/^(men)$/i, "\\1"}, - {~r/^(women)/i, "\\1"}, - {~r/^(echo)$/i, "\\1es"}, - {~r/^(hero)$/i, "\\1es"}, - {~r/^(potato)/i, "\\1es"}, - {~r/^(tomato)/i, "\\1es"}, - {~r/^(t)ooth$/i, "\\1eeth"}, - {~r/^(l)ouse$/i, "\\1ice"}, - {~r/^(addend|bacteri|curricul|dat|memorand|quant)um$/i, "\\1a"}, - {~r/^(di)e$/i, "\\1ce"}, - {~r/^(f)oot$/i, "\\1eet"}, - {~r/^(phenomen)on/i, "\\1a"} + {~s/(alumn|cact|fung|radi|stimul|syllab)us/, "i", "\\1i"}, + {~s/(alg|antenn|amoeb|larv|vertebr)a/, "i", "\\1ae"}, + {~s/^(gen)us$/, "i", "\\1era"}, + {~s/(pe)rson$/, "i", "\\1ople"}, + {~s/^(zombie)s$/, "i", "\\1"}, + {~s/(g)oose$/, "i", "\\1eese"}, + {~s/(criteri)on/, "i", "\\1a"}, + {~s/^(men)$/, "i", "\\1"}, + {~s/^(women)/, "i", "\\1"}, + {~s/^(echo)$/, "i", "\\1es"}, + {~s/^(hero)$/, "i", "\\1es"}, + {~s/^(potato)/, "i", "\\1es"}, + {~s/^(tomato)/, "i", "\\1es"}, + {~s/^(t)ooth$/, "i", "\\1eeth"}, + {~s/^(l)ouse$/, "i", "\\1ice"}, + {~s/^(addend|bacteri|curricul|dat|memorand|quant)um$/, "i", "\\1a"}, + {~s/^(di)e$/, "i", "\\1ce"}, + {~s/^(f)oot$/, "i", "\\1eet"}, + {~s/^(phenomen)on/, "i", "\\1a"} ] @singular @irregular ++ [ - {~r/(child)ren/i, "\\1"}, - {~r/(wo|sea)men$/i, "\\1man"}, - {~r/^(m|l)ice$/i, "\\1ouse"}, - {~r/(bus|canvas|status|alias)(es)?$/i, "\\1"}, - {~r/(ss)$/i, "\\1"}, - {~r/(database)s$/i, "\\1"}, - {~r/([ti])a$/i, "\\1um"}, - {~r/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, + {~s/(child)ren/, "i", "\\1"}, + {~s/(wo|sea)men$/, "i", "\\1man"}, + {~s/^(m|l)ice$/, "i", "\\1ouse"}, + {~s/(bus|canvas|status|alias)(es)?$/, "i", "\\1"}, + {~s/(ss)$/, "i", "\\1"}, + {~s/(database)s$/, "i", "\\1"}, + {~s/([ti])a$/, "i", "\\1um"}, + {~s/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/, "i", "\\1sis"}, - {~r/(analy)(sis|ses)$/i, "\\1sis"}, - {~r/(octop|vir)i$/i, "\\1us"}, - {~r/(hive)s$/i, "\\1"}, - {~r/(tive)s$/i, "\\1"}, - {~r/(er)ves$/i, "\\1ve"}, - {~r/([lora])ves$/i, "\\1f"}, - {~r/([^f])ves$/i, "\\1fe"}, - {~r/([^aeiouy]|qu)ies$/i, "\\1y"}, - {~r/(m)ovies$/i, "\\1ovie"}, - {~r/(x|ch|ss|sh)es$/i, "\\1"}, - {~r/(shoe)s$/i, "\\1"}, - {~r/(o)es$/i, "\\1"}, - {~r/s$/i, ""} + {~s/(analy)(sis|ses)$/, "i", "\\1sis"}, + {~s/(octop|vir)i$/, "i", "\\1us"}, + {~s/(hive)s$/, "i", "\\1"}, + {~s/(tive)s$/, "i", "\\1"}, + {~s/(er)ves$/, "i", "\\1ve"}, + {~s/([lora])ves$/, "i", "\\1f"}, + {~s/([^f])ves$/, "i", "\\1fe"}, + {~s/([^aeiouy]|qu)ies$/, "i", "\\1y"}, + {~s/(m)ovies$/, "i", "\\1ovie"}, + {~s/(x|ch|ss|sh)es$/, "i", "\\1"}, + {~s/(shoe)s$/, "i", "\\1"}, + {~s/(o)es$/, "i", "\\1"}, + {~s/s$/, "i", ""} ] @plural @plural_irregular ++ [ - {~r/(child)$/i, "\\1ren"}, - {~r/(m)an$/i, "\\1en"}, - {~r/(m|l)ouse/i, "\\1ice"}, - {~r/(database)s$/i, "\\1"}, - {~r/(quiz)$/i, "\\1zes"}, - {~r/^(ox)$/i, "\\1en"}, - {~r/(matr|vert|ind)ix|ex$/i, "\\1ices"}, - {~r/(x|ch|ss|sh)$/i, "\\1es"}, - {~r/([^aeiouy]|qu)y$/i, "\\1ies"}, - {~r/(hive)$/i, "\\1s"}, - {~r/(sc[au]rf)$/i, "\\1s"}, - {~r/(?:([^f])fe|((hoo)|([lra]))f)$/i, "\\2\\1ves"}, - {~r/sis$/i, "ses"}, - {~r/([ti])um$/i, "\\1a"}, - {~r/(buffal|tomat)o$/i, "\\1oes"}, - {~r/(octop|vir)us$/i, "\\1i"}, - {~r/(bus|alias|status|canvas)$/i, "\\1es"}, - {~r/(ax|test)is$/i, "\\1es"}, - {~r/s$/i, "s"}, - {~r/data$/i, "data"}, - {~r/$/i, "s"} + {~s/(child)$/, "i", "\\1ren"}, + {~s/(m)an$/, "i", "\\1en"}, + {~s/(m|l)ouse/, "i", "\\1ice"}, + {~s/(database)s$/, "i", "\\1"}, + {~s/(quiz)$/, "i", "\\1zes"}, + {~s/^(ox)$/, "i", "\\1en"}, + {~s/(matr|vert|ind)ix|ex$/, "i", "\\1ices"}, + {~s/(x|ch|ss|sh)$/, "i", "\\1es"}, + {~s/([^aeiouy]|qu)y$/, "i", "\\1ies"}, + {~s/(hive)$/, "i", "\\1s"}, + {~s/(sc[au]rf)$/, "i", "\\1s"}, + {~s/(?:([^f])fe|((hoo)|([lra]))f)$/, "i", "\\2\\1ves"}, + {~s/sis$/, "i", "ses"}, + {~s/([ti])um$/, "i", "\\1a"}, + {~s/(buffal|tomat)o$/, "i", "\\1oes"}, + {~s/(octop|vir)us$/, "i", "\\1i"}, + {~s/(bus|alias|status|canvas)$/, "i", "\\1es"}, + {~s/(ax|test)is$/, "i", "\\1es"}, + {~s/s$/, "i", "s"}, + {~s/data$/, "i", "data"}, + {~s/$/, "i", "s"} ] @singular @irregular ++ [ - {~r/(child)ren/i, "\\1"}, - {~r/(wo|sea)men$/i, "\\1man"}, - {~r/^(m|l)ice$/i, "\\1ouse"}, - {~r/(bus|canvas|status|alias)(es)?$/i, "\\1"}, - {~r/(ss)$/i, "\\1"}, - {~r/(database)s$/i, "\\1"}, - {~r/([ti])a$/i, "\\1um"}, - {~r/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, + {~s/(child)ren/, "i", "\\1"}, + {~s/(wo|sea)men$/, "i", "\\1man"}, + {~s/^(m|l)ice$/, "i", "\\1ouse"}, + {~s/(bus|canvas|status|alias)(es)?$/, "i", "\\1"}, + {~s/(ss)$/, "i", "\\1"}, + {~s/(database)s$/, "i", "\\1"}, + {~s/([ti])a$/, "i", "\\1um"}, + {~s/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/, "i", "\\1sis"}, - {~r/(analy)(sis|ses)$/i, "\\1sis"}, - {~r/(octop|vir)i$/i, "\\1us"}, - {~r/(hive)s$/i, "\\1"}, - {~r/(tive)s$/i, "\\1"}, - {~r/(er)ves$/i, "\\1ve"}, - {~r/([lora])ves$/i, "\\1f"}, - {~r/([^f])ves$/i, "\\1fe"}, - {~r/([^aeiouy]|qu)ies$/i, "\\1y"}, - {~r/(m)ovies$/i, "\\1ovie"}, - {~r/(x|ch|ss|sh)es$/i, "\\1"}, - {~r/(shoe)s$/i, "\\1"}, - {~r/(o)es$/i, "\\1"}, - {~r/s$/i, ""} + {~s/(analy)(sis|ses)$/, "i", "\\1sis"}, + {~s/(octop|vir)i$/, "i", "\\1us"}, + {~s/(hive)s$/, "i", "\\1"}, + {~s/(tive)s$/, "i", "\\1"}, + {~s/(er)ves$/, "i", "\\1ve"}, + {~s/([lora])ves$/, "i", "\\1f"}, + {~s/([^f])ves$/, "i", "\\1fe"}, + {~s/([^aeiouy]|qu)ies$/, "i", "\\1y"}, + {~s/(m)ovies$/, "i", "\\1ovie"}, + {~s/(x|ch|ss|sh)es$/, "i", "\\1"}, + {~s/(shoe)s$/, "i", "\\1"}, + {~s/(o)es$/, "i", "\\1"}, + {~s/s$/, "i", ""} ] @plural @plural_irregular ++ [ - {~r/(child)$/i, "\\1ren"}, - {~r/(m)an$/i, "\\1en"}, - {~r/(m|l)ouse/i, "\\1ice"}, - {~r/(database)s$/i, "\\1"}, - {~r/(quiz)$/i, "\\1zes"}, - {~r/^(ox)$/i, "\\1en"}, - {~r/(matr|vert|ind)ix|ex$/i, "\\1ices"}, - {~r/(x|ch|ss|sh)$/i, "\\1es"}, - {~r/([^aeiouy]|qu)y$/i, "\\1ies"}, - {~r/(hive)$/i, "\\1s"}, - {~r/(sc[au]rf)$/i, "\\1s"}, - {~r/(?:([^f])fe|((hoo)|([lra]))f)$/i, "\\2\\1ves"}, - {~r/sis$/i, "ses"}, - {~r/([ti])um$/i, "\\1a"}, - {~r/(buffal|tomat)o$/i, "\\1oes"}, - {~r/(octop|vir)us$/i, "\\1i"}, - {~r/(bus|alias|status|canvas)$/i, "\\1es"}, - {~r/(ax|test)is$/i, "\\1es"}, - {~r/s$/i, "s"}, - {~r/data$/i, "data"}, - {~r/$/i, "s"} + {~s/(child)$/, "i", "\\1ren"}, + {~s/(m)an$/, "i", "\\1en"}, + {~s/(m|l)ouse/, "i", "\\1ice"}, + {~s/(database)s$/, "i", "\\1"}, + {~s/(quiz)$/, "i", "\\1zes"}, + {~s/^(ox)$/, "i", "\\1en"}, + {~s/(matr|vert|ind)ix|ex$/, "i", "\\1ices"}, + {~s/(x|ch|ss|sh)$/, "i", "\\1es"}, + {~s/([^aeiouy]|qu)y$/, "i", "\\1ies"}, + {~s/(hive)$/, "i", "\\1s"}, + {~s/(sc[au]rf)$/, "i", "\\1s"}, + {~s/(?:([^f])fe|((hoo)|([lra]))f)$/, "i", "\\2\\1ves"}, + {~s/sis$/, "i", "ses"}, + {~s/([ti])um$/, "i", "\\1a"}, + {~s/(buffal|tomat)o$/, "i", "\\1oes"}, + {~s/(octop|vir)us$/, "i", "\\1i"}, + {~s/(bus|alias|status|canvas)$/, "i", "\\1es"}, + {~s/(ax|test)is$/, "i", "\\1es"}, + {~s/s$/, "i", "s"}, + {~s/data$/, "i", "data"}, + {~s/$/, "i", "s"} ] + defp compile_rules(rules) do + Enum.map(rules, fn {pattern, opts, repl} -> + {Regex.compile!(pattern, opts), repl} + end) + end + def singularize(word) when is_atom(word) do - find_match(@singular, to_string(word)) + @singular + |> compile_rules() + |> find_match(to_string(word)) end - def singularize(word), do: find_match(@singular, word) + def singularize(word) do + @singular + |> compile_rules() + |> find_match(word) + end def pluralize(word) when is_atom(word) do - find_match(@plural, to_string(word)) + @plural + |> compile_rules() + |> find_match(to_string(word)) end - def pluralize(word), do: find_match(@plural, word) + def pluralize(word) do + @plural + |> compile_rules() + |> find_match(word) + end def inflect(word, n) when n == 1, do: singularize(word) def inflect(word, n) when is_number(n), do: pluralize(word) @@ -193,7 +210,7 @@ defmodule Inflex.Pluralize do defp find_match(set, word) do cond do uncountable?(word) -> word - @default -> replace_match(set, word) + true -> replace_match(set, word) end end diff --git a/test/inflex_test.exs b/test/inflex_test.exs index 7196799..0f5cbd3 100644 --- a/test/inflex_test.exs +++ b/test/inflex_test.exs @@ -190,21 +190,21 @@ defmodule InflexTest do end test :camelize_upper do - assert "Upper" == camelize("upper") + assert "Upper" == camelize("upper") assert "UpperCamelCase" == camelize("upper_camel_case") assert "UpperCamelCase" == camelize("UpperCamelCase") assert "UpperCamelCase" == camelize("UPPER_CAMEL_CASE") - assert "" == camelize("") + assert "" == camelize("") refute "UpperCamelCase" == camelize("upper_camel_case", :lower) end test :camelize_lower do - assert "lower" == camelize("lower", :lower) + assert "lower" == camelize("lower", :lower) assert "lowerCamelCase" == camelize("lower_camel_case", :lower) assert "lowerCamelCase" == camelize("Lower_camel_case", :lower) assert "lowerCamelCase" == camelize("lowerCamelCase", :lower) assert "lowerCamelCase" == camelize("LOWER_CAMEL_CASE", :lower) - assert "" == camelize("", :lower) + assert "" == camelize("", :lower) refute "lowerCamelCase" == camelize("lower_camel_case") end @@ -277,5 +277,4 @@ defmodule InflexTest do assert "accomplice" == inflect("accomplice", 1) assert "accomplice" == inflect("accomplice", 1.0) end - end diff --git a/test/test_helper.exs b/test/test_helper.exs index 4b8b246..869559e 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1 +1 @@ -ExUnit.start +ExUnit.start()