module_attribute_names.ex (1838B)
1 defmodule Credo.Check.Readability.ModuleAttributeNames do 2 use Credo.Check, 3 base_priority: :high, 4 explanations: [ 5 check: """ 6 Module attribute names are always written in snake_case in Elixir. 7 8 # snake_case 9 10 @inbox_name "incoming" 11 12 # not snake_case 13 14 @inboxName "incoming" 15 16 Like all `Readability` issues, this one is not a technical concern. 17 But you can improve the odds of others reading and liking your code by making 18 it easier to follow. 19 """ 20 ] 21 22 alias Credo.Code.Name 23 24 @doc false 25 @impl true 26 def run(%SourceFile{} = source_file, params) do 27 issue_meta = IssueMeta.for(source_file, params) 28 29 Credo.Code.prewalk(source_file, &traverse(&1, &2, issue_meta)) 30 end 31 32 # ignore non-alphanumeric @ ASTs, for when you're redefining the @ macro. 33 defp traverse({:@, _meta, [{:{}, _, _}]} = ast, issues, _) do 34 {ast, issues} 35 end 36 37 # TODO: consider for experimental check front-loader (ast) 38 # NOTE: see above how we want to exclude certain front-loads 39 defp traverse( 40 {:@, _meta, [{name, meta, _arguments}]} = ast, 41 issues, 42 issue_meta 43 ) do 44 case issue_for_name(issue_meta, name, meta) do 45 nil -> {ast, issues} 46 val -> {ast, issues ++ [val]} 47 end 48 end 49 50 defp traverse(ast, issues, _source_file) do 51 {ast, issues} 52 end 53 54 defp issue_for_name(issue_meta, name, meta) 55 when is_binary(name) or is_atom(name) do 56 unless name |> to_string |> Name.snake_case?() do 57 issue_for(issue_meta, meta[:line], "@#{name}") 58 end 59 end 60 61 defp issue_for_name(_, _, _), do: nil 62 63 defp issue_for(issue_meta, line_no, trigger) do 64 format_issue( 65 issue_meta, 66 message: "Module attribute names should be written in snake_case.", 67 trigger: trigger, 68 line_no: line_no 69 ) 70 end 71 end