在__before_compile__中调用一个插件什么都不做

时间:2016-12-12 21:08:24

标签: macros elixir metaprogramming

我正试图了解elixir模块的生命周期,我注意到的一件事就是在调用控制器时调用 before_compile 块中的插件宏不执行插件。据我所知,这个块在编译之前就执行了,所以插件宏也会在模块中编译。

对于这个:

  defmacro __before_compile__(env) do
    quote do
     plug :say_hi
    end
  end

使用phoinex控制器中的方法:

def say_hi(conn, _) do
   IO.inspect("hello")
end

这不会打印hello,因为在使用块中具有相同的引用块。我错过了什么?

克里斯

1 个答案:

答案 0 :(得分:1)

Per the relevant documentation on Module and compilation callbacks__before_compile__需要在目标模块中使用@before_compile MyApp.MyModule调用(其中MyApp.MyModule是模块的名称)。

如果您尝试在__before_compile__模块的其他模块中发生use,则可以定义__using__ {{1像这样:

__before_compile__

Sugar web development framework有一个相对简单的现实演示,说明它在控制器代码中是如何工作的;当您在控制器模块中调用defmodule MyApp.MyModule do defmacro __using__(_) do quote do @before_compile MyApp.MyModule end end defmacro __before_compile__(env) do quote do plug :say_hi end end end (例如,use Sugar.Controller)时,将调用MyApp.Controllers.Main宏,从而导致Sugar.Controller.__using__/1在{@before_compile Sugar.Controller的上下文中被调用1}},因此做了一堆幕后插件相关的魔术(主要是实现MyApp.Controllers.Main行为,但这点不在这里)。

菲尼克斯也用它的控制器做类似的事情,虽然有点间接; Phoenix.Controller.Pipeline是这种模式的另一个很好的证明(虽然更复杂)。

在一个不相关的说明中,我得到了非常复杂的结果,让PlugIO.inspect(或IO.puts任何东西(就此而言)实际显示在这种情况下情况。您可能想尝试IO.