single_function_to_block_pipe.ex (2008B)
1 defmodule Credo.Check.Readability.SingleFunctionToBlockPipe do 2 use Credo.Check, 3 tags: [:controversial], 4 explanations: [ 5 check: """ 6 A single pipe (`|>`) should not be used to pipe into blocks. 7 8 The code in this example ... 9 10 list 11 |> length() 12 |> case do 13 0 -> :none 14 1 -> :one 15 _ -> :many 16 end 17 18 ... should be refactored to look like this: 19 20 case length(list) do 21 0 -> :none 22 1 -> :one 23 _ -> :many 24 end 25 26 If you want to disallow piping into blocks all together, use 27 `Credo.Check.Readability.BlockPipe`. 28 """ 29 ] 30 31 @doc false 32 @impl true 33 def run(%SourceFile{} = source_file, params) do 34 Credo.Code.prewalk(source_file, &traverse(&1, &2, IssueMeta.for(source_file, params))) 35 end 36 37 defp traverse(ast, {false, issues}, _issue_meta) do 38 {ast, issues} 39 end 40 41 defp traverse(ast, issues, issue_meta) do 42 case issue(ast, issue_meta) do 43 nil -> {ast, issues} 44 false -> {ast, {false, issues}} 45 issue -> {ast, [issue | issues]} 46 end 47 end 48 49 defp issue({:|>, _, [{:|>, _, [{:|>, _, _} | _]} | _]}, _), do: false 50 51 defp issue({:|>, meta, [arg, {marker, _case_meta, _case_args}]}, issue_meta) 52 when marker in [:case, :if] do 53 if issue?(arg), do: issue_for(issue_meta, meta[:line]), else: nil 54 end 55 56 defp issue(_, _), do: nil 57 58 defp issue?({_, _, nil}), do: true 59 60 defp issue?({:%{}, _, _}), do: true 61 62 defp issue?(arg) when is_list(arg), do: true 63 64 defp issue?({:|>, _, [{_, _, nil}, {_, _, args}]}) when is_list(args), do: true 65 66 defp issue?({:|>, _, [{:%{}, _, _}, {_, _, args}]}) when is_list(args), do: true 67 68 defp issue?({:|>, _, [arg, {_, _, args}]}) when is_list(arg) and is_list(args), do: true 69 70 defp issue?(_), do: false 71 72 defp issue_for(issue_meta, line_no) do 73 format_issue( 74 issue_meta, 75 message: "Avoid single pipes to a block", 76 line_no: line_no 77 ) 78 end 79 end