lib/fussy/validators/boolean.ex

defmodule Fussy.Validators.Boolean do
  @behaviour Fussy.Validator

  defstruct strict: true

  @opaque t :: %__MODULE__{}

  @spec new(strict: boolean()) :: __MODULE__.t()
  def new(args \\ []), do: struct!(%__MODULE__{}, args)

  @impl true
  def validate(_, true), do: {:ok, true}

  @impl true
  def validate(_, false), do: {:ok, false}

  @impl true
  def validate(%__MODULE__{strict: false}, 0), do: {:ok, false}

  @impl true
  def validate(%__MODULE__{strict: false}, n) when is_integer(n), do: {:ok, true}

  @impl true
  def validate(%__MODULE__{strict: false}, str) when is_binary(str) do
    if String.valid?(str) do
      case String.downcase(str) do
        "true" ->
          {:ok, true}

        "false" ->
          {:ok, false}

        _ ->
          {:error, ["cannot coerce into boolean"]}
      end
    else
      {:error, ["cannot coerce into boolean"]}
    end
  end

  @impl true
  def validate(_, _), do: {:error, ["must be a boolean"]}
end