Skip to content

Commit 2af7d19

Browse files
committed
Enum.map |> Enum.intersperse => Enum.map_intersperse
1 parent 7884561 commit 2af7d19

5 files changed

Lines changed: 71 additions & 43 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ they can and will change without that change being reflected in Styler's semanti
77

88
### Improvements
99

10+
Two new standard-library pipe optimizations
11+
12+
- `enum |> Enum.map(fun) |> Enum.intersperse(separator)` => `Enum.map_intersperse(enum, separator, fun)`
1013
- `enum |> Enum.sort() |> Enum.reverse()` => `Enum.sort(enum, :desc)`
11-
- Req pipe optimizations (see below!)
14+
15+
And Req (the http client library) pipe optimizations, as detailed below
1216

1317
#### Req pipe optimizations
1418

docs/pipes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ a |> Enum.find(default, fun) |> ...
114114
# Given:
115115
a |> Enum.sort() |> Enum.reverse() |> ...
116116
a |> Enum.sort(:desc) |> ...
117+
118+
# Given:
119+
a |> Enum.map(fun) |> Enum.intersperse(separator) |> ...
120+
a |> Enum.map_intersperse(separator, fun) |> ...
117121
```
118122

119123
## Unpiping Single Pipes

lib/style/pipes.ex

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,17 @@ defmodule Styler.Style.Pipes do
311311
end
312312
end
313313

314+
# `lhs |> Enum.map(fun) |> Enum.intersperse(sep)` => `lhs |> Enum.map_intersperse(sep, fun)
315+
defp fix_pipe(
316+
pipe_chain(
317+
pm,
318+
lhs,
319+
{{:., dm, [{_, _, [:Enum]} = enum, :map]}, em, [fun]},
320+
{{:., _, [{_, _, [:Enum]}, :intersperse]}, _, [sep]}
321+
)
322+
),
323+
do: {:|>, pm, [lhs, {{:., dm, [enum, :map_intersperse]}, em, [Style.set_line(sep, em[:line]), fun]}]}
324+
314325
# `lhs |> Enum.reverse() |> Enum.concat(enum)` => `lhs |> Enum.reverse(enum)`
315326
defp fix_pipe(
316327
pipe_chain(
@@ -319,9 +330,8 @@ defmodule Styler.Style.Pipes do
319330
{{:., _, [{_, _, [:Enum]}, :reverse]} = reverse, meta, []},
320331
{{:., _, [{_, _, [:Enum]}, :concat]}, _, [enum]}
321332
)
322-
) do
323-
{:|>, pm, [lhs, {reverse, [line: meta[:line]], [enum]}]}
324-
end
333+
),
334+
do: {:|>, pm, [lhs, {reverse, meta, [enum]}]}
325335

326336
# `lhs |> Enum.filter(fun) |> List.first([default])` => `lhs |> Enum.find([default], fun)`
327337
defp fix_pipe(
@@ -331,10 +341,8 @@ defmodule Styler.Style.Pipes do
331341
{{:., dm, [{_, _, [:Enum]} = enum, :filter]}, meta, [fun]},
332342
{{:., _, [{_, _, [:List]}, :first]}, _, default}
333343
)
334-
) do
335-
line = meta[:line]
336-
{:|>, pm, [lhs, {{:., dm, [enum, :find]}, [line: line], Style.set_line(default, line) ++ [fun]}]}
337-
end
344+
),
345+
do: {:|>, pm, [lhs, {{:., dm, [enum, :find]}, meta, Style.set_line(default, meta[:line]) ++ [fun]}]}
338346

339347
# `lhs |> Enum.reverse() |> Kernel.++(enum)` => `lhs |> Enum.reverse(enum)`
340348
defp fix_pipe(
@@ -344,9 +352,8 @@ defmodule Styler.Style.Pipes do
344352
{{:., _, [{_, _, [:Enum]}, :reverse]} = reverse, meta, []},
345353
{{:., _, [{_, _, [:Kernel]}, :++]}, _, [enum]}
346354
)
347-
) do
348-
{:|>, pm, [lhs, {reverse, [line: meta[:line]], [enum]}]}
349-
end
355+
),
356+
do: {:|>, pm, [lhs, {reverse, meta, [enum]}]}
350357

