Skip to content

Instantly share code, notes, and snippets.

@rodrigues
Last active September 12, 2021 06:43
Show Gist options
  • Save rodrigues/952c51944529058cbdb579a3bf2afca2 to your computer and use it in GitHub Desktop.
Save rodrigues/952c51944529058cbdb579a3bf2afca2 to your computer and use it in GitHub Desktop.
defmodule CredoExtra.Check.Readability.FunctionOrder do
use Credo.Check,
base_priority: :low,
explanations: [
check: """
Alphabetically ordered lists are more easily scannable by the read.
# preferred
def a ...
def b ...
def c ...
# NOT preferred
def b ...
def c ...
def a ...
Function names should be alphabetically ordered inside a module.
Like all `Readability` issues, this one is not a technical concern.
But you can improve the odds of others reading and liking your code by making
it easier to follow.
"""
]
alias Credo.Code
@doc false
@impl true
def run(%SourceFile{} = source_file, params) do
issue_meta = IssueMeta.for(source_file, params)
Code.prewalk(source_file, &traverse(&1, &2, issue_meta))
end
defp traverse({:defmodule, _, _} = ast, issues, issue_meta) do
new_issues =
ast
|> Code.postwalk(&find_function_definitions/2)
|> sorting_issues(issue_meta)
{ast, issues ++ new_issues}
end
defp traverse(ast, issues, _), do: {ast, issues}
defp sorting_issues([], _), do: []
defp sorting_issues(fun_list_with_lines, issue_meta) do
fun_list = Enum.map(fun_list_with_lines, &elem(&1, 0))
sorted_fun_list = Enum.sort(fun_list)
if fun_list != sorted_fun_list do
{function, line_no} =
fun_list_with_lines
|> Enum.with_index()
|> Enum.find_value(fn {{function, _line_no} = entry, index} ->
if function != Enum.at(sorted_fun_list, index) do
entry
end
end)
[issue_for(issue_meta, %{trigger: function, line_no: line_no})]
else
[]
end
end
defp find_function_definitions(
{key, meta, [{name, _, _} | _]} = ast,
definitions
)
when key in [:def, :defp, :defmacro, :defmacrop] do
{ast, definitions ++ [{to_string(name), meta[:line]}]}
end
defp find_function_definitions(ast, definitions), do: {ast, definitions}
defp issue_for(issue_meta, %{line_no: line_no, trigger: trigger}) do
format_issue(
issue_meta,
message: "The function `#{trigger}` is not alphabetically ordered inside the module.",
trigger: trigger,
line_no: line_no
)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment