Reputation: 531
I'm currently learning/reading metaprogramming elixir
I managed to generate a function that puts it's name using macros:
defmodule MyMacros do
defmacro fun_gen(name) do
atom_name = elem(name, 0)
str_name = atom_name |> to_string
quote do
def unquote(name) do
IO.puts unquote(str_name)
end
end
end
end
defmodule My do
require MyMacros
MyMacros.fun_gen(bar)
end
the result:
iex(1)> My.bar
bar
:ok
so this is great :) but I was wondering if it was possible to generate several functions using a Enum.each or something like that:
defmodule MyMacros do
defmacro fun_gen(name) do
atom_name = elem(name, 0)
str_name = atom_name |> to_string
quote do
def unquote(name) do
IO.puts unquote(str_name)
end
end
end
end
defmodule My do
require MyMacros
loop (~w(foo bar baz) do
MyMacros.fun_gen(item)
end
end
Is there a way of looping in order to generate source code ? Thank you !
Upvotes: 2
Views: 964
Reputation: 12085
You could do it without using macros at all:
defmodule My do
@methods ~w|one two three|a
for method <- @methods do
def unquote(method)() do
IO.puts unquote(method)
end
end
end
produces:
iex> My.one
one
iex> My.two
two
Or with a macro:
defmodule MyMacros do
defmacro gen_funs(names) do
for name <- names do
quote do
def unquote(name)() do
IO.puts unquote(name)
end
end
end
end
end
defmodule My2 do
require MyMacros
MyMacros.gen_funs([:one, :two, :three])
end
produces:
iex> My2.one
one
iex> My2.two
two
Note: We are passing the list directly to gen_funs
rather than a sigil or a variable containing the list. We must do this since macros receive their arguments quoted. This is why you must do the looping in the macro rather than the module using the macro.
Upvotes: 4