Current section
Files
Jump to
Current section
Files
lib/bang.ex
defmodule Bang do
@moduledoc """
Creates an auto bang function with callback methods of result of non-bang
function. Bang uses accumulated approach by definition. So, you can define
several bangs inside your module and can use different callback for
each `@bang` function.
"""
@doc """
Registers @bang attribute for the module
## Examples
defmodule SomeModule do
use Bang
# now you can use @bang attribute to generate bang! functions
end
"""
defmacro __using__(_) do
quote do
Module.register_attribute __MODULE__, :bang, accumulate: true,
persist: false
@before_compile Bang
end
end
@doc """
Creates bang! functions using exisiting functions and callback function.
You can use multiple `@bang` attributes to specify several callback functions.
## Examples
# @bang {[list_of_func_name_arg_cnt_tuples], {CallbackModule, :callback_fn}}
@bang {[welcome: 1, welcome: 2], {SampleTestModule, :titleize}}
# or one by one
@bang {[welcome: 1], {SampleTestModule, :titleize}}
@bang {[welcome: 2], {SampleTestModule, :titleize}}
# Both of two approaches create [welcome!: 1, welcome!: 2] functions using
# existing [welcome: 1, welcome: 2] functions and after calls
# SampleTestModule.titleize method using output of
# [welcome: 1, welcome: 2]
"""
defmacro __before_compile__(env) do
bangs = Module.get_attribute(env.module, :bang)
for {fn_list, {cb_mdl, cb_fn}} <- bangs do
create_funcs(env.module, fn_list, cb_mdl, cb_fn)
end
end
defp create_funcs(fn_mdl, fn_list, cb_mdl, cb_fn) do
for {fn_name, arg_cnt} <- fn_list do
create_func(fn_mdl, fn_name, arg_cnt, cb_mdl, cb_fn)
end
end
defp create_func(fn_mdl, fn_name, arg_cnt, cb_mdl, cb_fn) do
fn_args = create_args(fn_mdl, arg_cnt)
create_ast(fn_mdl, fn_name, fn_args, :"#{fn_name}!", cb_mdl, cb_fn)
end
defp create_args(_, 0),
do: []
defp create_args(fn_mdl, arg_cnt),
do: Enum.map(1..arg_cnt, &(Macro.var (:"arg#{&1}"), fn_mdl))
defp create_ast(fn_mdl, fn_name, fn_args, bang_func, cb_mdl, cb_fn) do
quote do
@doc false
def unquote(bang_func)(unquote_splicing(fn_args)) do
value = apply(unquote(fn_mdl), unquote(fn_name), unquote(fn_args))
apply(unquote(cb_mdl), unquote(cb_fn), [value])
end
end
end
end