Elixir宏重写模块方法和全局__using__宏

时间:2017-03-21 14:07:28

标签: macros elixir

使用elixir的__using__宏并借助__on_definition__我可以跟踪模块中的所有方法。我想要做的是用一些其他实现替换模块中的所有方法。现在创建我想要的新方法相当简单,但我也想删除现有的方法。

除此之外,有没有办法将宏应用于多个模块,而无需向每个模块明确添加use XXX。换句话说,如果我有文件夹结构:

  • 富/
    • 酒吧/
      • module1.ex
      • module2.ex

我可以动态地将using宏应用于./foo/bar/中的所有内容。

为了简化我的问题,想象一下,对于foo/bar/文件夹中所有模块中的所有方法,我想更改那里的实现,以便它们首先运行IO.inspect "called before method",也就是某种方法之前的aop。

1 个答案:

答案 0 :(得分:1)

def只是来自Kernel的宏。因此,您可以使用import Kernel, except: [def: 2]将其排除,然后创建def。除了返回值之外,这里几乎可以工作。

defmodule Def do
  import Kernel, except: [def: 2]
  defmacro __using__(_) do
    quote do
      import Kernel, except: [def: 2]
    end
  end

  defmacro def(call, expr) do
    # caller = __CALLER__
    # IO.inspect call
    # IO.inspect expr

    # import Kernel
    quote do
      Kernel.def unquote(call) do
        IO.puts "do something first"
        unquote(expr)
      end
    end
  end
end

defmodule Special do
  use Def
  import Def

  def test(one, two) do
    IO.puts "one: #{inspect one}, two: #{inspect two}"
  end
end

在iex中运行

Interactive Elixir (1.4.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Special.test 1, 2
do something first
one: 1, two: 2
[do: :ok]
iex(2)>

我在自定义def宏的顶部留下了一些print语句。您可以使用它来检查新def宏的输入的AST。

您可以在Kernel源代码中找到更多信息。

我没有想过一次将use自动应用于多个模块的想法。如果我想到任何事情,我会回来更新。