intentionally-left-nil
intentionally-left-nil

Reputation: 8336

Macro block unexpectedly returns [do: return value]

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?

Larger snippet

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

Results

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

Answers (1)

Dogbert
Dogbert

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

Related Questions