diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..53ee0b1 --- /dev/null +++ b/.tool-versions @@ -0,0 +1,2 @@ +elixir 1.16.1-otp-26 +erlang 26.2.1 diff --git a/lib/ex_toolkit/naming.ex b/lib/ex_toolkit/naming.ex index f7c3441..7a2b7f7 100644 --- a/lib/ex_toolkit/naming.ex +++ b/lib/ex_toolkit/naming.ex @@ -5,6 +5,8 @@ defmodule ExToolkit.Naming do returns results in a formatted, readable way. """ + alias ExToolkit.Roman + @doc """ Shortens the first name to its initial, while preserving the rest of the name. @@ -121,6 +123,21 @@ defmodule ExToolkit.Naming do iex> Naming.extract_first_last_name("john doe smith") "John Smith" + + iex> Naming.extract_first_last_name("john doe smith jr") + "John Smith Jr" + + iex> Naming.extract_first_last_name("john jr") + "John Jr" + + iex> Naming.extract_first_last_name("john jose doe III") + "John Doe III" + + iex> Naming.extract_first_last_name("john doe v") + "John Doe V" + + iex> Naming.extract_first_last_name("Sir Alexander Chapman Ferguson") + "Sir Alexander Ferguson" """ @spec extract_first_last_name(nil | String.t()) :: String.t() def extract_first_last_name(name) when is_nil(name) or name == "", do: "" @@ -134,9 +151,29 @@ defmodule ExToolkit.Naming do |> Enum.map(&String.capitalize/1) case names do - [] -> "" - [first] -> first - [first | rest] -> first <> " " <> Enum.at(rest, -1) + [] -> + "" + + [first] -> + first + + [first | rest] -> + cond do + length(rest) == 1 -> + first <> " " <> Enum.at(rest, -1) + + first == "Sir" -> + "Sir" <> " " <> Enum.at(rest, 0) <> " " <> Enum.at(rest, -1) + + Enum.at(rest, -1) == "Jr" -> + first <> " " <> Enum.at(rest, -2) <> " Jr" + + Roman.is_valid_roman(Enum.at(rest, -1)) -> + first <> " " <> Enum.at(rest, -2) <> " " <> String.upcase(Enum.at(rest, -1)) + + true -> + first <> " " <> Enum.at(rest, -1) + end end end diff --git a/lib/ex_toolkit/roman.ex b/lib/ex_toolkit/roman.ex new file mode 100644 index 0000000..cf02e29 --- /dev/null +++ b/lib/ex_toolkit/roman.ex @@ -0,0 +1,20 @@ +defmodule ExToolkit.Roman do + @valid_romans ["I", "V", "X", "L", "C", "D", "M"] + + def is_valid_roman(string) do + string + |> String.upcase() + |> String.graphemes() + |> is_valid_roman(@valid_romans) + end + + defp is_valid_roman([], _), do: true + + defp is_valid_roman([head | tail], valid_romans) do + if Enum.member?(@valid_romans, head) do + is_valid_roman(tail, valid_romans) + else + false + end + end +end