# Using \`~p\` dynamically inside a macro

**URL:** <https://forum.elixirforum.com/t/using-p-dynamically-inside-a-macro/56707>\
**Category:** Questions\
**Tags:** phoenix, macro, verified-routes\
**Created:** [June 26, 2023, 2:45pm UTC](https://forum.elixirforum.com/t/using-p-dynamically-inside-a-macro/56707 "2023-06-26T14:45:51Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![sodapopcan](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/32/34668_2.png) [@sodapopcan](https://forum.elixirforum.com/u/sodapopcan)\
**Post date:** [June 26, 2023, 2:45pm UTC](https://forum.elixirforum.com/t/using-p-dynamically-inside-a-macro/56707/1 "2023-06-26T14:45:51Z")

</div>

I’m having a bit of trouble wrapping my brain around how I would pass a dynamic fragment to `~p` inside a macro:

```elixir
defmacro __using__ (opts) do
  @path opts.path

  quote do
    def handle_event("event", _, socket) do
        path = ~p"/#{@path}"

        # ...
        {:noreply, socket}
    end
  end
end

```

I’ve tried a fair number of functions from the `Macro` module both inside, namely `escape` and `expand`/`expand_once` which are the ones I though would do it as well as `unquote` (and even `quote` for good measure). I understand that passing an argument to the `~p` macro is going to `quote` it and when it’s called already inside a `quote` block, well, uh… oh boy 😵‍💫 As I have it does produce the correct route but of course gives a console warning. I feel like this question must have been answered before but I can’t find it and my brain hurts. At the very least I’m treating this forum as a rubber duck but any help would be much appreciated.

---

<div class="post-metadata">

**Author:** ![0xG](https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/0/b782af/32.png) [@0xG](https://forum.elixirforum.com/u/0xG)\
**Post date:** [June 26, 2023, 4:12pm UTC](https://forum.elixirforum.com/t/using-p-dynamically-inside-a-macro/56707/2 "2023-06-26T16:12:35Z")

</div>

There is some macro confusion here.

This changed version compiles:

```elixir
defmodule A do
  defmacro __using__ (opts) do
    path = opts.path
  
    quote do
      def handle_event("event", _, socket) do
          path = ~p"/#{unquote(path)}"
  
          # ...
          {:noreply, socket}
      end
    end
  end
end

```

But there is one more problem.  
Since you are using dot syntax, I assume you’re trying to pass a map. Instead use a keyword. IIRC, keywords are not escaped:

```elixir
defmodule A do
  defmacro __using__ (opts) do
    path = opts[:path]
  
    quote do
      def handle_event("event", _, socket) do
          path = ~p"/#{unquote(path)}"
  
          # ...
          {:noreply, socket}
      end
    end
  end
end

defmodule B do
  use A, path: "my-path"
end

```

---

<div class="post-metadata">

**Author:** ![sodapopcan](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/32/34668_2.png) [@sodapopcan](https://forum.elixirforum.com/u/sodapopcan)\
**Post date:** [June 26, 2023, 4:35pm UTC](https://forum.elixirforum.com/t/using-p-dynamically-inside-a-macro/56707/3 "2023-06-26T16:35:16Z")

</div>

Hey hey, thanks for the response and welcome to the forum!

I’ve tried your suggestions and I’m still getting the warning. Are you seeing it? Maybe I messed up still. My problem was never that it didn’t compile—it compiled and produced the correct path, but it failed to be verified. The warning is `no route path for MyAppWeb.Router matches "/#{"some-path"}"` so I need to be able to pass the `~p` macro and already expanded variable… which is what I’m having a hard time wrapping my head around.

---

<div class="post-metadata">

**Author:** ![LostKobrakai](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lostkobrakai/32/3072_2.png) [@LostKobrakai](https://forum.elixirforum.com/u/LostKobrakai)\
**Post date:** [June 26, 2023, 4:44pm UTC](https://forum.elixirforum.com/t/using-p-dynamically-inside-a-macro/56707/4 "2023-06-26T16:44:03Z")

</div>

> [@sodapopcan](#):
>
> no route path for MyAppWeb.Router matches “/#{“some-path”}”

That’s likely the clue here. The compile time validation doesn’t see `~p"/some-path"`, but `~p"/#{"some-path"}"`. Evaluate both and it’ll be the same, but their AST/the code isn’t. The latter is not using a static string, even if the dynamic input takes a static value.

You likely want this: `path = sigil_p(unquote("/#{path}"))` – build the static path before unquoting the result into the sigil macro call.

---

<div class="post-metadata">

**Author:** ![0xG](https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/0/b782af/32.png) [@0xG](https://forum.elixirforum.com/u/0xG)\
**Post date:** [June 26, 2023, 7:30pm UTC](https://forum.elixirforum.com/t/using-p-dynamically-inside-a-macro/56707/5 "2023-06-26T19:30:40Z")

</div>

Hmm, I think `sigil_p/2` [pattern matches against ast](https://github.com/phoenixframework/phoenix/blob/3f0dfced31a66edb0932c479e2da51125d1c8e30/lib/phoenix/verified_routes.ex#L202) and unquoting that expression results in fully evaluated binary.

I bet there would be a more intuitive solution but this works:

```ex
defmodule A do
  defmacro __using__ (opts) do
    path = opts[:path]

    quote do
      use Phoenix.Component

      def handle_event("event", _, socket) do
        path = sigil_p(unquote({:<<>>, _meta = [], ["/#{path}"]}), [])

        # ...
        {:noreply, socket}
      end
    end
  end
end

defmodule B do
  use A, path: "my-path"
end

```

```iex
warning: no route path for InformedCMSWeb.Router matches "/my-path"
  iex:112: B.handle_event/3

```

So I passed the simplified version of desired ast:

```iex
iex> quote(do: "/#{path}")
{:<<>>, [],
 [
   "/",
   {:"::", [],
    [
      {{:., [], [Kernel, :to_string]}, [], [{:path, [], Elixir}]},
      {:binary, [], Elixir}
    ]}
 ]}

```

---

<div class="post-metadata">

**Author:** ![sodapopcan](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/32/34668_2.png) [@sodapopcan](https://forum.elixirforum.com/u/sodapopcan)\
**Post date:** [July 4, 2023, 1:53pm UTC](https://forum.elixirforum.com/t/using-p-dynamically-inside-a-macro/56707/6 "2023-07-04T13:53:44Z")

</div>

Thanks for your help, @0xG and @LostKobrakai. I’m ultimately going with a slightly more verbose but more flexible (and less brain-bendy for me) solution. I though I was only going to be dealing with URLs in the form of: `~p/resource/#{resource}` but it turns out that is not the case and don’t want to get too crazy! Thanks again!
