Consider the simplest thing that could work: listing the mapping from command to handler atom explicitly.
@handlers %{
"foo" => Commands.Foo,
"bar" => Commands.Bar,
# etc
}
defp parse!(_state, [cmd | opts]) do
case Map.fetch(@handlers, cmd) do
{:ok, mod} -> {:ok, {mod, opts}}
:error -> {:ok, {:echo, "#{cmd}: UNKNOWN_COMMAND"}}
end
end
This approach also has logical extension points for useful things:
- broadening the possible keys of the map to things like
Regexes would allow for “partial match” commands - broadening the possible values of the map to
{module, baked_in_opts}lets one “command module” serve multiple external commands
One downside is that the command → module mapping can get quite long; consider extracting parts of it to functions and combining them at compile-time to reduce clutter.
Worth looking into persistent_term for storing the map - an Agent still forces every access through a single thread.






















