• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

exercism / elixir-analyzer / 81bb2bd44c91598e28b337a76394d2632f36db5b

29 Sep 2025 12:19AM UTC coverage: 98.524%. Remained the same
81bb2bd44c91598e28b337a76394d2632f36db5b

push

github

web-flow
Add analyzer for gotta-snatch-em-all (#451)

* Add analyzer for gotta-snatch-em-all

* Fix space alignment & formatting

* Add tests for gotta snatch em all analyzer

* Fix wording & spelling mistakes

Co-authored-by: Jie <jie.gillet@gmail.com>

---------

Co-authored-by: Jie <jie.gillet@gmail.com>

868 of 881 relevant lines covered (98.52%)

16232.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/lib/elixir_analyzer/exercise_test/common_checks/boolean_functions.ex
1
defmodule ElixirAnalyzer.ExerciseTest.CommonChecks.BooleanFunctions do
2
  @moduledoc """
3
  Reports the first boolean function with a name that's not appropriate.
4

5
  Doesn't report more if there are more.
6
  A single comment should be enough for the student to know what to fix.
7

8
  Common check to be run on every single solution.
9
  """
10

11
  alias ElixirAnalyzer.Constants
12
  alias ElixirAnalyzer.Comment
13

14
  @spec run(Macro.t()) :: [{:pass | :fail, Comment.t()}]
15
  def run(ast) do
16
    {_, function_names} =
1,031✔
17
      Macro.prewalk(ast, %{defs: [], defguards: [], defmacros: []}, &traverse/2)
18

19
    function_names
20
    |> Enum.map(fn {type, list} -> {type, List.last(list)} end)
3,093✔
21
    |> Enum.map(&to_comment/1)
22
    |> List.flatten()
1,031✔
23
  end
24

25
  @def_ops [:def, :defp, :defmacro, :defmacrop, :defguard, :defguardp]
26
  defp traverse({op, _meta, [{name, _meta2, _parameters} | _]} = ast, acc) when op in @def_ops do
27
    name = to_string(name)
1,997✔
28

29
    if correct_name?(op, name) do
1,997✔
30
      {ast, acc}
31
    else
32
      {ast, put_correct_name(acc, op, name)}
33
    end
34
  end
35

36
  defp traverse(ast, acc) do
43,907✔
37
    {ast, acc}
38
  end
39

40
  defp correct_name?(type, name) do
41
    starts_with_is = String.starts_with?(name, "is_")
1,997✔
42
    end_with_? = String.ends_with?(name, "?")
1,997✔
43

44
    cond do
1,997✔
45
      starts_with_is and end_with_? -> false
1,997✔
46
      starts_with_is and type in [:def, :defp] -> false
1,983✔
47
      end_with_? and type in [:defguard, :defguardp] -> false
1,979✔
48
      true -> true
1,975✔
49
    end
50
  end
51

52
  defp put_correct_name(acc, type, wrong_name) when type in [:def, :defp] do
53
    name =
10✔
54
      wrong_name
55
      |> String.replace_leading("is_", "")
56
      |> String.replace_trailing("?", "")
57

58
    Map.update!(acc, :defs, &[{"#{type} #{wrong_name}", "#{type} #{name}?"} | &1])
10✔
59
  end
60

61
  defp put_correct_name(acc, type, wrong_name) when type in [:defguard, :defguardp] do
62
    name =
8✔
63
      wrong_name
64
      |> String.replace_leading("is_", "")
65
      |> String.replace_trailing("?", "")
66

67
    Map.update!(acc, :defguards, &[{"#{type} #{wrong_name}", "#{type} is_#{name}"} | &1])
8✔
68
  end
69

70
  defp put_correct_name(acc, type, wrong_name) do
71
    option1 = String.replace_leading(wrong_name, "is_", "")
4✔
72
    option2 = String.replace_trailing(wrong_name, "?", "")
4✔
73

74
    Map.update!(
4✔
75
      acc,
76
      :defmacros,
77
      &[{"#{type} #{wrong_name}", "#{type} #{option1}", "#{type} #{option2}"} | &1]
4✔
78
    )
79
  end
80

81
  defp to_comment({_, nil}), do: []
3,072✔
82

83
  defp to_comment({:defs, {wrong_def, correct_def}}) do
9✔
84
    {:fail,
85
     %Comment{
86
       type: :actionable,
87
       name: Constants.solution_def_with_is(),
88
       comment: Constants.solution_def_with_is(),
89
       params: %{
90
         expected: correct_def,
91
         actual: wrong_def
92
       }
93
     }}
94
  end
95

96
  defp to_comment({:defguards, {wrong_def, correct_def}}) do
8✔
97
    {:fail,
98
     %Comment{
99
       type: :actionable,
100
       name: Constants.solution_defguard_with_question_mark(),
101
       comment: Constants.solution_defguard_with_question_mark(),
102
       params: %{
103
         expected: correct_def,
104
         actual: wrong_def
105
       }
106
     }}
107
  end
108

109
  defp to_comment({:defmacros, {wrong_def, correct_?, correct_is}}) do
4✔
110
    {:fail,
111
     %Comment{
112
       type: :actionable,
113
       name: Constants.solution_defmacro_with_is_and_question_mark(),
114
       comment: Constants.solution_defmacro_with_is_and_question_mark(),
115
       params: %{
116
         actual: wrong_def,
117
         option1: correct_?,
118
         option2: correct_is
119
       }
120
     }}
121
  end
122
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc