Packages

Define easily :call and :cast, :info functions when using gen_server in elixir.

Current section

Files

Jump to
min_delegate lib min_delegate.ex
Raw

lib/min_delegate.ex

defmodule MinDelegate do
@moduledoc """
Documentation for MinDelegate.
"""
@doc false
defmacro __using__(_opts) do
quote do
unless Module.get_attribute(__MODULE__, :min_delegate) do
attributes = [
:min_delegate,
:alias
]
if Enum.any?(attributes, &Module.get_attribute(__MODULE__, &1)) do
raise "you must set @alias after the call to \"use MinDelegate\""
end
Enum.each(attributes, &Module.register_attribute(__MODULE__, &1, []))
end
# , only: [min_delegate: 2]
import MinDelegate
end
end
defmacro defcall(message, _var \\ quote(do: _), do: contents) do
{func, args} = Macro.decompose_call(message)
args = Macro.escape(args)
func = Macro.escape(func)
pid = Macro.escape(Macro.var(:pid, nil))
contents = Macro.escape(contents)
quote bind_quoted: [pid: pid, args: args, func: func, contents: contents] do
state_name = MinDelegate.get_attribute(__MODULE__, :alias, :state, true)
args = Enum.filter(args, &(!match?({^state_name, _, _}, &1)))
state = Macro.var(state_name, nil)
def unquote(func)(unquote(pid), unquote_splicing(args)) do
msg = {unquote(func), unquote_splicing(args)}
GenServer.call(unquote(pid), msg)
end
def handle_call({unquote(func), unquote_splicing(args)}, _from, unquote(state)) do
unquote(contents)
end
end
end
defmacro defcast(message, _var \\ quote(do: _), do: contents) do
{func, args} = Macro.decompose_call(message)
args = Macro.escape(args)
func = Macro.escape(func)
pid = Macro.escape(Macro.var(:pid, nil))
contents = Macro.escape(contents)
quote bind_quoted: [pid: pid, args: args, func: func, contents: contents] do
state_name = MinDelegate.get_attribute(__MODULE__, :alias, :state, true)
args = Enum.filter(args, &(!match?({^state_name, _, _}, &1)))
state = Macro.var(state_name, nil)
def unquote(func)(unquote(pid), unquote_splicing(args)) do
msg = {unquote(func), unquote_splicing(args)}
GenServer.cast(unquote(pid), msg)
end
def handle_cast({unquote(func), unquote_splicing(args)}, unquote(state)) do
unquote(contents)
end
end
end
defmacro definfo(message, _var \\ quote(do: _), do: contents) do
{func, args} = Macro.decompose_call(message)
args = Macro.escape(args)
func = Macro.escape(func)
pid = Macro.escape(Macro.var(:pid, nil))
contents = Macro.escape(contents)
quote bind_quoted: [pid: pid, args: args, func: func, contents: contents] do
state_name = MinDelegate.get_attribute(__MODULE__, :alias, :state, true)
args = Enum.filter(args, &(!match?({^state_name, _, _}, &1)))
state = Macro.var(state_name, nil)
def unquote(func)(unquote(pid), unquote_splicing(args), delay \\ 0) do
msg = {unquote(func), unquote_splicing(args)}
if delay > 0 do
Process.send_after(unquote(pid), msg, delay)
else
send(unquote(pid), msg)
end
end
def handle_info({unquote(func), unquote_splicing(args)}, unquote(state)) do
unquote(contents)
end
end
end
def get_attribute(mod, key, default, delete?) do
attr =
if delete? do
Module.delete_attribute(mod, key)
else
Module.get_attribute(mod, key)
end
if attr do
attr
else
default
end
end
end
defmodule MinDelegateQ do
@moduledoc """
Simple queue for testing min_delegate
"""
use GenServer
use MinDelegate
### GenServer Initializations
def init(_state), do: {:ok, []}
def start_link(state \\ []) do
GenServer.start_link(__MODULE__, state, name: __MODULE__)
end
@alias :data
defcall add_value(value, data) do
data = [value | data]
{:reply, data, data}
end
defcast add_value_cast(value, state) do
{:noreply, [value | state]}
end
defcall count(state) do
{:reply, length(state), state}
end
# #@whereis &whereis/1
definfo add_value_info(value, state) do
{ :noreply, [value | state] }
end
# def whereis(id) do
# Registry.lookup(:min_delegate_app, id)
# end
end