mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-12-12 10:45:54 +00:00
48 lines
1.7 KiB
Elixir
48 lines
1.7 KiB
Elixir
defmodule WandererApp.GenImpl do
|
|
@moduledoc "Simple utility for avoiding boilerplate in a GenServer implementation."
|
|
|
|
@doc """
|
|
If your GenServer is a thin wrapper around a struct, you can make its handle_call/3 and/or
|
|
handle_cast/2 implementations be "just this."
|
|
|
|
Use it like this:
|
|
|
|
GenImpl.apply_call(&MyGenServer.Impl.update/3, %MyGenServer.Impl{}, [arg2, arg3])
|
|
|
|
This will result in a call that looks like:
|
|
|
|
MyGenServer.Impl.update(%MyGenServer.Impl{}, arg2, arg3)
|
|
|
|
Supports operations that:
|
|
|
|
- Update the state struct
|
|
- Return a result tuple, or even just :error
|
|
- Query the state and return a value
|
|
|
|
...but not operations that both modify the state *and* query something.
|
|
"""
|
|
def apply_call(impl_function, state, additional_args)
|
|
when is_function(impl_function) and is_struct(state) and is_list(additional_args) do
|
|
result = apply(impl_function, [state | additional_args])
|
|
handle_call_result(state, result)
|
|
end
|
|
|
|
def apply_call(impl_function_name, %struct_module{} = state, additional_args)
|
|
when is_atom(impl_function_name) and is_list(additional_args) do
|
|
result = apply(struct_module, impl_function_name, [state | additional_args])
|
|
handle_call_result(state, result)
|
|
end
|
|
|
|
defp handle_call_result(%struct_type{}, %struct_type{} = updated_state),
|
|
do: {:reply, :ok, updated_state}
|
|
|
|
defp handle_call_result(%struct_type{}, {:ok, %struct_type{} = updated_state}),
|
|
do: {:reply, :ok, updated_state}
|
|
|
|
defp handle_call_result(%struct_type{}, {result, %struct_type{} = updated_state}),
|
|
do: {:reply, result, updated_state}
|
|
|
|
defp handle_call_result(%_struct_type{} = state, :error), do: {:reply, :error, state}
|
|
defp handle_call_result(%_struct_type{} = state, result), do: {:reply, result, state}
|
|
end
|