1
votes

With elixir's __using__ macro and with the aid of __on_definition__ I can keep track of all methods in a module. What I would like to do is replace all methods in a module with some other implementation. Now it's fairly trivial to create the new methods I want but I also want to remove the existing methods.

Additionally to this, is there a way to apply a macro to several modules without explicitly adding the use XXX to each module. In otherwords if I have a folder structure:

  • foo/
    • bar/
      • module1.ex
      • module2.ex

Could I dynamically apply the using macro to everything in ./foo/bar/.

To simplify my problem, imagine that for all methods in all modules in the foo/bar/ folder I want to change there implementation so that they will first run IO.inspect "called before method", aka some kind of before method aop.

1

1 Answers

2
votes

def is just a macro from Kernel. So you could exclude it with import Kernel, except: [def: 2] and then create you def. Here is something that almost works, except for the return value.

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

Running in 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)>

I left some print statement at the top of the custom def macro. You can use this to examine the AST of the inputs to the new def macro.

You can find more information in the Kernel source code.

I have not thought of an idea to automatically apply the use to multiple modules at once. I'm come back and update this if I think of anything.