zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

map_join.ex (2607B)


      1 defmodule Credo.Check.Refactor.MapJoin do
      2   use Credo.Check,
      3     base_priority: :high,
      4     explanations: [
      5       check: """
      6       `Enum.map_join/3` is more efficient than `Enum.map/2 |> Enum.join/2`.
      7 
      8       This should be refactored:
      9 
     10           ["a", "b", "c"]
     11           |> Enum.map(&String.upcase/1)
     12           |> Enum.join(", ")
     13 
     14       to look like this:
     15 
     16           Enum.map_join(["a", "b", "c"], ", ", &String.upcase/1)
     17 
     18       The reason for this is performance, because the two separate calls
     19       to `Enum.map/2` and `Enum.join/2` require two iterations whereas 
     20       `Enum.map_join/3` performs the same work in one pass.
     21       """
     22     ]
     23 
     24   @doc false
     25   def run(source_file, params \\ []) do
     26     issue_meta = IssueMeta.for(source_file, params)
     27 
     28     Credo.Code.prewalk(source_file, &traverse(&1, &2, issue_meta))
     29   end
     30 
     31   defp traverse(
     32          {{:., _, [{:__aliases__, meta, [:Enum]}, :join]}, _,
     33           [{{:., _, [{:__aliases__, _, [:Enum]}, :map]}, _, _}, _]} = ast,
     34          issues,
     35          issue_meta
     36        ) do
     37     new_issue = issue_for(issue_meta, meta[:line], "map_join")
     38     {ast, issues ++ List.wrap(new_issue)}
     39   end
     40 
     41   defp traverse(
     42          {:|>, meta,
     43           [
     44             {{:., _, [{:__aliases__, _, [:Enum]}, :map]}, _, _},
     45             {{:., _, [{:__aliases__, _, [:Enum]}, :join]}, _, _}
     46           ]} = ast,
     47          issues,
     48          issue_meta
     49        ) do
     50     new_issue = issue_for(issue_meta, meta[:line], "map_join")
     51     {ast, issues ++ List.wrap(new_issue)}
     52   end
     53 
     54   defp traverse(
     55          {{:., meta, [{:__aliases__, _, [:Enum]}, :join]}, _,
     56           [
     57             {:|>, _, [_, {{:., _, [{:__aliases__, _, [:Enum]}, :map]}, _, _}]},
     58             _
     59           ]} = ast,
     60          issues,
     61          issue_meta
     62        ) do
     63     new_issue = issue_for(issue_meta, meta[:line], "map_join")
     64     {ast, issues ++ List.wrap(new_issue)}
     65   end
     66 
     67   defp traverse(
     68          {:|>, meta,
     69           [
     70             {:|>, _,
     71              [
     72                _,
     73                {{:., _, [{:__aliases__, _, [:Enum]}, :map]}, _, _}
     74              ]},
     75             {{:., _, [{:__aliases__, _, [:Enum]}, :join]}, _, _}
     76           ]} = ast,
     77          issues,
     78          issue_meta
     79        ) do
     80     new_issue = issue_for(issue_meta, meta[:line], "map_join")
     81     {ast, issues ++ List.wrap(new_issue)}
     82   end
     83 
     84   defp traverse(ast, issues, _issue_meta) do
     85     {ast, issues}
     86   end
     87 
     88   defp issue_for(issue_meta, line_no, trigger) do
     89     format_issue(
     90       issue_meta,
     91       message: "`Enum.map_join/3` is more efficient than `Enum.map/2 |> Enum.join/2`",
     92       trigger: trigger,
     93       line_no: line_no
     94     )
     95   end
     96 end