Skip to content

Commit 50ae386

Browse files
committed
if: treat is_nil as a negator
1 parent 5b1c946 commit 50ae386

File tree

4 files changed

+24
-5
lines changed

4 files changed

+24
-5
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ they can and will change without that change being reflected in Styler's semanti
88
### Improvements
99

1010
- `if`: drop empty `do` bodies like `if a, do: nil, else: b` => `if !a, do: b` (#227)
11+
- `if`: treat `is_nil` as a negator.
12+
13+
this means `if is_nil(x), do: a, else: b` will be inverted to `if x, do: b, else: a`
14+
15+
or `if !is_nil(x), do: y` will be rewritten as `if x, do: y`
16+
17+
This could cause problems where x is `false` =)
1118

1219
### Fixes
1320

docs/control_flow_macros.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ if !a, do: b
6969
### Negation Inversion
7070

7171
Styler removes negators in the head of `if` statements by "inverting" the statement.
72-
The following operators are considered "negators": `!`, `not`, `!=`, `!==`
72+
The following operators are considered "negators": `!`, `not`, `!=`, `!==`, `is_nil`
7373

7474
Examples:
7575

@@ -83,7 +83,12 @@ if x, do: z, else: y
8383
Because elixir relies on truthy/falsey values for its `if` statements, boolean casting is unnecessary and so double negation is simply removed.
8484

8585
```elixir
86-
if !!x, do: y
86+
if !x, do: y
87+
# styled:
88+
if x, do: y
89+
90+
# similarly
91+
if !is_nil(x), do: y
8792
# styled:
8893
if x, do: y
8994
```

lib/style/blocks.ex

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ defmodule Styler.Style.Blocks do
3030
alias Styler.Style
3131
alias Styler.Zipper
3232

33-
defguardp is_negator(n) when elem(n, 0) in [:!, :not, :!=, :!==]
33+
defguardp is_if_negator(n) when elem(n, 0) in [:!, :not, :!=, :!==, :is_nil]
3434
defguardp is_empty_body(n) when elem(n, 0) == :__block__ and elem(n, 2) in [[nil], []]
3535

3636
# case statement with exactly 2 `->` cases
@@ -132,12 +132,12 @@ defmodule Styler.Style.Blocks do
132132
case children do
133133
# double negator
134134
# if !!x, do: y[, else: ...] => if x, do: y[, else: ...]
135-
[{_, _, [nb]} = na, do_else] when is_negator(na) and is_negator(nb) ->
135+
[{_, _, [nb]} = na, do_else] when is_if_negator(na) and is_if_negator(nb) ->
136136
zipper |> Zipper.replace({:if, m, [invert(nb), do_else]}) |> run(ctx)
137137

138138
# Credo.Check.Refactor.NegatedConditionsWithElse
139139
# if !x, do: y, else: z => if x, do: z, else: y
140-
[negator, [{do_, do_body}, {else_, else_body}]] when is_negator(negator) ->
140+
[negator, [{do_, do_body}, {else_, else_body}]] when is_if_negator(negator) ->
141141
zipper |> Zipper.replace({:if, m, [invert(negator), [{do_, else_body}, {else_, do_body}]]}) |> run(ctx)
142142

143143
# drop `else end` and `else: nil`
@@ -368,5 +368,6 @@ defmodule Styler.Style.Blocks do
368368
defp invert({:!, _, [condition]}), do: condition
369369
defp invert({:not, _, [condition]}), do: condition
370370
defp invert({:in, m, [_, _]} = ast), do: {:not, m, [ast]}
371+
defp invert({:is_nil, _, [a]}), do: a
371372
defp invert({_, m, _} = ast), do: {:!, [line: m[:line]], [ast]}
372373
end

test/style/blocks_test.exs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,12 @@ defmodule Styler.Style.BlocksTest do
10121012
end
10131013
"""
10141014
)
1015+
1016+
assert_style "if is_nil(a.b), do: nil, else: a.c", "if a.b, do: a.c"
1017+
end
1018+
1019+
test "if not is_nil" do
1020+
assert_style "if is_nil(a), do: b, else: c", "if a, do: c, else: b"
10151021
end
10161022

10171023
test "double negator rewrites" do

0 commit comments

Comments
 (0)