Hoare.State behaviour (hoare v0.1.0)

Copy Markdown View Source

A named record state: the status that tags it and the properties that refine it.

A state module is a struct of witnesses, record plus whatever its properties extract, and match/2 builds it or says why the record is not in that state. A Hoare.Transition names states as its from and to.

defmodule PendingUnpack do
  @behaviour Hoare.State
  defstruct [:record, :package]

  def status, do: :PENDING_UNPACK
  def missing, do: :not_pending_unpack
  def properties, do: [&single_package/1]

  defp single_package(%{record: %{packages: [package]}} = state),
    do: {:ok, %{state | package: package}}

  defp single_package(%{record: %{packages: []}}), do: {:error, :no_packages}
  defp single_package(_state), do: {:error, :multiple_packages}
end

Summary

Callbacks

The reason reported when a record's status does not tag it.

Arrows over the state struct that refine the tag and fill its witnesses.

The status value that tags a record as being in this state.

Functions

Matches a sum of states: the first whose status tags the record decides.

Types

property()

@type property() :: (struct() -> {:ok, struct()} | {:error, reason()})

reason()

@type reason() :: atom()

subject()

@type subject() :: %{:status => atom(), optional(atom()) => term()}

Callbacks

missing()

@callback missing() :: reason()

The reason reported when a record's status does not tag it.

properties()

@callback properties() :: [property()]

Arrows over the state struct that refine the tag and fill its witnesses.

status()

@callback status() :: atom()

The status value that tags a record as being in this state.

Functions

match(state, record)

@spec match(module(), subject()) :: {:ok, struct()} | {:error, reason()}

match_any(states, record)

@spec match_any([module(), ...], subject()) :: {:ok, struct()} | {:error, reason()}

Matches a sum of states: the first whose status tags the record decides.

When no state tags the record, the first state's missing/0 is the reason.