【问题标题】:Elixir macro rewriting module methods and global __using__ macroElixir 宏重写模块方法和全局 __using__ 宏
【发布时间】:2017-08-13 06:11:50
【问题描述】:

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

除此之外,有没有一种方法可以将宏应用于多个模块,而无需将use XXX 显式添加到每个模块。换句话说,如果我有一个文件夹结构:

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

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

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

【问题讨论】:

    标签: macros elixir


    【解决方案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 宏的顶部留下了一些打印语句。您可以使用它来检查新 def 宏的输入的 AST。

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

    我还没有想到一次自动将use 应用于多个模块的想法。如果我想到什么,我会回来更新这个。

    【讨论】:

    • 嗨,史蒂夫,感谢您的回复,我知道我可以重新定义 def。我真正要问的是是否可以不必显式添加使用。如果我只是说给定一个目录可能会更容易,我可以挂钩到编译器以更改目录中的所有模块,而无需显式调用 using 或模块代码本身中的任何宏。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-25
    • 1970-01-01
    • 1970-01-01
    • 2017-01-22
    • 1970-01-01
    • 2016-05-05
    • 2020-05-25
    相关资源
    最近更新 更多