Reputation: 8336
I have the following definition inside a macro:
defmacro route(pattern, options \\ [], block) do
name = "my_fun"
def unquote(name)(var!(conn)) do
unquote(block)
end
end
I am calling the macro with this function:
route "/" do
conn
|> put_resp_content_type("text/plain")
|> send_resp(200, "Hello, world!")
The inner block is returning a %Plug.Conn{}
struct, but when I print the results of unquote(block)
in my macro, I get [do: %Plug.Conn{}]
What am I doing wrong? Where did the do
keyword list come from?
defmacro route(pattern, options \\ [], block) do
name = Keyword.get_lazy(options, :name, fn -> create_name(pattern, options) end)
route = {pattern, name}
quote do
@routes [unquote(route) | @routes]
def unquote(name)(var!(conn)) do
resp = unquote(block)
IO.puts("outside the block, resp is")
IO.inspect(resp)
end
end
end
route "/" do
resp = conn
|> put_resp_content_type("text/plain")
|> send_resp(200, "Hello, world!")
IO.puts("Inside the block, resp is")
IO.inspect(resp)
resp
end
Inside the block, resp is
%Plug.Conn{
adapter: {Plug.Adapters.Cowboy2.Conn, :...},
assigns: %{},
{....SNIP....}
}
outside the block, resp is
[
do: %Plug.Conn{
adapter: {Plug.Adapters.Cowboy2.Conn, :...},
assigns: %{},
{....SNIP....}
}
]
Upvotes: 0
Views: 57
Reputation: 222388
You need to change the argument from block
to do: block
:
defmacro route(pattern, options \\ [], do: block) do
A do ... end
argument in an Elixir macro invocation is passed as a one item keyword list with the key being :do
.
If you don't remove that nesting by pattern matching it as do: block
, the argument's value will be [do: block]
and when you unquote it, you're unquoting [do: ...]
, which is also a valid expression and explains why your code works and why it prints [do: ...]
.
Upvotes: 1