我目前正在尝试
use
我自己的模块中的 Interceptor 库。为此,我需要提供一个配置参数。此参数由一个映射组成,其中键是字符串,表示必须拦截哪些模块的哪些功能,值由一个列表组成,其中包含有关应如何进行拦截的信息。我专门在寻找钥匙方面的帮助。
正如我所解释的,我的键是代表要拦截的函数的字符串。它们的格式如下:
moduleName.functionName/arity
。当只是硬编码这个字符串时,一切正常。但是,我希望能够动态地形成这个字符串。更具体地说,我想动态填写模块名称。这样做的原因是我想在稍后阶段使用宏注入这段代码,然后我不会事先知道模块。我将能够事先知道和硬编码的功能名称和数量。
我的代码目前如下所示:
use Interceptor, config: %{
String.slice(to_string(__MODULE__), 7..-1) <> ".someFunction/2" => [
before: "SpecialInterceptor.intercept_before/1",
after: "SpecialInterceptor.intercept_after/2"
]
}
注意,我之所以对字符串进行切片是因为
__MODULE__
在模块名称前加上“Elixir”。例如,Elixir.ModuleName
。因此,我需要将那部分切片。
当我在我的模块中使用此代码片段来设置拦截器时,它不起作用。代码运行没有错误,但没有任何内容被拦截。当我将
String.slice(to_string(__MODULE__), 7..-1) <> ".someFunction/2"
替换为 "SomeModule" <> ".someFunction/2"
时,它确实有效。
我希望有人能指出我在这里做错了什么。
首先,人们不会做
String.slice/2
来获取模块名称作为字符串,而是Kernel.inspect/2
。
inspect(String)
#⇒ "String"
Function.capture/3
Function.capture(String, :length, 1) |> inspect
#⇒"&String.length/1"
最后但同样重要的是,
use/2
是 __using__/2
的语法糖,它是一个宏,其参数中的远程调用作为 AST 传递给它的实现。但是宏可以从上下文扩展模块参数,这在这种情况下会有所帮助。
就是说,正确的代码应该与以下代码并列。
@config %{
inspect(Function.capture(__MODULE__, :some_function, 2)) => […]
}
use Interceptor, config: @config
旁注: 我打赌你实际上不需要对捕获进行字符串化。