マクロで関数を定義する
Elixirでは, 関数を定義しているマクロを呼び出すことで, その関数を呼び出し元の関数として定義することができます.
つまり
defmodule MyMacro do
defmacro __using__(opts) do
quote do
def hello() do
IO.puts "Hello from macro"
end
end
end
end
こんな感じのモジュールを用意し
defmodule UseMacro do
use MyMacro
end
このように別のUseMacroモジュールでuseしてやることとで, マクロ内で定義されたhelloをUseMacroモジュールの関数として定義することができるわけです.
iex(3)> UseMacro.hello
UseMacro.hello
Hello from macro
:ok
関数をオーバライドする
しかし, この方法で定義される関数の一部だけを別処理に変えたい場合があるかもしれません。
関数を定義しているマクロの方に直接手をいれることができるならば, 何も悩むことはなくマクロの方を修正すればいいのですが,
そうでない場合は, 以下のように同じシグニチャを持つ関数を__マクロを呼び出す前に__定義してやることで,
オーバライドすることができるようです.
defmodule UseMacro do
def hello() do
IO.puts "Hello from module"
end
use MyMacro
end
iex(2)> c("/home/vagrant/phoenix_sample/lib/use_macro.ex")
use_macro.ex:7: warning: this clause cannot match because a previous clause at line 3 always matches
[UseMacro]
iex(3)> UseMacro.hello
UseMacro.hello
Hello from module #<--- モジュールで定義された関数が呼び出されている
:ok
もっとも, この方法はあくまでハックなので, ライブラリの更新などで動かなくなって悲しみを背負う覚悟の元で使用してください:P