quoteブロックに値を注入する方法
- unquote関数を使う
- バインディングを使う
バインディング:
- 変数名と値のキーワードリスト
- quoteにバインディングを渡すとquoteのボディの中の変数が設定される
goh@goh% iex macros/macro_no_bindin_prep.exs
Erlang/OTP 21 [erts-10.1.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]
some_nameマクロはコンパイル時に実行される
マクロが呼ばれた時点では、 each の繰り返しは実行されていないため、渡すべき値がない
goh@goh% iex macros/macro_no_binding.exs
Erlang/OTP 21 [erts-10.1.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]
** (CompileError) macros/macro_no_binding.exs:11: invalid syntax in def x1()
(elixir) lib/enum.ex:765: Enum."-each/2-lists^foreach/1-0-"/2
(elixir) lib/enum.ex:765: Enum.each/2
macros/macro_no_binding.exs:11: (module)バインディングの効果
nameの現在の値をquoteブロックで利用可能になる
内部表現はキーワードリストになっているので、nameのキー:nameを指定してnameの値を取り出しているbind_quoted:により、unquoteの実行が遅延される
bind_quotedはquoteされた(内部表現化された)コード片を取る
goh@goh% iex macros/macro_binding.exs
Erlang/OTP 21 [erts-10.1.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [dtrace]
fred`Macro.escape(expr, opts)
- expr: 式
- opts: オプション
再帰的に値をエスケープする
これにより抽象構文木に挿入可能になる
Kernel.SpecialForms.quote/2 との違いは「変数に格納された値」の処理の仕方
> value = {:a, :b, :c}
{:a, :b, :c}
> Macro.escape(value)
{:{}, [], [:a, :b, :c]}
> quote do: value
{:value, [], Elixir}
> quote do: unquote(value)
{:a, :b, :c}