ukraine-taxid-ex/lib/ukraine_taxid_ex/base_parser.ex

47 lines
1.5 KiB
Elixir

defmodule UkraineTaxidEx.BaseParser do
@typedoc """
Options for parsing:
- `:normalize?` - if true, pad the string to the right length (8 for EDRPOU, 10 for ITIN)
- `:clean?` - if true, remove non-digit characters
"""
@type options :: [normalize?: boolean, clean?: boolean]
@callback parse(code :: String.t(), options :: options()) :: {:ok, term} | {:error, atom}
defmacro __using__(_) do
quote do
@behaviour UkraineTaxidEx.BaseParser
alias UkraineTaxidEx.BaseParser
@type string_or_ok() :: String.t() | {:ok, String.t()}
@type struct_or_error() :: {:ok, term} | {:error, atom()}
@struct_module Module.split(__MODULE__) |> Enum.slice(0..-2//1) |> Module.concat()
# def struct_module(), do: @struct_module
defp to_struct(map), do: struct(@struct_module, map)
@impl BaseParser
@spec parse(data :: string_or_ok, options :: BaseParser.options()) :: struct_or_error()
def parse(data, options \\ [normalize?: false, clean?: true])
def parse({:ok, string}, options), do: parse(string, options)
def parse({:error, error}, _options), do: {:error, error}
def parse(string, options) do
length = (Keyword.get(options, :normalize?, false) && length()) || 0
clean? = Keyword.get(options, :clean?, false)
string
|> digits(length, clean?)
|> undigits()
|> validate()
|> generate()
end
defp generate({:error, error}), do: {:error, error}
defp generate({:ok, string}), do: generate(string)
end
end
end