2

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 !

1 Answer 1

4

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Cool ! Atoms are represented as themself internally that's convenient :) Thank you
@BenNG yep, and lists too! [:one,:two,:three] == quote do: [:one, :two, :three]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.