defmodule Timex.Parse.Duration.Parser do @moduledoc """ This module is responsible for parsing input strings into Duration structs. The actual parsing is delegated to specific parser modules, but this module provides a unified API for all of them. """ alias Timex.Duration alias Timex.Parse.ParseError alias Timex.Parse.Duration.Parsers.ISO8601Parser defmacro __using__(_) do quote do @behaviour Timex.Parse.Duration.Parser alias Timex.Duration end end @callback parse(String.t()) :: {:ok, Duration.t()} | {:error, term} @doc """ Parses the given input using the ISO-8601 duration parser, and returns either an :ok, or :error tuple. """ @spec parse(String.t()) :: {:ok, Duration.t()} | {:error, term} def parse(str) when is_binary(str) do parse(str, ISO8601Parser) end @doc """ Parses the given input using the provided parser module, and returns either an :ok, or :error tuple. """ @spec parse(String.t(), module()) :: {:ok, Duration.t()} | {:error, term} def parse(str, parser) when is_binary(str) and is_atom(parser) do case parser.parse(str) do %Duration{} = d -> {:ok, d} {:ok, d} -> {:ok, d} {:error, term} -> {:error, term} end end @doc """ Parses the given input using the ISO-8601 duration parser, and either returns a Duration, or raises an error. """ @spec parse!(String.t()) :: Duration.t() | no_return def parse!(str) when is_binary(str) do parse!(str, ISO8601Parser) end @doc """ Parses the given input using the provided parser module, and either returns a Duration, or raises an error. """ @spec parse!(String.t(), module()) :: Duration.t() | no_return def parse!(str, parser) when is_binary(str) and is_atom(parser) do case parse(str) do {:ok, d} -> d {:error, reason} when is_binary(reason) -> raise ParseError, message: reason {:error, term} -> raise ParseError, message: "#{inspect(term)}" end end end