defmodule Blunt.Context do
alias Blunt.Context
alias Blunt.Context.Proxy
defmodule Error do
defexception [:message]
end
defmacro __using__(_opts) do
quote do
use Blunt.Message.Compilation
Module.register_attribute(__MODULE__, :proxies, accumulate: true)
Module.register_attribute(__MODULE__, :messages, accumulate: true, persist: true)
@before_compile Blunt.Context
@after_compile Blunt.Context
import Blunt.Context, only: :macros
end
end
defmacro command(message_module, opts \\ []) do
quote bind_quoted: [message_module: message_module, opts: opts] do
{function_name, _opts} = Proxy.function_name(message_module, opts)
@messages {:command, message_module, function_name}
@proxies {{:command, message_module, opts}, {__ENV__.file, __ENV__.line}}
end
end
defmacro query(message_module, opts \\ []) do
quote bind_quoted: [message_module: message_module, opts: opts] do
{function_name, _opts} = Proxy.function_name(message_module, opts)
@messages {:query, message_module, function_name}
@proxies {{:query, message_module, opts}, {__ENV__.file, __ENV__.line}}
end
end
defmacro __before_compile__(_env) do
quote do
Enum.map(@proxies, fn {message_info, {file, line}} ->
code = Proxy.generate(message_info)
__ENV__
|> Map.put(:file, file)
|> Map.put(:line, line)
|> Module.eval_quoted(code)
end)
end
end
defmacro __after_compile__(%{module: module}, _bytecode) do
module
|> Context.proxied_messages()
|> Enum.each(&Proxy.validate!(&1, module))
nil
end
@doc false
def proxied_messages(bounded_context_module) do
:attributes
|> bounded_context_module.__info__()
|> Keyword.get_values(:messages)
|> List.flatten()
end
end