Skip to content

Instantly share code, notes, and snippets.

@IvanRublev
Last active June 15, 2022 18:42
Show Gist options
  • Save IvanRublev/c8dcb87068ffe4f35518cb97ca65cc27 to your computer and use it in GitHub Desktop.
Save IvanRublev/c8dcb87068ffe4f35518cb97ca65cc27 to your computer and use it in GitHub Desktop.
Types as Specification in Elixir with Domo library

Types as Specification in Elixir with Domo library

Run in Livebook

Mix.install([:domo])

https://hex.pm/packages/domo

Define the struct type enriched with precondition

defmodule Guardian do
  use Domo, skip_defaults: true

  defstruct [:name]

  @type t :: %__MODULE__{name: String.t()}
end

defmodule User do
  use Domo, skip_defaults: true

  defstruct [:name, :age, :address, :guardian]
  @type str :: String.t()

  @type t :: %__MODULE__{
          name: str(),
          age: integer(),
          address: str(),
          guardian: Guardian.t() | nil
        }

  precond(
    t:
      &cond do
        &1.age < 18 and is_nil(&1.guardian) ->
          {:error, "Users under 18 must have guardian."}

        &1.age >= 18 and not is_nil(&1.guardian) ->
          {:error, "Users of age 18 and over must have no guardian."}

        true ->
          :ok
      end
  )
end

Shared structure proofs allowed use cases by itself 💯

User.new(name: "Junior", age: 8, address: "Somestr. 14", guardian: nil)
{:error, [t: "Users under 18 must have guardian."]}
ok_junior =
  User.new(name: "Junior", age: 8, address: "Somestr. 14", guardian: Guardian.new!(name: "John"))
{:ok, %User{address: "Somestr. 14", age: 8, guardian: %Guardian{name: "John"}, name: "Junior"}}
{:ok, junior} = ok_junior
User.ensure_type(%{junior | age: 18})
{:error, [t: "Users of age 18 and over must have no guardian."]}
User.ensure_type(%{junior | age: 18, guardian: nil})
{:ok, %User{address: "Somestr. 14", age: 18, guardian: nil, name: "Junior"}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment