I’m trying to invoke a private macro, within a quote block, using a variable defined within the code block itself.
Notice that the variable doesn’t need to be evaluated, I’m thinking of the macro in terms of search-and-replace:
Find the debug keyword, replace it with IO.puts(my)
This is the pseudo-code showing what I would like to do (doesn’t work)
defmodule Foo do
defmacrop debug(msg) do
quote bind_quoted: [msg: msg], do: IO.puts(msg)
end
defmacro __using__(_) do
quote do
def hello do
my = "testme"
unquote(debug(quote do: my))
end
end
end
end
defmodule Bar do
use Foo
end
Bar.hello()
And the end result would be pretty simple:
defmodule Bar do
def hello do
my = "testme"
IO.puts(my)
end
end
The usual way I would expect this to be done is as follows
defmodule Foo do
defmacro debug(msg) do
quote do
IO.puts(unquote(msg))
end
end
defmacro __using__(_) do
quote do
def hello do
my = "testme"
Foo.debug(my)
end
end
end
end
defmodule Bar do
use Foo
end
Bar.hello()
You will note that the debug macro is not private. The reason is simple, the Foo.__using__ macro in this case is being used to write a function in the Bar module: Bar.hello. For a function in Bar to call a macro (or function) in Foo that function must be public.
Mhhh that’s very different result though. My purpose was to actually keep the macro private because it’s an internal utility of the module itself. I’m strictly looking for a way to do it with a private macro that is not included in the module “using” the other one (to avoid overlapping names).
Thanks for the suggestion though. I’ll consider it
If the macro is private to Foo then it can only ever be called from functions or other macros that are also in Foo - the very definition of private.
The concept of “a private macro that is not included in the module using the other one” simply does not make sense. To call a private macro from Bar the macro will have to be defined in Bar.
Overall, in my opinion, it looks like you are trying to replicate the object oriented constructs of public, protected, and private inheritance which suggests to me that you’re going about things the wrong way.
Perhaps if you offered more details about what you are trying to accomplish?
For note, don’t make debug/1 be a macro, you are already in a macro context and you are wanting to inject AST, not the result of such AST:
defmodule Foo do
defp debug(msg) do
quote bind_quoted: [msg: msg], do: IO.puts(msg)
end
defmacro __using__(_) do
quote do
def hello do
my = "testme"
unquote(debug(quote do: my))
end
end
end
end
defmodule Bar do
use Foo
end
Bar.hello()