在__using__内定义另一个宏

时间:2018-10-30 13:52:08

标签: macros elixir

我有一个名为Interfaces的模块:

defmodule Interfaces do
  defmacro __using__(module) do
    @module unquote(module) |> List.first |> elem(1)
    defmacro expose(name) do
      IO.inspect params, label: "Expanding macro with: "
      IO.inspect @module, label: "I need this !!"

      def unquote(name)() do
        IO.puts "The function has been created with exposed name"
      end
    end
  end
end

另一个名为Interfaces.MyModule的模块:

defmodule Interfaces.MyModule do
  use Interfaces, for: Something.DefinedElseWhere

  expose :plop
end

但是在编译时我得到了

** (CompileError) lib/my_module.ex:6: undefined function expose/1

1 个答案:

答案 0 :(得分:1)

我强烈建议您阅读Elixir官方网站上的Macros Guide。尽管您正在做的事情是可能的(使用quote),但完全不鼓励这样做。

宏应该很简单,如果需要的话,应该在其他宏和方法中进一步细分其功能。 一种实现方法是在宏中使用import语句,以导入需要在最终模块中公开的其他宏:

defmodule Interface do
  defmacro __using__(opts) do
    quote(bind_quoted: [opts: opts]) do
      import Interface

      @interface_module Keyword.get(opts, :for)
    end
  end

  defmacro expose(name) do
    quote do
      IO.inspect @interface_module, label: "I need this !!"

      def unquote(name)() do
        IO.puts "The function has been created with exposed name"
      end
    end
  end
end

现在您可以使用它了:

defmodule MyImplementation do
  use Interface, for: AnotherModule

  expose(:hello)
end

这是我的一个项目中的another example,内容涉及如何使用辅助函数和其他宏来分解大型宏的实现。