我正面临一个让我疯狂的奇怪问题。
我正在尝试构建这样的DSL:
amazon_query do
list "Items", "//Items/Items" do
field :asin, "./ASIN/text()", :string
field :detail_page, "./DetailPage/text()", :string
end
end
我正在关注Chris McCord编写的Metaprogramming Elixir一书的类似例子,它使DSL能够解析HTML标签。该示例使用AgentServer来保存状态。
所以我目前的宏是:
defmacro amazon_query(do: inner) do
quote do
{:ok, var!(buffer, __MODULE__)} = start_buffer([])
unquote(inner)
result = get_result(var!(buffer, __MODULE__))
stop_buffer(var!(buffer, __MODULE__))
result
end
end
defmacro list(name, xpath, do: inner) do
quote do
unquote(inner)
element_sigil = unquote(xpath)
element_name = unquote(name)
element =[{String.to_atom(element_name), ~x(#{element_sigil})l}]
put_buffer var!(buffer, __MODULE__), element
end
end
defmacro field(name, xpath, :string) when is_atom(name) do
quote do
element = { unquote(name), ~x(#{unquote(xpath)})s }
put_buffer(var!(buffer, __MODULE__), element) # This line raises the error
end
end
我有这个测试:
test "Field and element are processed" do
query =
amazon_query do
list "Items", "//Items/Items" do
field(:asin, "./ASIN/text()", :string)
field(:detail_page, "./DetailPage/text()", :string)
end
end
assert query == []
end
这是我收到的错误:
== Compilation error in file test/get_amazon_query_generator_test.exs ==
** (CompileError) test/get_amazon_query_generator_test.exs:45: expected "buffer" (context GetAmazon.Xml.QueryGeneratorTests) to expand to an existing variable or be part of a match
(elixir) expanding macro: Kernel.var!/2
test/get_amazon_query_generator_test.exs:45: GetAmazon.Xml.QueryGeneratorTests."test Field is processed"/1
(get_amazon) expanding macro: GetAmazon.Xml.QueryGenerator.field/3
test/get_amazon_query_generator_test.exs:45: GetAmazon.Xml.QueryGeneratorTests."test Field is processed"/1
(elixir) lib/code.ex:677: Code.require_file/2
(elixir) lib/kernel/parallel_compiler.ex:201: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6
我做错了什么?任何帮助将不胜感激