I’m trying to write a couple macros that define either a public or private functions. Here’s an example
defmodule Defs do
defmacro mydef(name, do: block) do
quote do
def unquote(name), do: unquote(block)
end
end
defmacro mydefp(name, do: block) do
quote do
defp unquote(name), do: unquote(block)
end
end
end
# Example usage
mydefp hello do
:world
end
Since the functions that are being written are exactly the same except for def
/defp
, I’d like to extract the function writing logic into a common place
defmodule Defs do
defmacro mydef(name, do: block), do: do_def(name, block, :def)
defmacro mydefp(name, do: block), do: do_def(name, block, :defp)
defp do_def(name, block, visibility) do
#What goes here?
end
end
Since def
is just a macro on Kernel
, I rewrote my macros to look like they were writing function calls.
defmodule Defs do
defmacro mydef(name, do: block) do
quote do
Kernel.def(unquote(name), do: unquote(block))
end
end
defmacro mydefp(name, do: block) do
quote do
Kernel.defp(unquote(name), do: unquote(block))
end
end
end
From there, it seemed that I should be able to use apply/3
to dynamically call def
or defp
.
defmodule Defs do
defmacro mydef(name, do: block), do: do_def(name, block, :def)
defmacro mydefp(name, do: block), do: do_def(name, block, :defp)
defp do_def(name, block, visibility)
apply(Kernel, unquote(visibility), [unquote(name), do: unquote(block)])
end
end
However, when I use this macro in a module:
defmodule Greeter do
import Defs
mydef hello do
:world
end
I get the following error:
** (CompileError) iex:3: undefined function hello/0
(stdlib) lists.erl:1354: :lists.mapfoldl/3
(stdlib) lists.erl:1355: :lists.mapfoldl/3
(my_app) expanding macro: Defs.mydef/2
Long question short, how do I dynamically call def
or defp
so I can share the rest of the logic between my macros?