An expanded example:
# file: lib/my_storage.ex
defmodule MyStorage do
@config_key :my_storage_config
def config_key,
do: @config_key
def init do
%{:module => m, :init => f} = config = get_config()
handle = apply(m, f, [])
{config, handle}
end
def put({%{:module => m, :put => f} = config, handle}, value) do
handle = apply(m, f, [handle, value])
{config, handle}
end
def peek({%{:module => m, :peek => f}, handle}, default) do
apply(m, f, [handle, default])
end
defp get_config() do
Application.get_application(__MODULE__)
|> Application.fetch_env!(@config_key)
|> Map.new
end
end
# file: lib/tuple_storage.ex
defmodule TupleStorage do
def tuple_init do
IO.puts(Atom.to_string(__MODULE__))
nil
end
def tuple_put(_handle, nil),
do: nil
def tuple_put(_handle, value),
do: {:value, value}
def tuple_peek(nil, default),
do: default
def tuple_peek({:value, value}, _default),
do: value
end
# file: lib/agent_storage.ex
defmodule AgentStorage do
def agent_init do
IO.puts(Atom.to_string(__MODULE__))
{:ok, pid} = Agent.start(fn -> nil end)
pid
end
def agent_put(pid, nil) do
Agent.update(pid, fn _ -> nil end)
pid
end
def agent_put(pid, value) do
Agent.update(pid, fn _ -> {:value, value} end)
pid
end
def agent_peek(pid, default) do
case Agent.get(pid, fn contents -> contents end) do
{:value, value} ->
value
_ ->
default
end
end
end
# file: lib/demo.ex
defmodule Demo do
def run() do
handle = MyStorage.init()
result = MyStorage.peek(handle, :undefined)
IO.inspect(result)
handle = MyStorage.put(handle, :something)
result = MyStorage.peek(handle, :undefined)
IO.inspect(result)
:ok
end
def show do
config =
Application.get_application(__MODULE__)
|> Application.get_env(MyStorage.config_key, :empty)
IO.puts("Config: #{inspect config}")
end
def load(config) do
Application.get_application(__MODULE__)
|> Application.put_env(MyStorage.config_key, config)
end
def agent_config,
do: [module: AgentStorage, init: :agent_init, put: :agent_put, peek: :agent_peek]
def tuple_config,
do: [module: TupleStorage, init: :tuple_init, put: :tuple_put, peek: :tuple_peek]
end
$ iex -S mix
Erlang/OTP 21 [erts-10.0.7] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]
Compiling 4 files (.ex)
Interactive Elixir (1.7.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Demo.show()
Config: :empty
:ok
iex(2)> Demo.load(Demo.tuple_config())
:ok
iex(3)> Demo.show()
Config: [module: TupleStorage, init: :tuple_init, put: :tuple_put, peek: :tuple_peek]
:ok
iex(4)> Demo.run()
Elixir.TupleStorage
:undefined
:something
:ok
iex(5)> Demo.load(Demo.agent_config())
:ok
iex(6)> Demo.show()
Config: [module: AgentStorage, init: :agent_init, put: :agent_put, peek: :agent_peek]
:ok
iex(7)> Demo.run()
Elixir.AgentStorage
:undefined
:something
:ok
iex(8)>