351358
# `lhs |> Enum.filter(filterer) |> Enum.count()` => `lhs |> Enum.count(count)`
352359
defp fix_pipe(
@@ -357,9 +364,8 @@ defmodule Styler.Style.Pipes do
357364
{{:., _, [{_, _, [:Enum]}, :count]} = count, _, []}
358365
)
359366
)
360-
when mod in @enum do
361-
{:|>, pm, [lhs, {count, [line: meta[:line]], [filterer]}]}
362-
end
367+
when mod in @enum,
368+
do: {:|>, pm, [lhs, {count, meta, [filterer]}]}
363369

364370
# `lhs |> Stream.map(fun) |> Stream.run()` => `lhs |> Enum.each(fun)`
365371
# `lhs |> Stream.each(fun) |> Stream.run()` => `lhs |> Enum.each(fun)`
@@ -371,9 +377,8 @@ defmodule Styler.Style.Pipes do
371377
{{:., _, [{_, _, [:Stream]}, :run]}, _, []}
372378
)
373379
)
374-
when map_or_each in [:map, :each] do
375-
{:|>, pm, [lhs, {{:., dm, [{a, am, [:Enum]}, :each]}, fm, fa}]}
376-
end
380+
when map_or_each in [:map, :each],
381+
do: {:|>, pm, [lhs, {{:., dm, [{a, am, [:Enum]}, :each]}, fm, fa}]}
377382

378383
# `lhs |> Enum.map(mapper) |> Enum.join(joiner)` => `lhs |> Enum.map_join(joiner, mapper)`
379384
defp fix_pipe(
@@ -384,10 +389,8 @@ defmodule Styler.Style.Pipes do
384389
{{:., _, [{_, _, [:Enum]} = enum, :join]}, _, join_args}
385390
)
386391
)
387-
when mod in @enum do
388-
rhs = {{:., dm, [enum, :map_join]}, em, Style.set_line(join_args, dm[:line]) ++ map_args}
389-
{:|>, pm, [lhs, rhs]}
390-
end
392+
when mod in @enum,
393+
do: {:|>, pm, [lhs, {{:., dm, [enum, :map_join]}, em, Style.set_line(join_args, dm[:line]) ++ map_args}]}
391394

392395
# `lhs |> Enum.map(mapper) |> Enum.into(empty_map)` => `lhs |> Map.new(mapper)`
393396
# or
@@ -426,9 +429,8 @@ defmodule Styler.Style.Pipes do
426429
{{:., _, [{_, _, [mod]}, :new]} = new, _, []}
427430
)
428431
)
429-
when mod in @collectable and enum in @enum do
430-
{:|>, pm, [lhs, {Style.set_line(new, em[:line]), em, [mapper]}]}
431-
end
432+
when mod in @collectable and enum in @enum,
433+
do: {:|>, pm, [lhs, {Style.set_line(new, em[:line]), em, [mapper]}]}
432434

433435
@req2 for fun <- ~w(delete get head patch post put request run), bang <- ["", "!"], do: :"#{fun}#{bang}"
434436

@@ -441,18 +443,16 @@ defmodule Styler.Style.Pipes do
441443
{{:., _, [{_, _, [:Req]}, fun]} = req, _, []}
442444
)
443445
)
444-
when req_or_kw in [:Req, :Keyword] and fun in @req2 do
445-
fix_pipe({:|>, pm, [lhs, {req, m, [kw]}]})
446-
end
446+
when req_or_kw in [:Req, :Keyword] and fun in @req2,
447+
do: fix_pipe({:|>, pm, [lhs, {req, m, [kw]}]})
447448

448449
# Req.new |> Req.fun1,2 -> Req.fun1,2
449450
# all `fun` options take the same args as `Req.new`, so it's redundant to call Req.new before them
450451
defp fix_pipe(
451452
pipe_chain(pm, lhs, {{:., _, [{_, _, [:Req]}, :new]}, m, []}, {{:., _, [{_, _, [:Req]}, fun]} = req, _, args})
452453
)
453-
when fun in @req2 do
454-
{:|>, pm, [lhs, {req, m, args}]}
455-
end
454+
when fun in @req2,
455+
do: {:|>, pm, [lhs, {req, m, args}]}
456456

