使用模块注释作为方法属性
Using module annotations as method attributes
所以这是一个有趣的问题,我查看了 elixir 中模块属性的文档,即底部的 http://elixir-lang.org/getting-started/module-attributes.html 它提到它们可以用作 ExUnit 中的方法注释。
不幸的是,基本上没有关于如何实现这一点的信息,查看 ExUnit 代码让我迷路了。似乎我需要确定最接近属性的方法来说明它们以某种方式关联(尽管可能是错误的)。
知道我可以从哪里了解这方面的信息吗?
它是这样工作的。查看ExUnit.Case.
的源代码
首先,查看 __using__
宏,因为当您在测试用例中使用它时,它会首先被调用。特别注意 here
Enum.each [:ex_unit_tests, :tag, :describetag, :moduletag, :ex_unit_registered],
&Module.register_attribute(__MODULE__, &1, accumulate: true)
这会注册 @tag
和更多的属性。阅读 Module.register_attribute/3 的文档,您会发现这意味着任何时候调用属性时,该值都会附加到先前属性的列表中。
然后记下 test/3
宏,特别是 here
quote bind_quoted: [var: var, contents: contents, message: message] do
name = ExUnit.Case.register_test(__ENV__, :test, message, [])
def unquote(name)(unquote(var)), do: unquote(contents)
end
注意对 ExUnit.Case.register_test/4
的调用。在看,特地here
tag = Module.delete_attribute(mod, :tag)
它获取到这里的标签,然后删除它们。通过拥有标签和测试名称,它调用 (here)
test = %ExUnit.Test{name: name, case: mod, tags: tags}
Module.put_attribute(mod, :ex_unit_tests, test)
它将测试连同标签一起保存在另一个属性中。
最后,请注意这里
@doc false
defmacro __before_compile__(_) do
quote do
def __ex_unit__(:case) do
%ExUnit.TestCase{name: __MODULE__, tests: @ex_unit_tests}
end
end
end
函数__ex_unit__/1
在ExUnit.Runner.run_case/3中被调用以获取每个案例中的测试信息。
你明白了吗?使用一个累积的属性,在你的宏中调用一个函数,它总是获取属性的当前值并清除它,然后用这个值做任何你想做的事情,因为你知道它总是在调用宏时使用。
我希望已经足够清楚了,如果您需要更多解释,请发表评论。
PS。我只是阅读源代码来找出这一点。很高兴知道它是如何工作的。
所以这是一个有趣的问题,我查看了 elixir 中模块属性的文档,即底部的 http://elixir-lang.org/getting-started/module-attributes.html 它提到它们可以用作 ExUnit 中的方法注释。
不幸的是,基本上没有关于如何实现这一点的信息,查看 ExUnit 代码让我迷路了。似乎我需要确定最接近属性的方法来说明它们以某种方式关联(尽管可能是错误的)。
知道我可以从哪里了解这方面的信息吗?
它是这样工作的。查看ExUnit.Case.
的源代码首先,查看 __using__
宏,因为当您在测试用例中使用它时,它会首先被调用。特别注意 here
Enum.each [:ex_unit_tests, :tag, :describetag, :moduletag, :ex_unit_registered],
&Module.register_attribute(__MODULE__, &1, accumulate: true)
这会注册 @tag
和更多的属性。阅读 Module.register_attribute/3 的文档,您会发现这意味着任何时候调用属性时,该值都会附加到先前属性的列表中。
然后记下 test/3
宏,特别是 here
quote bind_quoted: [var: var, contents: contents, message: message] do
name = ExUnit.Case.register_test(__ENV__, :test, message, [])
def unquote(name)(unquote(var)), do: unquote(contents)
end
注意对 ExUnit.Case.register_test/4
的调用。在看,特地here
tag = Module.delete_attribute(mod, :tag)
它获取到这里的标签,然后删除它们。通过拥有标签和测试名称,它调用 (here)
test = %ExUnit.Test{name: name, case: mod, tags: tags}
Module.put_attribute(mod, :ex_unit_tests, test)
它将测试连同标签一起保存在另一个属性中。
最后,请注意这里
@doc false
defmacro __before_compile__(_) do
quote do
def __ex_unit__(:case) do
%ExUnit.TestCase{name: __MODULE__, tests: @ex_unit_tests}
end
end
end
函数__ex_unit__/1
在ExUnit.Runner.run_case/3中被调用以获取每个案例中的测试信息。
你明白了吗?使用一个累积的属性,在你的宏中调用一个函数,它总是获取属性的当前值并清除它,然后用这个值做任何你想做的事情,因为你知道它总是在调用宏时使用。
我希望已经足够清楚了,如果您需要更多解释,请发表评论。
PS。我只是阅读源代码来找出这一点。很高兴知道它是如何工作的。