lib/greeklix.ex

defmodule Greeklix do
  require Greeklix.Rules

  @moduledoc """
  Module containing functions for converting Greek text to Greeklish.
  """

  @moduledoc since: "0.1.0"

  @rules Greeklix.Rules.compile_substitution_rules()

  @doc """
  Show the compiled substitution rules.
  """
  @doc since: "0.1.0"
  def get_rules do
    @rules
  end

  # Remove accent characters from text.
  defp remove_accent_chars(input_tokens) when is_list(input_tokens) do
    input_tokens
    |> Enum.map(fn x ->
      String.normalize(x, :nfd) |> String.codepoints() |> hd()
    end)
  end

  # Detect digraphs that will be substituted based on the `@rules` module attribute.
  defp detect_digraphs(input_tokens, acc \\ [])

  defp detect_digraphs(input_tokens, acc) when length(input_tokens) > 1 do
    [a, b | tail] = input_tokens

    case String.downcase(a <> b) in Map.keys(@rules) do
      true -> detect_digraphs(tail, acc ++ [a <> b])
      false -> detect_digraphs([b] ++ tail, acc ++ [a])
    end
  end

  defp detect_digraphs(input_tokens, acc)
       when length(input_tokens) == 1 or input_tokens == [] do
    acc ++ input_tokens
  end

  # Perform substitutions based on the compiled rules, with an optional parameter of the variant number (integer)
  defp substitute(input_tokens, variant \\ 0) do
    input_tokens
    |> Enum.map(fn x ->
      if x in Map.keys(@rules) do
        @rules[x] |> Enum.at(min(variant, length(@rules[x]) - 1))
      else
        x
      end
    end)
  end

  @doc """
  Convert Greek text to Greeklish, with an optional parameter of the variant number (integer).
  """
  @doc since: "0.1.0"
  def convert(input_tokens, variant \\ 0) do
    input_tokens
    |> String.graphemes()
    |> remove_accent_chars()
    |> detect_digraphs()
    |> substitute(variant)
    |> List.to_string()
  end
end