Packages
ex_gram
0.23.0
0.67.0
0.66.0
0.65.0
0.64.0
0.63.0
0.62.0
0.61.0
0.60.0
0.58.0
0.57.0
0.56.1
0.56.0
0.55.1
0.55.0
0.54.0
0.53.0
0.52.2
0.52.1
0.52.0
0.51.1
0.51.0
0.50.2
0.50.1
0.50.0
0.41.0
0.40.0
0.34.0
0.33.0
0.32.0
0.31.0
0.30.0
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.1
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.0
0.10.0
0.9.0
0.8.1
0.8.0
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.0
0.5.0-rc6
0.5.0-rc5
0.5.0-rc4
0.5.0-rc3
0.5.0-rc2
Telegram Bot API low level and framework
Current section
Files
Jump to
Current section
Files
lib/ex_gram/macros/helpers.ex
defmodule ExGram.Macros.Helpers do
@moduledoc """
Helpers for the ExGram.Macros module
"""
def analyze_param({:{}, line, [{name, _line, nil}]}), do: {{name, line, nil}, [name, [:any]]}
def analyze_param({:{}, line, [{name, _line, nil}, types, :optional]}),
do: {{:\\, line, [{name, line, nil}, nil]}, [name, types, :optional]}
def analyze_param({name, _line, nil} = full), do: {full, [name, [:any]]}
def analyze_param({{name, line, nil}, :optional}),
do: {{:\\, line, [{name, line, nil}, nil]}, [name, [:any], :optional]}
def analyze_param({{name, line, nil}, types}), do: {{name, line, nil}, [name, types]}
def analyze_param({{name, line, nil}, types, :optional}),
do: {{:\\, line, [{name, line, nil}, nil]}, [name, types, :optional]}
def mandatory_type_specs(analyzed) do
analyzed
|> Enum.map(&elem(&1, 1))
|> Enum.filter(&(not is_par_optional(&1)))
|> Enum.map(fn [n, ts] -> parameter_type_spec(n, types_list_to_spec(ts)) end)
end
def mandatory_value_type(analyzed) do
analyzed
|> Enum.map(&elem(&1, 1))
|> Enum.filter(&(not is_par_optional(&1)))
|> Enum.map(fn [name, types] -> [nid(name), types] end)
end
def optional_type_specs(analyzed) do
analyzed
|> Enum.map(&elem(&1, 1))
|> Enum.filter(&is_par_optional/1)
|> Enum.map(fn [n, ts, :optional] -> {n, types_list_to_spec(ts)} end)
|> Kernel.++(common_opts())
end
def mandatory_parameters(analyzed) do
mandatory =
analyzed
|> Enum.filter(fn {_name, desc} -> not is_par_optional(desc) end)
names = Enum.map(mandatory, fn {name, _desc} -> name end)
mand_atoms = Enum.map(names, &extract_param_name/1)
mand_values = Enum.map(mand_atoms, &nid/1)
body = Enum.zip(mand_atoms, mand_values)
{names, body}
end
def optional_parameters(analyzed) do
optionals =
analyzed
|> Enum.map(&elem(&1, 1))
|> Enum.filter(&is_par_optional/1)
optional_types = Enum.map(optionals, fn [name, types, :optional] -> {name, types} end)
optional_names = Enum.map(optionals, fn [name, _, _] -> name end)
{optional_names, optional_types}
end
def file_parameters(analyzed) do
analyzed
|> Enum.map(fn {_n, types} -> types end)
|> Enum.filter(fn [_n, t | _] -> Enum.any?(t, &(&1 == :file or &1 == :file_content)) end)
|> Enum.map(fn
[n, _t] -> {nid(n), Atom.to_string(n)}
[n, _t, :optional] -> n
end)
end
def type_to_spec(:string),
do: {{:., [], [{:__aliases__, [alias: false], [:String]}, :t]}, [], []}
def type_to_spec(:enum),
do: {{:., [], [{:__aliases__, [alias: false], [:Enum]}, :t]}, [], []}
def type_to_spec(:file) do
orT(
{:file, type_to_spec(:string)},
type_to_spec(:file_content)
)
end
def type_to_spec(:file_content) do
{:{}, [], [:file_content, type_to_spec(:file_data), type_to_spec(:string)]}
end
def type_to_spec(:file_data) do
orT(type_to_spec(:iodata), type_to_spec(:enum))
end
def type_to_spec({:array, t}), do: {:list, [], [type_to_spec(t)]}
def type_to_spec(:integer), do: {:integer, [], []}
def type_to_spec(:boolean), do: {:boolean, [], []}
def type_to_spec(true), do: true
def type_to_spec({:__aliases__, _a, [:ExGram, :Model | _]} = f) do
quote do
unquote(f).t
end
end
def type_to_spec({:__aliases__, _a, _} = f) do
quote do
ExGram.Model.unquote(f).t
end
end
def type_to_spec(t) when is_atom(t), do: {t, [], Elixir}
def type_to_spec(l) when is_list(l), do: types_list_to_spec(l)
defp types_list_to_spec([e1]) do
type_to_spec(e1)
end
defp types_list_to_spec([e1 | rest]) do
orT(type_to_spec(e1), types_list_to_spec(rest))
end
defp types_list_to_spec([]) do
type_to_spec(:any)
end
@common_opts [
adapter: :atom,
bot: :atom,
token: :string,
debug: :boolean,
check_params: :boolean
]
defp common_opts do
@common_opts |> Enum.map(fn {k, v} -> {k, type_to_spec(v)} end)
end
defp parameter_type_spec(n, t) when is_atom(n), do: {:"::", [], [type_to_spec(n), t]}
defp parameter_type_spec(n, t), do: {:"::", [], [n, t]}
defp nid(x), do: {x, [], nil}
defp is_par_optional([_n, _t, :optional]), do: true
defp is_par_optional(_), do: false
defp extract_param_name({name, _line, nil}), do: name
defp extract_param_name({:\\, _line, [{name, _line2, nil}, nil]}), do: name
# MODEL helpers
def params_to_decode_as(params) do
params
|> Stream.map(fn
{k, v} -> {k, v}
{:{}, _, [k, v, :optional]} -> {k, v}
end)
|> Stream.map(fn {k, v} ->
{k, param_to_decode_as(v)}
end)
|> Enum.filter(fn {_k, v} -> not is_nil(v) end)
end
defp param_to_decode_as({:array, type}) do
case param_to_decode_as(type) do
nil ->
nil
t ->
quote do
[unquote(t)]
end
end
end
defp param_to_decode_as({:__aliases__, _, _} = st) do
quote do
ExGram.Model.unquote(st)
end
end
defp param_to_decode_as(_other), do: nil
def struct_type_specs([], acc), do: acc
def struct_type_specs([{id, t} | xs], acc) do
act = acc ++ [{id, type_to_spec(t)}]
xs
|> struct_type_specs(act)
end
def struct_type_specs([{:{}, _line, [id, t, :optional]} | xs], acc) do
act = acc ++ [{id, {:|, [], [type_to_spec(t), nil]}}]
xs
|> struct_type_specs(act)
end
def struct_type_specs(_x, acc) do
# Logger.error "WTF struct?"
# Logger.error inspect(x)
struct_type_specs(acc)
end
def struct_type_specs(initial), do: struct_type_specs(initial, [])
# credo:disable-for-next-line
defp orT({:|, _, [x, y]}, z), do: orT(x, orT(y, z))
defp orT(x, y), do: {:|, [], [x, y]}
end