開発時とデプロイ時で関数の定義を変えたいときがある。以下のように書けば、Mix.env
の値に応じて、異なる関数がコンパイルされる。
defmodule MyModule do
@moduledoc false
if Mix.env() == :prod do
@foo Application.fetch_env!(:myapp, :foo)
def foo, do: @foo
else
def foo, do: Application.fetch_env!(:myapp, :foo)
end
end
リリース時に Mix モジュールは存在しないが、この場合、コンパイル時に使われるだけなので問題ない。ただ、このままだとテスト時には片方の実装しかテストされないので、両方をテストしておきたいところ。以下のようにした。
defmodule MyModuleTest do
use ExUnit.Case
import ExUnit.CaptureIO
@source_filepath __DIR__
|> Path.join("../../lib/myapp/my_module.ex")
|> Path.expand()
test "foo" do
on_exit(fn ->
Mix.env(:test)
end)
# suppress warnings
capture_io(:stderr, fn ->
Mix.env(:prod)
Code.compile_file(@source_filepath)
assert MyModule.foo(), "compile on Mix.env(:prod)"
Mix.env(:test)
Code.compile_file(@source_filepath)
assert MyModule.foo(), "compile on Mix.env(:test)"
end)
end
end
Mix.env
を変更してから Code.compile_file/2
で対象ファイルを再コンパイルしてやる。on_exit/2
で戻してやるのも忘れずに。