457457
defp fix_pipe(node), do: node
458458

lib/styler.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ defmodule Styler do
7575
ast_to_string(ast, comments, formatter_opts)
7676
end
7777

78-
@doc "Just `Code.string_to_quoted_with_comments/2` with the necessary options"
78+
@doc "Just `Code.string_to_quoted_with_comments/2` with the necessary options"
7979
def string_to_ast(code, file \\ "nofile") when is_binary(code) do
8080
Code.string_to_quoted_with_comments!(code,
8181
literal_encoder: &__MODULE__.literal_encoder/2,

test/style/pipes_test.exs

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
defmodule Styler.Style.PipesTest do
1212
use Styler.StyleCase, async: true
1313

14-
describe "big picture" do
14+
describe "big picture / readability" do
1515
test "unnests multiple steps" do
1616
assert_style("f(g(h(x))) |> j()", "x |> h() |> g() |> f() |> j()")
1717
end
@@ -78,6 +78,16 @@ defmodule Styler.Style.PipesTest do
7878
"""
7979
)
8080
end
81+
82+
test "rewrites anonymous function invocations to use then" do
83+
assert_style("a |> (& &1).()", "then(a, & &1)")
84+
assert_style("a |> (& {&1, &2}).(b)", "(&{&1, &2}).(a, b)")
85+
assert_style("a |> (& &1).() |> c", "a |> then(& &1) |> c()")
86+
87+
assert_style("a |> (fn x, y -> {x, y} end).() |> c", "a |> then(fn x, y -> {x, y} end) |> c()")
88+
assert_style("a |> (fn x -> x end).()", "then(a, fn x -> x end)")
89+
assert_style("a |> (fn x -> x end).() |> c", "a |> then(fn x -> x end) |> c()")
90+
end
8191
end
8292

8393
describe "block pipe starts" do
@@ -501,17 +511,7 @@ defmodule Styler.Style.PipesTest do
501511
end
502512
end
503513

504-
describe "optimizations & readability improvements" do
505-
test "rewrites anonymous function invocations to use then" do
506-
assert_style("a |> (& &1).()", "then(a, & &1)")
507-
assert_style("a |> (& {&1, &2}).(b)", "(&{&1, &2}).(a, b)")
508-
assert_style("a |> (& &1).() |> c", "a |> then(& &1) |> c()")
509-
510-
assert_style("a |> (fn x, y -> {x, y} end).() |> c", "a |> then(fn x, y -> {x, y} end) |> c()")
511-
assert_style("a |> (fn x -> x end).()", "then(a, fn x -> x end)")
512-
assert_style("a |> (fn x -> x end).() |> c", "a |> then(fn x -> x end) |> c()")
513-
end
514-
514+
describe "readability" do
515515
test "rewrites then/2 when the passed function is a named function reference" do
516516
assert_style "a |> then(&fun/1) |> c", "a |> fun() |> c()"
517517
assert_style "a |> then(&(&1 / 1)) |> c", "a |> Kernel./(1) |> c()"
@@ -542,6 +542,26 @@ defmodule Styler.Style.PipesTest do
542542
test "adds parens to 1-arity pipes" do
543543
assert_style("a |> b |> c", "a |> b() |> c()")
544544
end
545+
end
546+
547+
describe "optimizations for stdlib functions" do
548+
test "map/intersperse => map_intersperse" do
549+
assert_style "a |> Enum.map(fun) |> Enum.intersperse(sep)", "Enum.map_intersperse(a, sep, fun)"
550+
551+
assert_style(
552+
"""
553+
a
554+
|> Enum.map(fun)
555+
|> Enum.intersperse(sep)
556+
|> foo()
557+
""",
558+
"""
559+
a
560+
|> Enum.map_intersperse(sep, fun)
561+
|> foo()
562+
"""
563+
)
564+
end
545565

546566
test "filter/first => find" do
547567
assert_style "a |> Enum.filter(fun) |> List.first()", "Enum.find(a, fun)"

0 commit comments

Comments
 (0)