我正在研究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
宏。
我怎样才能让Router中的代码工作,以便调用资源“xxx”将“xxx”推送到@stack
模块属性的堆栈?
答案 0 :(得分:1)
您需要单独定义第二个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的官方指南。