Current section
Files
Jump to
Current section
Files
lib/ecto_schema_directories.ex
defmodule Nicene.EctoSchemaDirectories do
@moduledoc """
Ecto schemas should not be in directories with other types of files.
"""
@explanation [check: @moduledoc]
require Logger
use Credo.Check, base_priority: :high, category: :refactoring
@doc false
def run(source_file, params \\ []) do
is_schema? = Credo.Code.prewalk(source_file, &schema?/2, false)
if is_schema? do
sibling_contents = get_sibling_file_contents(source_file.filename)
ensure_all_siblings_are_schema(source_file, sibling_contents, params)
else
[]
end
end
# exported for testing purposes only
@doc false
def ensure_all_siblings_are_schema(source_file, sibling_contents, params) do
if Enum.all?(sibling_contents, &schema?/1) do
[]
else
issue_meta = IssueMeta.for(source_file, params)
[issue_for(issue_meta, source_file.filename)]
end
end
defp get_sibling_file_contents(filename) do
"#{Path.dirname(filename)}/*.ex"
|> Path.wildcard()
|> Enum.reduce([], fn file, acc ->
case File.read(file) do
{:ok, binary} ->
[binary | acc]
{:error, error} ->
Logger.warn("Unable to read file #{file} - #{inspect(error)}")
acc
end
end)
end
defp schema?(code) do
code
|> Code.string_to_quoted()
|> Credo.Code.prewalk(&schema?/2, false)
end
defp schema?({:schema, _, [schema, _]} = ast, _) when is_binary(schema) do
{ast, true}
end
defp schema?({:embedded_schema, _, _} = ast, _) do
{ast, true}
end
defp schema?(ast, acc) do
{ast, acc}
end
defp issue_for(issue_meta, filename) do
format_issue(issue_meta,
message: "#{filename} is in a directory with files that are not Ecto schemas"
)
end
end