How can I `def render(assigns)` in a macro? ~H can't see `assigns` variable

I am trying to define a macro that defines a render(assigns) function but the compiler keeps rejecting the sigil, claiming that no assigns variable exists.

~H requires a variable named "assigns" to exist and be set to a map

Here is a reduction of the code:

defmodule X do
  defmacro __using__(opts) do
    quote do
      def render(assigns) do
        ~H"""
        <div>Hello from the macro</div>
        """
      end
    end
  end
end

defmodule Web.Test do
  use Web :live_view
  use X

  @impl true
  def mount(params, _session, socket) do
    {:ok, socket}
  end

  # render provided by macro
end

I assume that perhaps the actual variable name is getting “unique’d” in the macro, so maybe def render(assigns) becomes def render(__safe_no_collide_assigns_1) for example. I tried using Macro.var but couldn’t figure quite how to make it work.

Is this possible to do?

1 Like

I have to use var!(assigns)

def render(var!(assigns)) do
...
end

I had been trying to unquote and Macro.var, but var! is in the Kernel:

https://hexdocs.pm/elixir/Kernel.html#var!/2

6 Likes

This is not working for me. It complains:

error: undefined variable "assigns" (context Web.LiveStateRecovery)

Here’s my code:

defmodule Web.LiveStateRecovery do

  defmacro __using__(opts \\ []) do
    quote do
      @live_state_recovery unquote(opts)

      def live_state_recovery(var!(assigns)) do
        state = Map.take(assigns, @live_state_recovery)
        |> :erlang.term_to_binary()
        |> Base.encode64()
        
        assigns = assign(assigns, :state, state)

        ~H"""
        <form id="live-state-recovery" phx-change="live-state-recovery" class="hidden">
          <input name="state" value={@state} />
        </form>
        """
      end

      def handle_event("live-state-recovery", %{"state" => state}, socket) do
        state = Base.decode64!(state) |> :erlang.binary_to_term()
        {:noreply, assign(socket, state)}
      end
    end
  end

end

Any ideas? Thanks for the help!