Elixir 将宏作为插件选项传递无法编译
在我的Phoenix应用程序中,我正在使用我编写的几个宏来向日志数据添加一些额外的自定义格式-但是,当我使用使用行为将负责HTTP访问日志记录的宏直接添加到router.ex管道中的插件时,我在使应用程序正确编译方面遇到了一些问题 首先,这里是我尝试使用的宏的简化版本:Elixir 将宏作为插件选项传递无法编译,elixir,phoenix-framework,Elixir,Phoenix Framework,在我的Phoenix应用程序中,我正在使用我编写的几个宏来向日志数据添加一些额外的自定义格式-但是,当我使用使用行为将负责HTTP访问日志记录的宏直接添加到router.ex管道中的插件时,我在使应用程序正确编译方面遇到了一些问题 首先,这里是我尝试使用的宏的简化版本: defmodule MacroTest do defmacro __using__(_) do quote do require Logger defmacro execute(data)
defmodule MacroTest do
defmacro __using__(_) do
quote do
require Logger
defmacro execute(data) do
quote do: Logger.log(:info, unquote(data))
end
end
end
end
在我的router.ex中,我想为Plug.Accesslog提供execute/1宏作为其有趣的选项:
当我像这样编译应用程序时,会出现以下错误:
** (CompileError) web/router.ex:21: undefined function execute/1
(stdlib) lists.erl:1338: :lists.foreach/2
(stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
(elixir) lib/kernel/parallel_compiler.ex:198: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6
但是,我发现,如果我定义了一个helper函数并在那里调用宏,这将起作用:
defmodule MyApp.Router do
use MyApp.Web., :router
use MacroTest
def my_fun(data), do: execute(data)
pipeline :api do
plug Plug.AccessLog,
format: :combined,
formatters: [ Plug.AccessLog.DefaultFormatter ],
fun: &__MODULE__.my_fun/1
end
end
这是我在这里完成所需任务的唯一方法,还是有什么可以更改的方法允许我直接将execute/1传递给插件而不必包装它?如果这是唯一的解决方案,那没什么大不了的,但是如果可能的话,我宁愿避免使用helper函数。虽然我不能真正清楚地解释为什么会发生这种情况,但我确实理解将一个宏传递到另一个宏的潜在编译复杂性
谢谢 您根本不需要宏或包装器,只需插入函数即可: defmodule宏测试do defmacro\uuuu使用 引述 需要记录器 def executedata do 日志:信息,数据 终止 终止 终止 终止 以及: defmodule MyApp.Router do 使用MyApp.Web,:路由器 使用宏测试 管道:api do plug.AccessLog, 格式::组合, 格式化程序:[Plug.AccessLog.DefaultFormatter], 乐趣:&模块执行/1 终止 终止
我认为你可以做fun:fn data->executedata end。这是否有效:fun:&MyApp.Router.execute/1?@Dogbert在这种情况下,应用程序将编译,但一旦调用fun,它就会抛出错误函数MyApp.Router未定义或私有。如果要调用此宏,请参阅Plug.AccessLog,确保需要MyApp.Router。
defmodule MyApp.Router do
use MyApp.Web., :router
use MacroTest
def my_fun(data), do: execute(data)
pipeline :api do
plug Plug.AccessLog,
format: :combined,
formatters: [ Plug.AccessLog.DefaultFormatter ],
fun: &__MODULE__.my_fun/1
end
end