Elixirのマクロで普通にできたので書きます。
はじめに
Elixirはモジュール内で以下のようにしてマクロで関数を定義できます。
defmodule Sample do
def unquote(:hoge)() do
unquote(1)
end
end
iex(1)> Sample.hoge()
1
どうも、
def unquote(シンボル)() do
unquote(式)
end
という処理が走っていればOKのようです。
Enum.each
で複数定義してみる
defmodule Sample do
[a: 1, b: 2, c: 3]
|> Enum.each(fn {sym, num} ->
def unquote(sym) do
unquoite(num)
end
end)
end
iex(1)> Sample.a()
1
iex(1)> Sample.b()
2
iex(1)> Sample.c()
3
ドキュメンテーション
次はドキュメンテーション込みで生成してみましょう。
exsファイルだとドキュメントがコンパイルされないようなので、mix new sample
でもしてからiex -S mix
すると楽だと思います。
defmodule Sample do
[a: 1, b: 2, c: 3]
|> Enum.each(fn {sym, num} ->
@doc ~s"""
#{sym} returns #{num}.
"""
def unquote(sym) do
unquoite(num)
end
end)
end
iex(1)> h Sample.a()
a returns 1.
iex(2)> h Sample.b()
b returns 2.
iex(3)> h Sample.c()
c returns 3.
いい感じです。
Typespecs
続いてtypespec
defmodule Sample do
[a: 1, b: 2, c: 3]
|> Enum.each(fn {sym, num} ->
@doc ~s"""
#{sym} returns #{num}.
"""
@spec unquote(unit)() :: number
def unquote(sym) do
unquoite(num)
end
end)
end
iex(1)> s Sample.a
@spec a() :: number()
iex(2)> s Sample.b
@spec b() :: number()
iex(3)> s Sample.c
@spec c() :: number()
いい感じです。ex_doc
を入れてmix docs
すればナイスなドキュメンテーションとtypespecが生成されることでしょう。