志士は溝壑(こうがく)に在るを忘れず、勇士は其の元(かうべ)を喪うことを忘れず
Advent Calendar 2022 131日目1の記事です。
I'm looking forward to 12/25,2022
私のAdvent Calendar 2022 一覧。
はじめに
Elixir を楽しんでいますか
この記事は、Application.compile_env/3をオススメします。
Compile-time environment
もし
defmodule Foo do
@moduledoc """
Documentation for `Foo`.
"""
@world Application.get_env(:foo, :world, "awesome")
def hello do
@world
end
end
と書いてあるところがありましたら、
defmodule Foo do
@moduledoc """
Documentation for `Foo`.
"""
@world Application.compile_env(:foo, :world, "awesome")
def hello do
@world
end
end
と書くようにしましょう。
違いは、@world
の中身の定義の仕方です。
前者はApplication.get_env/3
を、後者はApplication.compile_env/3
を使っています。
ということが、Compile-time environment に書いてあります。
@mnishiguchi さんに教えてもらいました
説明が前後しますが、こういうconfig/config.exs
もセットで置いてあることが多いとおもいます。
import Config
config :foo, :world, "awesome123"
注意事項
注意事項をいくつか書きます。
1.10 or later
Elixirのバージョンは1.10以上から、Application.compile_env/3は使えます。
(RuntimeError) Application.compile_env/3 cannot be called inside functions, only in the module body
defmodule Foo do
def foo do
Application.compile_env(:foo, :world, "awesome")
end
end
上記はコンパイルできません。
この場合は、以下のようにApplication.get_env/3を使います。
defmodule Foo do
def foo do
Application.get_env(:foo, :world, "awesome")
end
end
By using compile_env/3, tools like Mix will store the values used during compilation and compare the compilation values with the runtime values whenever your system starts, raising an error in case they differ.
なにもしていないのに壊れた に近いことが起こるかもしれません。
いや何かしているのです。なにかしているのでERROR!
が発生しているのです。
ERROR! the application :foo has a different value set for key :world during runtime compared to compile time. Since this application environment entry was marked as compile time, this difference can lead to different behaviour than expected:
* Compile time value was set to: "awesome1234"
* Runtime value was set to: "awesome123"
To fix this error, you might:
* Make the runtime value match the compile time one
* Recompile your project. If the misconfigured application is a dependency, you may need to run "mix deps.compile foo --force"
* Alternatively, you can disable this check. If you are using releases, you can set :validate_compile_env to false in your release configuration. If you are using Mix to start your system, you can pass the --no-validate-compile-env flag
** (ErlangError) Erlang error: "aborting boot"
(elixir 1.13.1) Config.Provider.boot/2
上記の:foo
や:world
は適宜読み替えてください。
解決方法は、mix compile --force
とでもすればいいでしょう。
foo
が依存しているHexならmix deps.compile foo --force
です。
発生方法は以下の通りです。
もっと実践的な発生方法がわかりましたら追記します。
defmodule Foo do
@moduledoc """
Documentation for `Foo`.
"""
@world Application.compile_env(:foo, :world, "awesome")
def hello do
@world
end
end
import Config
config :foo, :world, "awesome1234"
config/runtime.exs
はとりあえず空のファイルで大丈夫です。
上記の3ファイルがあるプロジェクトにて
iex -S mix
を一旦します。
実行してみます。
iex> Foo.hello
"awesome1234"
という結果が得られました。
config/config.exs
を書き換えます。
たとえば
import Config
config :foo, :world, "awesome123"
そしてrecompile
します。
iex> recompile
一旦、Ctl+Cを2回押しでもしてIExを終了させます。
そして再度iex -S mix
とすると冒頭のエラーに遭遇できます。
config/runtime.exs
が存在しない場合は、同じことをしてもERROR!
とはならないです。
もっと実践的なところで遭遇する例をみつけたら追記したいとおもいます。
まとめ
この記事は、Module attributesで、Application.get_env/3を使っている箇所があったら、Application.compile_env/3のほうを使うことがススメられていますよということをご紹介した記事です。
Application.compile_env/3に置き換えたときに遭遇するかもしれない注意事項を3点書きました。
- 1.10 or later
- (RuntimeError) Application.compile_env/3 cannot be called inside functions, only in the module body
- By using compile_env/3, tools like Mix will store the values used during compilation and compare the compilation values with the runtime values whenever your system starts, raising an error in case they differ.
Enjoy Elixir
$\huge{Enjoy\ Elixir🚀}$
We are the Alchemists, my friends!!!
I organize autoracex.
And I take part in NervesJP, fukuoka.ex, EDI, tokyo.ex, Pelemay.
I hope someday you'll join us.
We Are The Alchemists, my friends!