elixir - 将宏作为 Plug 选项传递无法编译
问题描述
在我的 Phoenix 应用程序中,我正在使用我编写的几个宏来向日志数据添加一些额外的自定义格式 - 但是,当我使用该use
行为时,我在让应用程序正确编译时遇到了一些麻烦,我添加负责将 HTTP 访问记录直接记录到plug
我router.ex
管道中的 a 的宏。
首先,这是我尝试使用的宏的简化版本:
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
中,我想将execute/1
宏提供给Plug.Accesslog作为其fun
选项:
defmodule MyApp.Router do
use MyApp.Web., :router
use MacroTest
pipeline :api do
plug Plug.AccessLog,
format: :combined,
formatters: [ Plug.AccessLog.DefaultFormatter ],
fun: &execute/1
end
end
当我像这样编译应用程序时,出现以下错误:
** (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
但是,我发现如果我定义一个辅助函数并在那里调用宏,这将起作用:
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
直接传递到plug
而无需包装它?如果这是唯一的解决方案,那没什么大不了的,但如果可能的话,我宁愿避免使用辅助功能。尽管我无法真正阐明为什么会发生这种情况,但我确实很欣赏将宏传递给另一个宏的潜在编译复杂性。
谢谢!
解决方案
您根本不需要宏或包装器,只需注入一个函数:
defmodule MacroTest do
defmacro __using__(_) do
quote do
require Logger
def execute(data) do
Logger.log(:info, data)
end
end
end
end
和:
defmodule MyApp.Router do
use MyApp.Web, :router
use MacroTest
pipeline :api do
plug Plug.AccessLog,
format: :combined,
formatters: [ Plug.AccessLog.DefaultFormatter ],
fun: &__MODULE__.execute/1
end
end
推荐阅读
- javascript - 更改列表中的文本并保留属性
- three.js - AFrame - 更新元素的矩阵
- python - 从 Python 数据框中提取值
- python - 用系列修改多索引切片
- mysql - 带有 MYSQL 后端和非常简单的查询的 Access 中的“操作必须使用可更新的查询”
- angular - FormGroup 返回一个空字符串
- javascript - 记录用户输入(在线)
- kubernetes - jvmkill 无法杀死由 Paketo Java Buildpack 创建的映像中的 JVM
- html - 在光标释放时向后播放 CSS 动画?
- sip - 了解 SIP 中继