Skip to content

Commit cb5dc63

Browse files
committed
rewrite single-clause case statements to assignments
1 parent b5d7d9d commit cb5dc63

File tree

5 files changed

+160
-5
lines changed

5 files changed

+160
-5
lines changed

CHANGELOG.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,24 @@ they can and will change without that change being reflected in Styler's semanti
55

66
## main
77

8+
### Improvements
9+
10+
Rewrite single-clause case statements to be assignments (h/t 🤖)
11+
12+
```elixir
13+
# before
14+
case foo |> Bar.baz() |> Bop.boop() do
15+
{:ok, widget} ->
16+
x = y
17+
wodget(widget)
18+
end
19+
20+
# after
21+
{:ok, widget} = foo |> Bar.baz() |> Bop.boop()
22+
x = y
23+
wodget(widget)
24+
```
25+
826
## 1.7.0
927

1028
Surprising how fast numbers go up when you're following semver.

lib/style/blocks.ex

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,34 @@ defmodule Styler.Style.Blocks do
4343
end
4444
end
4545

46+
# case statements with 1 clause: thanks 🤖!
47+
#
48+
# ideally rewrite to use `=`, but can't do that when there's a `when` clause
49+
def run({{:case, _, [_, [{_, [{:->, _, [[{:when, _, _} | _] | _]}]}]]}, _} = zipper, ctx), do: {:cont, zipper, ctx}
50+
#
51+
def run({{:case, m, [head, [{_, [{:->, _, [[lhs], rhs]}]}]]}, _} = zipper, ctx) do
52+
rhs =
53+
case rhs do
54+
{:__block__, _, children} -> children
55+
node -> [node]
56+
end
57+
58+
zipper =
59+
case Zipper.up(zipper) do
60+
{{:=, am, [parent_lhs, _single_clause_case]}, _} = zipper ->
61+
# this was a `x = case head, do: (lhs -> rhs)`. make it `x = lhs = head; rhs`
62+
meta = [line: am[:line]]
63+
Zipper.replace(zipper, {:=, meta, [parent_lhs, {:=, meta, [lhs, head]}]})
64+
65+
_ ->
66+
zipper
67+
|> Style.find_nearest_block()
68+
|> Zipper.replace({:=, [line: m[:line]], [lhs, head]})
69+
end
70+
71+
{:cont, Zipper.insert_siblings(zipper, rhs), ctx}
72+
end
73+
4674
def run({{:cond, _, [[{do_, clauses}]]}, _} = zipper, ctx) do
4775
# ensure all final `atom -> final_clause` use `true` for consistency.
4876
# `:else` is cute but consistency is all.

test/style/blocks_test.exs

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,110 @@
1111
defmodule Styler.Style.BlocksTest do
1212
use Styler.StyleCase, async: true
1313

14+
describe "case statements with a single clause" do
15+
test "noop for when" do
16+
assert_style """
17+
case foo do
18+
bar when is_binary(bar) -> baz(bar)
19+
end
20+
"""
21+
end
22+
23+
test "changes to assignment" do
24+
assert_style(
25+
"""
26+
case foo do
27+
bar -> baz(bar)
28+
end
29+
""",
30+
"""
31+
bar = foo
32+
baz(bar)
33+
"""
34+
)
35+
36+
assert_style(
37+
"""
38+
case foo |> Bar.baz() |> Bop.boop() do
39+
{:ok, widget} ->
40+
x = y
41+
wodget(widget)
42+
end
43+
""",
44+
"""
45+
{:ok, widget} = foo |> Bar.baz() |> Bop.boop()
46+
x = y
47+
wodget(widget)
48+
"""
49+
)
50+
end
51+
52+
test "with comments" do
53+
assert_style(
54+
"""
55+
# bar
56+
bar
57+
58+
# head
59+
case foo |> Bar.baz() |> Bop.boop() do
60+
# clause
61+
{:ok, widget} ->
62+
# body
63+
x = y
64+
wodget(widget)
65+
end
66+
""",
67+
"""
68+
# bar
69+
bar
70+
71+
# head
72+
# clause
73+
{:ok, widget} = foo |> Bar.baz() |> Bop.boop()
74+
# body
75+
x = y
76+
wodget(widget)
77+
"""
78+
)
79+
end
80+
81+
test "singleton parent" do
82+
assert_style """
83+
if foo do
84+
case complex |> head() |> stuff() do
85+
{:ok, whatever} ->
86+
some_body(whatever)
87+
end
88+
end
89+
""",
90+
"""
91+
if foo do
92+
{:ok, whatever} = complex |> head() |> stuff()
93+
some_body(whatever)
94+
end
95+
"""
96+
end
97+
98+
test "when already an assignment" do
99+
assert_style(
100+
"""
101+
m
102+
103+
x =
104+
case a do
105+
b -> c
106+
end
107+
""",
108+
"""
109+
m
110+
111+
x = b = a
112+
c
113+
"""
114+
)
115+
end
116+
end
117+
14118
describe "case to if" do
15119
test "rewrites case true false to if else" do
16120
assert_style(

test/style/pipes_test.exs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ defmodule Styler.Style.PipesTest do
184184
x =
185185
case y do
186186
:ok -> :ok |> IO.puts()
187+
:error -> :error
187188
end
188189
|> bar()
189190
|> baz()
@@ -192,6 +193,7 @@ defmodule Styler.Style.PipesTest do
192193
case_result =
193194
case y do
194195
:ok -> IO.puts(:ok)
196+
:error -> :error
195197
end
196198
197199
x =
@@ -286,11 +288,8 @@ defmodule Styler.Style.PipesTest do
286288
|> foo()
287289
""",
288290
"""
289-
case_result =
290-
case x do
291-
x -> x
292-
end
293-
291+
case_result = x = x
292+
x
294293
foo(case_result)
295294
"""
296295
)
@@ -300,6 +299,7 @@ defmodule Styler.Style.PipesTest do
300299
def foo do
301300
case x do
302301
x -> x
302+
y -> y
303303
end
304304
|> foo()
305305
end
@@ -309,6 +309,7 @@ defmodule Styler.Style.PipesTest do
309309
case_result =
310310
case x do
311311
x -> x
312+
y -> y
312313
end
313314
314315
foo(case_result)

test/style/single_node_test.exs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,11 +279,13 @@ defmodule Styler.Style.SingleNodeTest do
279279
"""
280280
case foo do
281281
bar = _ -> :ok
282+
_ -> :error
282283
end
283284
""",
284285
"""
285286
case foo do
286287
bar -> :ok
288+
_ -> :error
287289
end
288290
"""
289291
)
@@ -292,11 +294,13 @@ defmodule Styler.Style.SingleNodeTest do
292294
"""
293295
case foo do
294296
_ = bar -> :ok
297+
_ = second_clause_to_maintain_case -> :ok
295298
end
296299
""",
297300
"""
298301
case foo do
299302
bar -> :ok
303+
second_clause_to_maintain_case -> :ok
300304
end
301305
"""
302306
)

0 commit comments

Comments
 (0)