I have a tiny module defining some macros that allows me to define a GenServer
callbacks like this:
use GenServer
# This matches when `[name: name]` is passed as argument
oninit [name: name] do
# `name` is available
end
# This matches everything that does not match above clause
oninit do
# A variable called `args` is available
end
# Match event, from and state parameters
oncall someevent, from: {somepid, _ref}, state: %{somvar: somevalue} do
# `somevalue` and `somepid` are available
# `event`, `from` and `socket` are available too
end
# Every parameter to `oncall` is optional.
# This matches evey call not matched by above clause
oncall do
# `event`, `from` and `socket` are available too
end
# `oncast` and `oninfo` are just the same as `oncall`, just `from` is not available
oncast someevent, state: %{key: value} do
# `value` is available
# `event` and `socket` are available too
end
oncast do
# `event` and `socket` are available too
end
# Match only on event
oninfo someevent do
end
Basically, allows to not write the parameters that you don’t care about, and write callbacks more easily.
What are your takes on this? Do you like this, or you like the more explicit approach of writing everything?
If I see that this will be useful to people, I would expand it to include macros for other OTP behaviors, as well as Phoenix behaviors like LiveView
or Channel
.
In any circumstances, I will write another helper for myself for LiveView
, because my LiveView
callbacks tend to get kind of messy.
EDIT:
I forgot to mention that for callbacks implemented this way, there is no need to always return {:ok, state}
, {:noreply, state}
or {:reply, reply, state}
.
I you return something that does not match a standard for that callback, it will be wrapped in tuple most appropriate for that callback, e.g. return just a map and oninfo
will convert it to {:noreply, state}
.