augnustin
Unquote with parameter in block
So I have this macro:
defmacro content(_opts \\ [], do: block) do
quote location: :keep do
def page_view(var!(conn)) do
import Kernel, except: [div: 2, to_string: 1]
import ExAdmin.ViewHelpers
use Xain
_ = var!(conn)
markup safe: true do
unquote(block)
end
end
end
end
Which is used like that:
content do
# Whatever code
end
How can I pass the conn variable to the content block?
content do
IO.inspect(conn)
end
Can’t make it work. 
Thanks
Marked As Solved
LostKobrakai
defmodule TestXain do
defmacro content(do: block) do
block =
quote do
_ = var!(conn)
import Kernel, except: [div: 2, to_string: 1]
use Xain
markup safe: true do
unquote(block)
end
end
quote location: :keep do
def page_view(var!(conn)), do: unquote(block)
end
end
end
defmodule TestXain.View do
import TestXain
content do
IO.inspect(conn)
end
end
iex(1)> TestXain.View.page_view(1)
1
{:safe, "1"}
This seems to work fine for me and circumvents the whole problem of unquote fragments.
Also Liked
LostKobrakai
See my last paragraph here: I don't understand quote/unquote: why do we need them?
More on unquote fragments: https://hexdocs.pm/elixir/Kernel.SpecialForms.html#quote/2-binding-and-unquote-fragments
LostKobrakai
You could build the macro to be called like that:
content(conn) do
IO.inspect(conn)
end
or
content conn do
IO.inspect(conn)
end
I’d not jump to unhygienic variables without a good reason.
OvermindDL1
I personally prefer something like:
content do
conn -> IO.inspect(conn)
end
You can either decompose it to grab the head as the var, or just use it as a case context with full matching and all, which is also so easy to do in quotes. ![]()
LostKobrakai
Using var! makes the variable unhygienic, so it bleeds into the inner blocks scope. If you consider the resulting AST you’ll notice, that the inner block just refers to a variable like this {:conn, [], Some.Module}, where the last part is the context of the variable. var! makes it so that the contexts match, while without that they won’t.
The resulting AST doesn’t really care if it came out of a macro or not. With it it looks like you wrote:
def page_view(conn) do
import Kernel, except: [div: 2, to_string: 1]
import ExAdmin.ViewHelpers
use Xain
_ = conn
markup safe: true do
IO.inspect(conn)
end
end
Which is obviously fine code.
silviurosu
I like very much your idea. Can you give an example how can I write a macro like this?
I would like to be able to call it like this:
wrap_with_connection do
channel -> publish_on_existing_channel(channel, @exchange, @outcome_routing_key, outcome_payload)
end
I can not figure out how to write the macro. What I have by now is:
defmodule Example do
def init_rabbitmq_channel do
...
end
def close_rabbitmq_channel(channel) do
....
end
def publish_on_existing_channel(channel, exchange, routing_key, payload) do
.....
end
defmacro wrap_with_connection(do: block) do
quote do
var!(channel) = init_rabbitmq_channel()
unquote(block)
close_rabbitmq_channel(channel)
end
end
end







