Elixirのdefmacro内のコードには__MODULE__
というマクロが頻出しますが、これが「マクロが定義されているモジュール」を指しているのか、それとも「マクロを呼び出しているモジュール」を指しているのか、ちょっと分かりにくいので下記のように実験してみました。
defmodule A do
defmacro __using__(_opts) do
IO.inspect "__MODULE__ = #{__MODULE__}"
IO.inspect "unquote(__MODULE__) = #{unquote(__MODULE__)}"
quote do
IO.inspect "__MODULE__ = #{__MODULE__}"
IO.inspect "unquote(__MODULE__) = #{unquote(__MODULE__)}"
@before_compile unquote(__MODULE__)
end
end
defmacro __before_compile__(env) do
IO.inspect "env.module == #{env.module}"
end
end
defmodule B do
use A
end
iex上での実行結果は下記のようになります。
"__MODULE__ = Elixir.A"
"unquote(__MODULE__) = Elixir.A"
"__MODULE__ = Elixir.B"
"unquote(__MODULE__) = Elixir.A"
"env.module == Elixir.B"
要するに、defmacro内のquote式内で__MODULE__
と書いた場合のみ呼び出し側のモジュールが参照され、それ以外の場合はマクロが定義されているモジュールが参照される、ということになるようです。
attributeを操作する関数(Module.register_attribute
等)を使う場合は「呼び出し側のモジュール」を参照する必要がありますが、それ以外は基本的に「マクロが定義されているモジュール」を参照するケースの方が多いと思いますので、「基本的にはunquote(__MODULE__)を使う、attributeを操作するときだけ__MODULE__を使う」というような覚え方でも良さそうな印象です。