15
11

More than 5 years have passed since last update.

Elixir:マクロで定義された関数をオーバーライドする

Posted at

マクロで関数を定義する

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

15
11
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
11