Current section

Files

Jump to
metastatic lib metastatic document analyzer.ex
Raw

lib/metastatic/document/analyzer.ex

defmodule Metastatic.Document.Analyzer do
@moduledoc false
@callback handle_analyze(Metastatic.Document.t(), keyword()) ::
{:ok, map()} | {:error, term()}
defmacro __using__(opts \\ []) do
quote location: :keep, generated: true do
@behaviour Metastatic.Document.Analyzer
doc =
Keyword.get(
unquote(opts),
:doc,
"Analyzes a document for #{inspect(__MODULE__)}, raising on error."
)
@doc doc
@spec analyze(Document.t()) :: {:ok, map()} | {:error, term()}
@spec analyze(Document.t(), keyword()) :: {:ok, map()} | {:error, term()}
@spec analyze(Metastatic.language(), term(), keyword()) :: {:ok, map()} | {:error, term()}
def analyze(language_or_doc, source_or_ast_or_opts \\ [], opts \\ [])
def analyze(language, source_or_ast, opts) when is_atom(language) do
with {:ok, doc} <- Metastatic.Document.normalize({language, source_or_ast}),
do: analyze(doc, opts, opts)
end
def analyze(%Metastatic.Document{ast: nil}, _, _),
do: {:error, :invalid_ast}
def analyze(%Metastatic.Document{ast: _} = doc, opts, _),
do: handle_analyze(doc, opts)
@doc doc <> "\n\nUnlike not-banged version, this one either returns a result or raises"
@spec analyze!(Document.t()) :: Result.t()
@spec analyze!(Document.t(), keyword()) :: Result.t()
@spec analyze!(Metastatic.language(), term(), keyword()) :: Result.t()
def analyze!(language_or_doc, source_or_ast_or_opts \\ [], opts \\ []) do
case analyze(language_or_doc, source_or_ast_or_opts, opts) do
{:ok, result} ->
result
{:error, reason} ->
raise "Analysis by #{inspect(__MODULE__)} failed: #{inspect(reason)}"
end
end
end
end
end