Skip to content

Commit

Permalink
Fix error on projects with nested modules (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
brunvez committed May 12, 2022
1 parent bb58b93 commit f3f9822
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 32 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

### Bug fixes
- Fix multiple versions or errors for injected functions
- Fix error on project with nested modules

## 0.1.1 (2022-05-09)

Expand Down
6 changes: 3 additions & 3 deletions lib/scapa/cli.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ defmodule Scapa.CLI do
defp add_versions_to_file(file_path) do
file_content = File.read!(file_path)

case funtions_to_versionate(file_content) do
case funtions_to_versionate(file_content, file_path) do
[] ->
nil

Expand All @@ -40,9 +40,9 @@ defmodule Scapa.CLI do
end
end

defp funtions_to_versionate(file_contents) do
defp funtions_to_versionate(file_contents, file_path) do
file_contents
|> Code.string_to_quoted!()
|> Code.string_to_quoted!(file: file_path)
|> Scapa.Code.defined_modules()
|> Enum.flat_map(&Scapa.Code.functions_with_doc({:module, &1, file_contents}))
|> Enum.sort_by(&FunctionDefinition.line_number/1)
Expand Down
35 changes: 24 additions & 11 deletions lib/scapa/code.ex
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,29 @@ defmodule Scapa.Code do

@doc """
Returns the modules defined in an AST as modules.
## Examples
iex> ast = quote do defmodule Scapa do defmodule Scapa.Insider, do: nil end end
iex> Scapa.Code.defined_modules(ast)
[Scapa.Insider, Scapa]
"""
@spec defined_modules(Macro.t()) :: [atom()]
@spec defined_modules(Macro.t(), [String.t()]) :: [atom()]
@doc version: "84273486"
def defined_modules(ast) do
def defined_modules(ast, prefix \\ ["Elixir"]) do
ast
|> Macro.prewalk([], fn
{:defmodule, _, [{:__aliases__, _, module_name} | _]} = t, acc ->
{t, [module_name | acc]}
{:defmodule, _, [{:__aliases__, _, module_name} | inner]} = t, acc ->
module_name = Enum.map(module_name, &Atom.to_string/1)
inner_modules = defined_modules(inner, prefix ++ module_name)
acc = inner_modules ++ acc

case get_module(module_name, prefix) do
{:module, module} ->
{t, [module | acc]}

{:error, _} ->
{t, acc}
end

t, acc ->
{t, acc}
end)
|> elem(1)
|> Enum.map(&Enum.join(["Elixir"] ++ &1, "."))
|> Enum.map(&String.to_existing_atom/1)
end

defp functions_defined_in_source(module_source) do
Expand Down Expand Up @@ -137,4 +140,14 @@ defmodule Scapa.Code do
end
)
end

defp get_module(name, prefix) do
(prefix ++ name)
|> Enum.join(".")
|> String.to_existing_atom()
|> Code.ensure_compiled()
rescue
ArgumentError ->
{:error, :nonexistent_atom}
end
end
35 changes: 17 additions & 18 deletions test/scapa/code_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ defmodule Scapa.CodeTest do

assert [] = function_docs(docs, :private_fun)
end

test "does not include type docs", %{Scapa.ModuleWithTypedoc => module_source} do
docs = Code.functions_with_doc({:module, Scapa.ModuleWithTypedoc, module_source})

assert [] = function_docs(docs, :num)
end
end

describe "upsert_doc_version/3" do
Expand Down Expand Up @@ -213,36 +219,29 @@ defmodule Scapa.CodeTest do
assert [Scapa] = Code.defined_modules(ast)
end

test "returns nested modules" do
ast =
quote do
defmodule Scapa do
defmodule Scapa.Insider, do: nil
end
end

assert [Scapa.Insider, Scapa] = Code.defined_modules(ast)
end
test "returns nested modules and sibling modules" do
ast = Elixir.Code.string_to_quoted!(File.read!("test/support/nested_module.ex"))

test "returns sibling modules" do
ast =
quote do
defmodule Scapa, do: nil
defmodule Scapa.Sibling, do: nil
end

assert [Scapa.Sibling, Scapa] = Code.defined_modules(ast)
assert [
NestedModule,
NestedModule.Sibling,
NestedModule.Level1.AndSomethingElse,
NestedModule.Level1.AndSomethingElse.Level2
] = Code.defined_modules(ast)
end
end

setup_all do
module_with_doc = File.read!(Path.absname("../support/module_with_doc.ex", __DIR__))

module_with_typedoc = File.read!(Path.absname("../support/module_with_typedoc.ex", __DIR__))

module_with_hidden_doc =
File.read!(Path.absname("../support/module_with_hidden_doc.ex", __DIR__))

%{
Scapa.ModuleWithDoc => module_with_doc,
Scapa.ModuleWithTypedoc => module_with_typedoc,
Scapa.ModuleWithHiddenDoc => module_with_hidden_doc
}
end
Expand Down
10 changes: 10 additions & 0 deletions test/support/module_with_typedoc.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
defmodule Scapa.ModuleWithTypedoc do
@moduledoc """
Test module used to test typedocs
"""

@typedoc """
Pretty alias for string
"""
@type source :: String.t()
end
12 changes: 12 additions & 0 deletions test/support/nested_module.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defmodule NestedModule do
@moduledoc false
defmodule Level1.AndSomethingElse do
@moduledoc false
defmodule Level2 do
@moduledoc false
def hi, do: "Howdy!"
end
end

defmodule Sibling, do: @moduledoc(false)
end

0 comments on commit f3f9822

Please sign in to comment.