Packages

Elixir library to inflect Russian first, last, and middle names.

Current section

Files

Jump to
petrovich_elixir lib petrovich detector.ex
Raw

lib/petrovich/detector.ex

defmodule Petrovich.Detector do
@moduledoc """
Guesses the gender by person's name.
"""
alias Petrovich.GenderStore
alias Petrovich.Utils.ResultJoiner
@doc """
Detects a gender by name.
This function receives two arguments:
1. `name` raw person's name in nomenative case
2. `type` which shows what part of person's name it is
You can use any of these values as `type`:
[:firstname, :middlename, :lastname]
On success it returns a tuple `{:ok, "detected_gender"}`.
Or `:error` in cases when it is impossible to detect gender.
## Examples
iex> Detector.detect_gender("Игорь", :firstname)
{:ok, "male"}
iex> Detector.detect_gender("Саша", :firstname)
{:ok, "androgynous"}
iex> Detector.detect_gender("123", :firstname)
:error
"""
@spec detect_gender(String.t, atom()) :: {:ok, String.t} | :error
def detect_gender(name, type) do
%{"exceptions" => exceptions,
"suffixes" => suffixes} = GenderStore.get("gender", to_string(type))
name
|> String.downcase
|> String.split("-")
|> Enum.map(fn(item) -> prepare_value(item, exceptions, suffixes) end)
|> ResultJoiner.join_any_results(&join_result/1)
end
defp prepare_value(name, exceptions, suffixes) do
name
|> maybe_exception(exceptions)
|> maybe_rule(suffixes)
end
defp join_result(result) do
result
|> Enum.find(fn (item) ->
case item do
{:ok, _} -> true
_ -> false
end
end)
|> elem(1)
end
defp maybe_exception(name, exceptions) do
exceptions
|> Enum.find(fn({_, names}) -> name in names end)
|> case do
{gender, _} -> {:ok, gender}
nil -> {:error, name}
end
end
defp maybe_rule({:ok, gender}, _), do: {:ok, gender}
defp maybe_rule({:error, name}, suffixes) do
suffixes
|> Enum.find(fn({_, rule}) -> fits?(name, rule) end)
|> case do
{gender, _} -> {:ok, gender}
nil -> :error
end
end
defp fits?(name, rule) do
name_len = String.length(name)
Enum.any?(rule, fn(test) ->
test_len = String.length(test)
test == String.slice(name, name_len - test_len, test_len)
end)
end
end