Packages

A Credo check that flags every use of unless. Prefer usage of if with a negated condition.

Current section

Files

Jump to
Raw

README.md

# CredoNoUnless

A [Credo](https://github.com/rrrene/credo) check that flags every use of
`unless`.

Prefer usage of `if` with a negated condition.

Co-mingling `unless` and `if` is hard to read. The implicit negation of
conditionals can be confusing when reading code, especially when `if` and
`unless` are used in close proximity.

```elixir
if connected?(socket), do: push(socket, msg)
unless queue_empty?(state), do: drain(state)
if retries_left?(state), do: retry(state)
```

Written with `if` throughout, the sequence reads in one direction:

```elixir
if connected?(socket), do: push(socket, msg)
if !queue_empty?(state), do: drain(state)
if retries_left?(state), do: retry(state)
```

## Installation

Add `credo_no_unless` to your deps in `mix.exs`, alongside `credo` itself:

```elixir
def deps do
  [
    {:credo, "~> 1.7", only: [:dev, :test], runtime: false},
    {:credo_no_unless, "~> 0.1", only: [:dev, :test], runtime: false}
  ]
end
```

## Usage

Enable the check in your `.credo.exs`:

```elixir
%{
  configs: [
    %{
      name: "default",
      files: %{included: ["lib/"]},
      checks: %{
        enabled: [
          {CredoNoUnless.Check.Readability.NoUnless, []}
        ]
      }
    }
  ]
}
```

Then run `mix credo` as usual.

## What it catches

All three spellings of `unless` are flagged:

```elixir
# block form
unless Enum.empty?(list) do
  process(list)
end

# keyword form
unless valid?(changeset), do: reject(changeset)

# fully qualified
Kernel.unless(message == "", do: IO.puts(message))
```

Each is reported as a readability issue pointing at the `unless` keyword.
Rewrite it as an `if` with the condition negated:

```elixir
if !Enum.empty?(list) do
  process(list)
end
```

## License

MIT. See [LICENSE](LICENSE).