harnais_error v0.3.0 Harnais.Error exception View Source
The Exception for the Harnais Package Family.
Many of the functions in the Harnais packages return
either {:ok, any} or {error, error} where error will be an
Exception.
Many of the errors will be instances of Harnais.Error struct.
Exporting the Exception
As well as supporting the usual Exception callbacks, the package
support “exporting” the exception using Harnais.Error.export/1.
See the exception fields :export_function and :export_config for
how to contol what the export does.
Exception State
The exception struct has a number of fields
| Field | Aliases |
|---|---|
:message | :m, :msg |
:reason | :r |
:type | :t |
:location | :l, :loc, :ndx, :index, :i |
:value0 | :v, :v0, :value, :e, :error |
:value1 | :v1 |
:value2 | :v2 |
:message_function | |
:message_config | |
:export_function | |
:export_config |
Exception Field: :message
The explanatory message, normally a string.
Exception Field: :reason
The reason for the error; normally an Atom.
Exception Field: :type
An aribtrary term defining the type of the error e.g. :arg, :key, :value, etc
Exception Field: :location
An aribtrary term defining where the error happened.
For example this could be a key, index in a list, whatever.
Exception Field: :value0, :value1, :value2
Arbitrary terms identifying the cause of the error.
Three fields are useful when, for example, :value0 holds the name of
a key and :value1 and :value2 hold the values of the key that
were expected to be equal.
Sometimes :value0 holds an instance of Harnais.Error.Status.
Exception Field: :message_function
The module implements its own Exception.message/1 callback but
this can be overridden by this field.
If supplied, it must be an arity 1 function that is passed the
struct and must return a string.
Exception Field: :message_config
This field is used by the default Exception.message/1 formatter to
hold the fields to be included in the message. It can be overridden
to set the wanted fields.
If an explicit :message_function function is supplied, this field
can also be used to hold configuration for it.
Exception Field: :export_function
The exception can be “exported” using Harnais.Error.export/1 which
is passed the exception struct.
The default exporter creates a Keyword of selected fields where
the keys are the shortest alias for the field (e.g. :m for
:message).
A custom export function can be provided using this field.
Exception Field: :export_config
The default exporter using this field to hold the fields to be included in the export.
If a custom export function is provided, this field can be used to provide configuration for it.
Standard API
Unless otherwise specified, functions return either {:ok, status}
or {:error, error} when error will be an Exception..
Many functions have peer bang functions that returns either the value
in {:ok, value} or raise the error in {:error, error}.
Link to this section Summary
Functions
Callback implementation for Exception.exception/1
export/2 takes an instance of the module’s struct and an optional opts and exports it
export_exception/1 takes an exception struct and optional opts and exports it
gather_export/1 takes an export and, if the export is a Keyword or list of
Keyword, gathers all the values for the same key
(Keyword.get_values/2) together
new/1 creates an instance of the error module’s struct t
update/2 takes an instance of the module’s struct and an optional opts
Link to this section Types
Link to this section Functions
Callback implementation for Exception.exception/1.
export/2 takes an instance of the module’s struct and an optional opts and exports it.
If the opts are not empty, update/2 is called with the struct
and opts before performing the export.
A custom arity one export function can be given in the field :export_function.
Otherwise the default export function is used which creates Keyword
with one key (:error) whose value is a list of Keywords of the set fields in the
error where the keys are the short form of the full field name (e.g. :m for :message)
If the export works, {:ok, export} is returned.
Examples
iex> {:ok, error} = [message: "something broke", type: :arg, value: 42] |> new
...> error |> export
{:ok, [error: [[m: "something broke", t: :arg, v: 42]]]}
iex> export_fun = fn error -> {:ok, error.value} end
...> {:ok, error} = [export_function: export_fun, message: "something broke", type: :arg, value: 42] |> new
...> error |> export
{:ok, 42}
In these two examples :export_config is given in the opts to
change the fields in the export. The second example show the error
when an unknown field is given.
iex> {:ok, error} = [message: "something broke", type: :arg, value: 42] |> new
...> error |> export(export_config: [:m, :v])
{:ok, [error: [[m: "something broke", v: 42]]]}
iex> {:ok, error} = [message: "something broke", type: :arg, value: 42] |> new
...> {:error, export_error} = error |> export(export_config: [:m, :unknown_key])
...> export_error |> Exception.message |> String.starts_with?("key :unknown_key not found")
true
export_exception/1 takes an exception struct and optional opts and exports it.
If the struct is a Harnais.Error or Harnais.Error.Status their respective export/2 functions are called.
For any other exception, Exception.message/1 is called and {:ok, [m: message]} returned.
Examples
iex> {:ok, error} = [message: "something broke", type: :arg, value: 42] |> new
...> error |> export_exception
{:ok, [error: [[m: "something broke", t: :arg, v: 42]]]}
iex> {:ok, error} = [add_results: [ok: 42, error: :got_an_error, error: %BadMapError{term: 42}]]
...> |> Harnais.Error.Status.new
...> error |> export_exception
{:ok, [ok: 42, error: [[v: :got_an_error]], error: [[m: "expected a map, got: 42"]]]}
iex> %RuntimeError{message: "this is a test"} |> export_exception
{:ok, [error: [[m: "this is a test"]]]}
iex> %KeyError{key: :b, term: %{a: 1}} |> export_exception
{:ok, [error: [[m: "key :b not found in: %{a: 1}"]]]}
gather_export/1 takes an export and, if the export is a Keyword or list of
Keyword, gathers all the values for the same key
(Keyword.get_values/2) together.
The argument is expected to be the export in {:ok, export}
returned by export/2 or export_exception/2.
Otherwise the export is returned unchanged as {:ok, export}.
Examples
Gathering the export of single exception may not make any differnce:
iex> {:ok, error} = [message: "something broke", type: :arg, value: 42] |> new
...> {:ok, export} = error |> export_exception
...> export |> gather_export
{:ok, [error: [[m: "something broke", t: :arg, v: 42]]]}
iex> {:ok, export} = %KeyError{key: :b, term: %{a: 1}} |> export_exception
...> export |> gather_export
{:ok, [error: [[m: "key :b not found in: %{a: 1}"]]]}
However, when there are multiple :ok and/or :error values, they will be gathered together.
iex> {:ok, error} = [add_results:
...> [ok: 42, error: :got_an_error, error: %BadMapError{term: 42}, ok: "Hello World"]
...> ] |> Harnais.Error.Status.new
...> {:ok, export} = error |> export_exception
...> export |> gather_export
{:ok, [ok: [42, "Hello World"], error: [[v: :got_an_error], [m: "expected a map, got: 42"]]]}
new/1 creates an instance of the error module’s struct t.
If the opts are not empty, it calls update/2 with t and the opts.
Either {:ok, t} or {:error, error} is returned where error is
an exception generated during the creation.
Examples
iex> {:ok, t} = new()
...> match?(%Harnais.Error{}, t)
true
iex> {:ok, t} = new(m: "failed again", r: :usual_cause, v: 42)
...> t |> Exception.message
"failed again, reason=:usual_cause, got: 42"
update/2 takes an instance of the module’s struct and an optional opts.
The opts are normalised by calling the module’s update_canonical_opts/1
and then reduced with update_field/2:
opts |> Enum.reduce(instance, fn {k,v}, s -> s |> update_field({k,v}) end)
{:ok, instance} is returned.