Neat! I can think of a few places where this would clean up some of my own code.
A few ergonomics improvements that come to mind:
-
To ease the transition from existing custom exceptions to Splode and to decrease the API footprint, the existing
messagecallback could be wrapped instead of using asplode_messagecallback. -
Implement a default
splode_message(ormessageif the first suggestion is taken) that, for instance, just inspects the:fieldspresent in the error.
These last two I’m less sure of, but would pretty significantly reduce boilerplate:
-
Allow module namespaces to be used as implicit error classes when unspecified. For instance:
defmodule MyApp.Errors do use Splode, error_classes: [MyApp.Errors.Invalid, MyApp.Errors.Unknown], unknown_error: MyApp.Errors.Unknown.Unknown end defmodule MyApp.Errors.Invalid.InvalidThing do # Implicitly belongs to the MyApp.Errors.Invalid error class use Splode.Error, fields: [:foo, :bar] end -
Define error classes explicitly with
use Splode.ErrorClassas opposed to implicitly by including a:errorsfield. This could inject thesplode_messageimplementation, which it looks like will almost always (or just always?) be the same.defmodule MyApp.Errors.Invalid do use Splode.ErrorClass end
Taken all together, before:
defmodule MyApp.Errors do
use Splode, error_classes: [
invalid: MyApp.Errors.Invalid,
unknown: MyApp.Errors.Unknown
],
unknown_error: MyApp.Errors.Unknown.Unknown
end
defmodule MyApp.Errors.Invalid do
use Splode.Error, fields: [:errors], class: :invalid
def splode_message(%{errors: errors}) do
Splode.ErrorClass.error_messages(errors)
end
end
defmodule MyApp.Errors.Unknown do
use Splode.Error, fields: [:errors], class: :unknown
def splode_message(%{errors: errors}) do
Splode.ErrorClass.error_messages(errors)
end
end
defmodule MyApp.Errors.Unknown.Unknown do
use Splode.Error, fields: [:error], class: :unknown
def splode_message(%{error: error}) do
if is_binary(error) do
to_string(error)
else
inspect(error)
end
end
end
defmodule MyApp.Errors.InvalidArgument do
use Splode.Error, fields: [:name, :message], class: :invalid
def splode_message(%{name: name, message: message}) do
"Invalid argument #{name}: #{message}"
end
end
And after:
defmodule MyApp.Errors do
use Splode,
error_classes: [MyApp.Errors.Invalid, MyApp.Errors.Unknown],
unknown_error: MyApp.Errors.Unknown.Unknown
end
defmodule MyApp.Errors.Invalid do
use Splode.ErrorClass
end
defmodule MyApp.Errors.Unknown do
use Splode.ErrorClass
end
defmodule MyApp.Errors.Unknown.Unknown do
use Splode.Error, fields: [:error]
end
defmodule MyApp.Errors.InvalidArgument do
use Splode.Error, fields: [:name, :message]
def splode_message(%{name: name, message: message}) do
"Invalid argument #{name}: #{message}"
end
end


















