Eixir 元编程 - 在编译时从宏中定义可用的宏

Eixir metaprogramming - defining macro available at compile time from within macro

我正在研究 Elixir 元编程,并且正在尝试制作一个允许我定义 REST 资源的 macro。界面将是这样的:

defmodule Router do
  use Resources

  resource "cars"
  resource "animals"
end

我已经使用 Module 模块定义了模块属性,但我无法使以下内容起作用:

defmodule Resource do
  defmacro __using__(_opts) do
    quote do
      Module.put_attribute __MODULE__, :stack, [1, 2, 3]
      defmacro resource(name) do
        stack = Module.get_attribute __MODULE__, :stack
        Module.put_attribute __MODULE__, :stack, [name|stack]
      end
    end
  end
end

以下不编译:

defmodule Domain  do
  use Resource

  resource "foo"

  def run do
    IO.inspect @stack
  end
end

如果我删除资源行,它会正确打印 [1, 2, 3]

resource/1 宏在 run/0 中可见。

如何让路由器中的代码工作,以便调用资源 "xxx" 将 "xxx" 推送到 @stack 模块属性上的堆栈?

您需要单独定义第二个 Macro,而不是在 __using__ 宏中。您可以将第一个宏用于 import 资源并定义初始 @stack,这样您就可以在您的模块中使用 resource 宏。

您也不需要调用 Module.get_attributeModule.put_attribute,只需在任何地方使用 @stack

试试这个:

defmodule Resource do
  defmacro __using__(_opts) do
    quote do
      import Resource
      @stack [1,2,3]
    end
  end

  defmacro resource(name) do
    quote do
      @stack [unquote(name) | @stack]
    end
  end
end

调用 Domain.run 现在应该给你 ["foo", 1, 2, 3]。您还应该阅读有关在 Elixir 中构建您自己的 Domain Specific Languages 的官方指南。