-
-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Run common checks for every single solution; Add common check for sna…
…ke_case (#102) Co-authored-by: Tim Austin <[email protected]>
- Loading branch information
1 parent
9a6b02c
commit 1b24399
Showing
15 changed files
with
582 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
defmodule ElixirAnalyzer.ExerciseTest.CommonChecks do | ||
@moduledoc """ | ||
This module aggregates all common checks that should be run on every single solution. | ||
""" | ||
|
||
alias ElixirAnalyzer.ExerciseTest.CommonChecks.FunctionNames | ||
alias ElixirAnalyzer.ExerciseTest.CommonChecks.ModuleAttributeNames | ||
alias ElixirAnalyzer.Comment | ||
|
||
@spec run(Macro.t(), String.t()) :: [{:pass | :fail | :skip, %Comment{}}] | ||
def run(code_ast, code_as_string) when is_binary(code_as_string) do | ||
[ | ||
FunctionNames.run(code_ast), | ||
ModuleAttributeNames.run(code_ast) | ||
] | ||
|> List.flatten() | ||
end | ||
end |
63 changes: 63 additions & 0 deletions
63
lib/elixir_analyzer/exercise_test/common_checks/function_names.ex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
defmodule ElixirAnalyzer.ExerciseTest.CommonChecks.FunctionNames do | ||
@moduledoc """ | ||
Reports the first function/macro/guard with a name that's not snake_case. | ||
Doesn't report more if there are more. | ||
A single comment should be enough for the student to know what to fix. | ||
Common check to be run on every single solution. | ||
""" | ||
|
||
alias ElixirAnalyzer.Constants | ||
alias ElixirAnalyzer.Comment | ||
|
||
@def_ops [:def, :defp, :defmacro, :defmacrop, :defguard, :defguardp] | ||
|
||
@spec run(Macro.t()) :: [{:pass | :fail | :skip, %Comment{}}] | ||
def run(ast) do | ||
{_, names} = Macro.prewalk(ast, [], &traverse/2) | ||
wrong_name = List.last(names) | ||
|
||
if wrong_name do | ||
wrong_name = to_string(wrong_name) | ||
correct_name = to_snake_case(wrong_name) | ||
|
||
[ | ||
{:fail, | ||
%Comment{ | ||
type: :actionable, | ||
comment: Constants.solution_function_name_snake_case(), | ||
params: %{ | ||
expected: correct_name, | ||
actual: wrong_name | ||
} | ||
}} | ||
] | ||
else | ||
[] | ||
end | ||
end | ||
|
||
defp traverse({op, _meta, [{name, _meta2, _arguments} | _]} = ast, names) when op in @def_ops do | ||
if snake_case?(name) do | ||
{ast, names} | ||
else | ||
{ast, [name | names]} | ||
end | ||
end | ||
|
||
defp traverse(ast, names) do | ||
{ast, names} | ||
end | ||
|
||
defp snake_case?(name) do | ||
# the code had to compile and pass all the tests to get to the analyzer | ||
# so we can assume the name is otherwise valid | ||
to_snake_case(name) == to_string(name) | ||
end | ||
|
||
defp to_snake_case(name) do | ||
# Macro.underscore is good enough because a module attribute name must be a valid Elixir identifier anyway | ||
Macro.underscore(to_string(name)) | ||
end | ||
end |
61 changes: 61 additions & 0 deletions
61
lib/elixir_analyzer/exercise_test/common_checks/module_attribute_names.ex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
defmodule ElixirAnalyzer.ExerciseTest.CommonChecks.ModuleAttributeNames do | ||
@moduledoc """ | ||
Reports the first module attribute with a name that's not snake_case. | ||
Doesn't report more if there are more. | ||
A single comment should be enough for the student to know what to fix. | ||
Common check to be run on every single solution. | ||
""" | ||
|
||
alias ElixirAnalyzer.Constants | ||
alias ElixirAnalyzer.Comment | ||
|
||
@spec run(Macro.t()) :: [{:pass | :fail | :skip, %Comment{}}] | ||
def run(ast) do | ||
{_, names} = Macro.prewalk(ast, [], &traverse/2) | ||
wrong_name = List.last(names) | ||
|
||
if wrong_name do | ||
wrong_name = to_string(wrong_name) | ||
correct_name = to_snake_case(wrong_name) | ||
|
||
[ | ||
{:fail, | ||
%Comment{ | ||
type: :actionable, | ||
comment: Constants.solution_module_attribute_name_snake_case(), | ||
params: %{ | ||
expected: correct_name, | ||
actual: wrong_name | ||
} | ||
}} | ||
] | ||
else | ||
[] | ||
end | ||
end | ||
|
||
defp traverse({:@, _meta, [{name, _meta2, _arguments}]} = ast, names) do | ||
if snake_case?(name) do | ||
{ast, names} | ||
else | ||
{ast, [name | names]} | ||
end | ||
end | ||
|
||
defp traverse(ast, names) do | ||
{ast, names} | ||
end | ||
|
||
defp snake_case?(name) do | ||
# the code had to compile and pass all the tests to get to the analyzer | ||
# so we can assume the name is otherwise valid | ||
to_snake_case(name) == to_string(name) | ||
end | ||
|
||
defp to_snake_case(name) do | ||
# Macro.underscore is good enough because a module attribute name must be a valid Elixir identifier anyway | ||
Macro.underscore(to_string(name)) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
defmodule ElixirAnalyzer.TestSuite.Default do | ||
@moduledoc """ | ||
This is the default exercise analyzer extension module. | ||
It will be run for any exercise submission that doesn't have its own extension module. | ||
It's intentionally empty, which means it will only run the common checks. | ||
""" | ||
|
||
use ElixirAnalyzer.ExerciseTest | ||
end |
Oops, something went wrong.