Current section

Files

Jump to
ex_gram lib ex_gram macros.ex
Raw

lib/ex_gram/macros.ex

defmodule ExGram.Macros do
@moduledoc """
`model/3` and `method/5` macros to build the API
"""
import __MODULE__.Helpers
defmacro model(name, params, description) do
analyzed = analyze_params(params)
tps = struct_type_specs(analyzed)
initials =
Enum.map(tps, fn {id, _t} -> {id, nil} end)
dca = params_to_decode_as(analyzed)
params_descriptions = params_descriptions(analyzed)
quote do
defmodule unquote(name) do
@moduledoc """
#{unquote(description)}
Check the [documentation of this model on Telegram Bot API](https://core.telegram.org/bots/api##{unquote(name) |> inspect() |> String.split(".") |> Enum.at(-1) |> String.downcase()})
#{Enum.map_join(unquote(params_descriptions), "\n", fn {k, v} -> "- `#{k}`: #{v}" end)}
"""
defstruct unquote(initials)
@type t :: %unquote(name){unquote_splicing(tps)}
def decode_as do
%unquote(name){unquote_splicing(dca)}
end
end
end
end
defmacro method(verb, name, params, returned, description) do
fname =
name
|> Macro.underscore()
|> String.to_atom()
# fnametest =
# "#{Macro.underscore(name)}_test"
# |> String.to_atom
fname_exception =
String.to_atom("#{Macro.underscore(name)}!")
analyzed = analyze_params(params)
types_mand_value = mandatory_value_type(analyzed)
types_mand_spec = mandatory_type_specs(analyzed)
types_opt_spec = optional_type_specs(analyzed)
{mandatory_parameters, mandatory_body} = mandatory_parameters(analyzed)
n_parameters = length(mandatory_parameters) + 1
{opt_par, opt_par_types} = optional_parameters(analyzed)
returned_type_spec = type_to_spec(returned)
file_parameters = file_parameters(analyzed)
params_descriptions = params_descriptions(analyzed)
quote location: :keep do
# Safe method
@doc """
#{unquote(description)}
Check the [documentation of this method on Telegram Bot API](https://core.telegram.org/bots/api##{String.downcase(unquote(name))})
#{Enum.map_join(unquote(params_descriptions), "\n", fn {k, v} -> "- `#{k}`: #{v}" end)}
"""
@spec unquote(fname)(unquote_splicing(types_mand_spec), options :: unquote(types_opt_spec)) ::
{:ok, unquote(returned_type_spec)}
| {:error, ExGram.Error.t()}
def unquote(fname)(unquote_splicing(mandatory_parameters), options \\ []) do
name = unquote(name)
verb = unquote(verb)
mandatory_body = unquote(mandatory_body)
file_parameters = unquote(file_parameters)
returned = unquote(returned)
method_ops = Keyword.take(options, unquote(opt_par))
mandatory_types = unquote(types_mand_value)
optional_types = unquote(opt_par_types)
ExGram.Macros.Executer.execute_method(
name,
verb,
mandatory_body,
file_parameters,
returned,
options,
method_ops,
mandatory_types,
optional_types
)
end
# Unsafe method
@doc """
Unsafe version of `#{unquote(fname)}/#{unquote(n_parameters)}`. It will return the response or raise in case of error.
#{unquote(description)}
Check the [documentation of this method on Telegram Bot API](https://core.telegram.org/bots/api##{String.downcase(unquote(name))})
"""
@spec unquote(fname_exception)(
unquote_splicing(types_mand_spec),
ops :: unquote(types_opt_spec)
) :: unquote(returned_type_spec)
def unquote(fname_exception)(unquote_splicing(mandatory_parameters), ops \\ []) do
case unquote(fname)(unquote_splicing(mandatory_parameters), ops) do
{:ok, result} -> result
{:error, error} -> raise error
end
end
end
end
end