Edited at

Elixirでコンパイル時にStruct/Mapを生成して埋め込む方法

コンパイル時に外部ファイルなどからデータを取ってきて,それを元にStructなりMapなりを生成して実行ファイルに混ぜ込みたいということがあります.

そういうときは以下のようにすれば良いです:


sample.ex

defmodule Hoge do

defmacro generate_map do
map = File.read!("./sample.json") |> Poison.decode!

Macro.escape(map)
end
end

defmodule Sample1 do
require Hoge

def cached_file do
Hoge.generate_map
end

def main do
IO.inspect(Sample1.cached_file)
end
end


iex(1)> Sample1.main

%{"age" => 34, "name" => "John Smith"}
%{"age" => 34, "name" => "John Smith"}

generate_struct の最後にある Macro.escape(map) がミソで,これによってMapをASTに変換して実行ファイルに埋め込んでいます.

もちろん map = File.read!("./sample.json") |> Poison.decode! の部分には好きな処理を書くことができます.

例えばJSON APIのリクエストを叩いてその結果を埋め込むこともできます:


sample.ex

defmodule Fuga do

defmacro generate_map do
HTTPoison.start
map = HTTPoison.get!("https://jsonplaceholder.typicode.com/todos/1").body |> Poison.decode!

Macro.escape(map)
end
end

defmodule Sample2 do
require Fuga

def cached_http_call do
Fuga.generate_map
end

def main do
IO.inspect(Sample2.cached_http_call)
end
end


iex(1)> Sample2.main

%{
"completed" => false,
"id" => 1,
"title" => "delectus aut autem",
"userId" => 1
}
%{
"completed" => false,
"id" => 1,
"title" => "delectus aut autem",
"userId" => 1
}

参考: https://elixirforum.com/t/understand-macro-escape/405/2