71 lines
2.0 KiB
Elixir

defmodule Translator.Parser do
@type filename :: String.t()
@type extension :: String.t()
@type data :: map
@type parser :: atom
@type availiable_parsers_map :: %{required(extension) => parser}
@spec load(filename) :: {:error, any} | {:ok, any}
def load(filename) do
case select_parser(filename) do
{:error, message} -> {:error, message}
{:ok, parser} -> load(filename, parser)
end
end
@spec load(filename, parser) :: {:error, any} | {:ok, any}
def load(filename, parser) do
with {:ok, contents} <- File.read(filename),
{:ok, result} <- parser.parse(contents) do
{:ok, result}
else
{:error, error} -> {:error, error}
end
end
@spec save(filename, data) :: {:error, any} | {:ok, any}
def save(filename, data) do
case select_parser(filename) do
{:error, message} -> {:error, message}
{:ok, parser} -> save(filename, data, parser)
end
end
@spec save(filename, data, parser) :: :ok | {:error, any}
def save(filename, data, parser) do
with {:ok, contents} <- parser.generate(data),
:ok <- File.write(filename, contents) do
:ok
else
{:error, error} -> {:error, error}
end
end
@spec select_parser(filename) :: {:ok, atom} | {:error, any}
defp select_parser(filename) do
case select_parser!(filename) do
nil -> {:error, "Couldn't find availiable parser for this extension"}
value -> {:ok, value}
end
end
@spec select_parser!(filename) :: atom
defp select_parser!(filename),
do: Map.get(availiable(), String.trim_leading(Path.extname(filename), "."))
@spec availiable() :: availiable_parsers_map
defp availiable() do
Application.get_env(:translator, :parsers)
|> Enum.reduce(%{}, fn parser, avaliable_extensions_map ->
{:ok, extensions} = parser.extensions()
parser_extensions_map =
extensions
|> Enum.map(&{&1, parser})
|> Map.new()
Map.merge(avaliable_extensions_map, parser_extensions_map)
end)
end
end