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_attribute
和 Module.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 的官方指南。
我正在研究 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_attribute
和 Module.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 的官方指南。