如何根据属性为elixir定义函数?

时间:2016-05-06 08:42:32

标签: metaprogramming elixir phoenix-framework ecto

我们说我有一个模块SilentDefiner。我想基于其属性为Silent定义几个函数。让我解释一下:

defmodule Silent do
  @function_names [:a, :b, :c]

  use Definer
end

defmodule Definer do
  defmacro __using__(_) do
    quote do
      Enum.each(@function_names, fn(n) ->
        def unquote(n)() do # line 5
          IO.puts "a new method is here!"
        end
      end)
    end
  end
end

但这种方法实际上并不起作用,因为我有undefined function n/0 on line 5。如何实现所需的功能?

1 个答案:

答案 0 :(得分:1)

您需要将unquote: false传递到quote中的Definer.__using__/1才能在unquote内注入quote个片段。

defmodule Definer do
  defmacro __using__(_) do
    quote unquote: false do
      Enum.each(@function_names, fn(n) ->
        def unquote(n)() do # line 5
          IO.puts "a new method is here!"
        end
      end)
    end
  end
end

defmodule Silent do
  @function_names [:a, :b, :c]

  use Definer
end

Silent.a
Silent.b
Silent.c

打印

a new method is here!
a new method is here!
a new method is here!

Kernel.SpecialForms.quote/2 docs中详细记录了类似的案例,如果您想要将一些变量注入bind_quoted并创建quote,则会提及如何使用unquote片段。