single_pipe.ex (2445B)
1 defmodule Credo.Check.Readability.SinglePipe do 2 use Credo.Check, 3 base_priority: :high, 4 tags: [:controversial], 5 param_defaults: [allow_0_arity_functions: false], 6 explanations: [ 7 check: """ 8 Pipes (`|>`) should only be used when piping data through multiple calls. 9 10 So while this is fine: 11 12 list 13 |> Enum.take(5) 14 |> Enum.shuffle 15 |> evaluate() 16 17 The code in this example ... 18 19 list 20 |> evaluate() 21 22 ... should be refactored to look like this: 23 24 evaluate(list) 25 26 Using a single |> to invoke functions makes the code harder to read. Instead, 27 write a function call when a pipeline is only one function long. 28 29 Like all `Readability` issues, this one is not a technical concern. 30 But you can improve the odds of others reading and liking your code by making 31 it easier to follow. 32 """, 33 params: [ 34 allow_0_arity_functions: "Allow 0-arity functions" 35 ] 36 ] 37 38 @doc false 39 @impl true 40 def run(%SourceFile{} = source_file, params) do 41 issue_meta = IssueMeta.for(source_file, params) 42 43 allow_0_arity_functions = Params.get(params, :allow_0_arity_functions, __MODULE__) 44 45 {_continue, issues} = 46 Credo.Code.prewalk( 47 source_file, 48 &traverse(&1, &2, issue_meta, allow_0_arity_functions), 49 {true, []} 50 ) 51 52 issues 53 end 54 55 defp traverse({:|>, _, [{:|>, _, _} | _]} = ast, {_, issues}, _, _) do 56 {ast, {false, issues}} 57 end 58 59 defp traverse({:|>, meta, _} = ast, {true, issues}, issue_meta, false) do 60 { 61 ast, 62 {false, issues ++ [issue_for(issue_meta, meta[:line], "|>")]} 63 } 64 end 65 66 defp traverse({:|>, _, [{{:., _, _}, _, []}, _]} = ast, {true, issues}, _, true) do 67 {ast, {false, issues}} 68 end 69 70 defp traverse({:|>, _, [{fun, _, []}, _]} = ast, {true, issues}, _, true) when is_atom(fun) do 71 {ast, {false, issues}} 72 end 73 74 defp traverse({:|>, meta, _} = ast, {true, issues}, issue_meta, true) do 75 { 76 ast, 77 {false, issues ++ [issue_for(issue_meta, meta[:line], "|>")]} 78 } 79 end 80 81 defp traverse(ast, {_, issues}, _issue_meta, _allow_functions) do 82 {ast, {true, issues}} 83 end 84 85 defp issue_for(issue_meta, line_no, trigger) do 86 format_issue( 87 issue_meta, 88 message: "Use a function call when a pipeline is only one function long", 89 trigger: trigger, 90 line_no: line_no 91 ) 92 end 93 end