defmodule TemporaryEnv do @moduledoc """ Temporarily set Application environment variables. Quite handy for testing, but remember to set `async: false` for tests suites it is used in. """ @default :temporary_env_default_value_for_unset_var @doc false defmacro __using__(_) do quote do require TemporaryEnv test "TemporaryEnv test case async status", context do refute context.async, """ TemporaryEnv cannot be used in async tests. To make this test case synchronous, modify your use of ExUnit.Case like so: use ExUnit.Case, async: false """ end end end @spec set(atom, [{atom, any}], [{:do, any}]) :: any @doc """ Temporarily set an Application environment value within a block. TemporaryEnv.set :my_app, greeting: "Hello!" do # :greeting for :my_app is now "Hello!" end # :greeting for :my_app is back to its original value This *does* modify global state, so do not use it in an async situation. """ defmacro set(app, [{key, value}], do: block) do quote do # Get original state temporary_env_original_value = Application.get_env( unquote(app), unquote(key), unquote(@default) ) try do # Set temporary state Application.put_env unquote(app), unquote(key), unquote(value) unquote(block) after # Restore original state case temporary_env_original_value do # when the value was previously unset unquote(@default) -> Application.delete_env( unquote(app), unquote(key) ) # when the value was previously set _ -> Application.put_env( unquote(app), unquote(key), temporary_env_original_value ) end end end end @spec set(atom, atom, [{:do, any}]) :: any @doc """ Temporarily unset an Application environment value within a block. TemporaryEnv.delete :my_app, :greeting do # :greeting for :my_app now has no value end # :greeting for :my_app is back to its original value This *does* modify global state, so do not use it in an async situation. """ defmacro delete(app, key, do: block) when key |> is_atom do quote do # Get original state unquote(app) |> Application.get_env( unquote(key), unquote(@default) ) |> case do # when the value was previously unset unquote(@default) -> unquote(block) # when the value was previously set val -> try do Application.delete_env unquote(app), unquote(key) unquote(block) after Application.put_env unquote(app), unquote(key), val end end end end end