ForgeCredoChecks.WithElseClauses (forge_credo_checks v0.3.0)

Copy Markdown View Source

Basics

This check is disabled by default.

Learn how to enable it via .credo.exs.

This check has a base priority of normal and works with any version of Elixir.

Explanation

Avoid wide else blocks on with expressions.

Why

All failure clauses from every <- step are flattened into a single else block. The block stops describing which step failed and becomes a dispatch table on error shapes - and an exhaustive one, since any unmatched failure raises WithClauseError.

Prefer letting non-matches fall through: if every <- step returns a uniform shape (:ok | {:error, reason} or {:ok, value} | {:error, reason}), the bare with (no else) returns the first error verbatim and the caller decides what to do.

How to fix

For each <- step that returns a step-specific shape, wrap the call in a private helper that returns the uniform shape. Then delete the else block.

# BEFORE - else dispatches on step-specific shapes
with {:ok, user} <- Repo.get(User, id) |> ok_or_nil(),
     true <- User.active?(user) do
  {:ok, user}
else
  nil -> {:error, :not_found}
  false -> {:error, :inactive}
  {:error, _} = err -> err
end

# AFTER - each step returns {:ok, _} | {:error, _}; no else needed
with {:ok, user} <- find_user(id),
     :ok <- ensure_active(user) do
  {:ok, user}
end

defp find_user(id) do
  case Repo.get(User, id) do
    nil -> {:error, :not_found}
    user -> {:ok, user}
  end
end

defp ensure_active(user) do
  if User.active?(user), do: :ok, else: {:error, :inactive}
end

What NOT to do

Do not collapse the else into a single catch-all clause to silence this check - that loses the per-step error context entirely:

# STILL BAD
else
  err -> {:error, err}
end

Push the normalization upstream into helpers, as shown above.

Configuration

This check fires when a with has more than :max_clauses else clauses (default 1). Set :max_clauses to 0 to forbid else entirely; raise it for codebases that accept wider blocks.

Check-Specific Parameters

Use the following parameters to configure this check:

:max_clauses

Maximum number of else clauses allowed before the check fires. Default: 1.

This parameter defaults to 1.

General Parameters

Like with all checks, general params can be applied.

Parameters can be configured via the .credo.exs config file.