ForgeCredoChecks.WithBareBinding (forge_credo_checks v0.4.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 high and works with any version of Elixir.

Explanation

Every clause in a with chain must use <-, never =.

Why

<- is what gives with its reason for existing: a non-match aborts the chain and returns the offending value as-is. A bare = line skips that fall-through behavior - it's a local binding smuggled into the chain to set up arguments for the next <- step. That bypasses the one piece of control flow with is supposed to provide.

How to fix (two options)

Option 1 - bundle the infallible compute into the next fallible helper so it emerges already wrapped in {:ok, _} | {:error, _} and the with chain consumes it via <-:

# BAD
with :ok <- verify(),
     argv = normalize_argv(raw_argv),
     {:ok, opts} <- parse_options(argv) do
  ...
end

# GOOD
with :ok <- verify(),
     {:ok, opts} <- parse_options(raw_argv) do
  ...
end

defp parse_options(raw_argv) do
  raw_argv |> normalize_argv() |> OptionParser.parse(strict: @spec) |> ...
end

Option 2 - move the binding into the do block. The do block is normal Elixir code, so plain = bindings belong there. Use this when the binding only feeds the body, not later with steps:

with :ok <- verify(),
     {:ok, opts} <- parse_options(raw_argv) do
  display = format_for_display(opts)
  {:ok, display}
end

What NOT to do

Do not "fix" this by wrapping the bare compute in {:ok, ...} inline just to satisfy <-:

# STILL BAD - fake fallibility, no real control flow
with :ok <- verify(),
     {:ok, argv} <- {:ok, normalize_argv(raw_argv)},
     ...

If the step can't fail, it doesn't belong as a <- step. Pick one of the two options above.

Check-Specific Parameters

There are no specific parameters for this check.

General Parameters

Like with all checks, general params can be applied.

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