Edited at
ElixirDay 24

マクロを使ってドキュメントやtypespecsを生成する

More than 1 year has passed since last update.

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が生成されることでしょう。