zf

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

map_into.ex (2940B)


      1 defmodule Credo.Check.Refactor.MapInto do
      2   # only available in Elixir < 1.8 since performance improvements have since made this check obsolete
      3   use Credo.Check,
      4     base_priority: :high,
      5     elixir_version: "< 1.8.0",
      6     explanations: [
      7       check: """
      8       `Enum.into/3` is more efficient than `Enum.map/2 |> Enum.into/2`.
      9 
     10       This should be refactored:
     11 
     12           [:apple, :banana, :carrot]
     13           |> Enum.map(&({&1, to_string(&1)}))
     14           |> Enum.into(%{})
     15 
     16       to look like this:
     17 
     18           Enum.into([:apple, :banana, :carrot], %{}, &({&1, to_string(&1)}))
     19 
     20       The reason for this is performance, because the separate calls to
     21       `Enum.map/2` and `Enum.into/2` require two iterations whereas
     22       `Enum.into/3` only requires one.
     23 
     24       **NOTE**: This check is only available in Elixir < 1.8 since performance
     25       improvements have since made this check obsolete.
     26       """
     27     ]
     28 
     29   @doc false
     30   @impl true
     31   def run(%SourceFile{} = source_file, params) do
     32     issue_meta = IssueMeta.for(source_file, params)
     33 
     34     Credo.Code.prewalk(source_file, &traverse(&1, &2, issue_meta))
     35   end
     36 
     37   defp traverse(
     38          {{:., _, [{:__aliases__, meta, [:Enum]}, :into]}, _,
     39           [{{:., _, [{:__aliases__, _, [:Enum]}, :map]}, _, _}, _]} = ast,
     40          issues,
     41          issue_meta
     42        ) do
     43     new_issue = issue_for(issue_meta, meta[:line], "map_into")
     44 
     45     {ast, issues ++ List.wrap(new_issue)}
     46   end
     47 
     48   defp traverse(
     49          {:|>, meta,
     50           [
     51             {{:., _, [{:__aliases__, _, [:Enum]}, :map]}, _, _},
     52             {{:., _, [{:__aliases__, _, [:Enum]}, :into]}, _, _}
     53           ]} = ast,
     54          issues,
     55          issue_meta
     56        ) do
     57     new_issue = issue_for(issue_meta, meta[:line], "map_into")
     58 
     59     {ast, issues ++ List.wrap(new_issue)}
     60   end
     61 
     62   defp traverse(
     63          {{:., meta, [{:__aliases__, _, [:Enum]}, :into]}, _,
     64           [
     65             {:|>, _, [_, {{:., _, [{:__aliases__, _, [:Enum]}, :map]}, _, _}]},
     66             _
     67           ]} = ast,
     68          issues,
     69          issue_meta
     70        ) do
     71     new_issue = issue_for(issue_meta, meta[:line], "map_into")
     72 
     73     {ast, issues ++ List.wrap(new_issue)}
     74   end
     75 
     76   defp traverse(
     77          {:|>, meta,
     78           [
     79             {:|>, _,
     80              [
     81                _,
     82                {{:., _, [{:__aliases__, _, [:Enum]}, :map]}, _, _}
     83              ]},
     84             {{:., _, [{:__aliases__, _, [:Enum]}, :into]}, _, into_args}
     85           ]} = ast,
     86          issues,
     87          issue_meta
     88        )
     89        when length(into_args) == 1 do
     90     new_issue = issue_for(issue_meta, meta[:line], "map_into")
     91 
     92     {ast, issues ++ List.wrap(new_issue)}
     93   end
     94 
     95   defp traverse(ast, issues, _issue_meta) do
     96     {ast, issues}
     97   end
     98 
     99   defp issue_for(issue_meta, line_no, trigger) do
    100     format_issue(
    101       issue_meta,
    102       message: "`Enum.into/3` is more efficient than `Enum.map/2 |> Enum.into/2`",
    103       trigger: trigger,
    104       line_no: line_no
    105     )
    106   end
    107 end