From be2a382e577e7a8ac0bceaf47b52947b6efe3ef6 Mon Sep 17 00:00:00 2001 From: Christian Koch Date: Mon, 6 Sep 2021 22:21:03 -0500 Subject: [PATCH] initial commit --- .formatter.exs | 4 ++ .gitignore | 27 +++++++++++++ README.md | 21 ++++++++++ lib/ex_factor.ex | 48 +++++++++++++++++++++++ mix.exs | 29 ++++++++++++++ mix.lock | 6 +++ test/ex_factor_test.exs | 87 +++++++++++++++++++++++++++++++++++++++++ test/test_helper.exs | 1 + 8 files changed, 223 insertions(+) create mode 100644 .formatter.exs create mode 100644 .gitignore create mode 100644 README.md create mode 100644 lib/ex_factor.ex create mode 100644 mix.exs create mode 100644 mix.lock create mode 100644 test/ex_factor_test.exs create mode 100644 test/test_helper.exs diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3ca1a3d --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +ex_factor-*.tar + + +# Temporary files for e.g. tests +/tmp diff --git a/README.md b/README.md new file mode 100644 index 0000000..02cfe95 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# ExFactor + +**TODO: Add description** + +## Installation + +If [available in Hex](https://hex.pm/docs/publish), the package can be installed +by adding `ex_factor` to your list of dependencies in `mix.exs`: + +```elixir +def deps do + [ + {:ex_factor, "~> 0.1.0"} + ] +end +``` + +Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) +and published on [HexDocs](https://hexdocs.pm). Once published, the docs can +be found at [https://hexdocs.pm/ex_factor](https://hexdocs.pm/ex_factor). + diff --git a/lib/ex_factor.ex b/lib/ex_factor.ex new file mode 100644 index 0000000..e14797c --- /dev/null +++ b/lib/ex_factor.ex @@ -0,0 +1,48 @@ +defmodule ExFactor do + @moduledoc """ + Documentation for `ExFactor`. + """ + + @doc """ + Identify public functions from a module AST. + """ + def public_functions({:ok, ast}) do + # Macro.prewalk(ast, [], fn node, acc -> + # # walk_ast(node, acc, :def) + # {node, walk_ast(node, acc, :def)} + # # |> IO.inspect(label: "walk_ast") + # end) + + Macro.postwalk(ast, [], fn node, acc -> + # walk_ast(node, acc, :def) + {node, walk_ast(node, acc, :def)} + # |> IO.inspect(label: "walk_ast") + end) + end + + def private_functions({:ok, ast}) do + # Macro.prewalk(ast, [], fn node, acc -> + # # walk_ast(node, acc, :def) + # {node, walk_ast(node, acc, :def)} + # # |> IO.inspect(label: "walk_ast") + # end) + + Macro.postwalk(ast, [], fn node, acc -> + # walk_ast(node, acc, :def) + {node, walk_ast(node, acc, :defp)} + # |> IO.inspect(label: "walk_ast") + end) + end + + defp walk_ast({tkn, _, [{name, _meta, _args} | _]} = func, acc, token) when tkn == token do + # func |> IO.inspect(label: "walk func TOKEN: #{token}") + map = %{name: name, ast: func} + [map | acc] + end + + defp walk_ast(_func, acc, _token) do + # func |> IO.inspect(label: "walk fallback token: #{token}") + acc + # |> IO.inspect(label: "fallback accum") + end +end diff --git a/mix.exs b/mix.exs new file mode 100644 index 0000000..625a1e8 --- /dev/null +++ b/mix.exs @@ -0,0 +1,29 @@ +defmodule ExFactor.MixProject do + use Mix.Project + + def project do + [ + app: :ex_factor, + version: "0.1.0", + elixir: "~> 1.11", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications. + def application do + [ + extra_applications: [:logger] + ] + end + + # Run "mix help deps" to learn about dependencies. + defp deps do + [ + {:credo, ">= 1.5.0", only: [:dev, :test]} + # {:dep_from_hexpm, "~> 0.3.0"}, + # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} + ] + end +end diff --git a/mix.lock b/mix.lock new file mode 100644 index 0000000..bf1731d --- /dev/null +++ b/mix.lock @@ -0,0 +1,6 @@ +%{ + "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, + "credo": {:hex, :credo, "1.5.6", "e04cc0fdc236fefbb578e0c04bd01a471081616e741d386909e527ac146016c6", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "4b52a3e558bd64e30de62a648518a5ea2b6e3e5d2b164ef5296244753fc7eb17"}, + "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, + "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, +} diff --git a/test/ex_factor_test.exs b/test/ex_factor_test.exs new file mode 100644 index 0000000..787e8f5 --- /dev/null +++ b/test/ex_factor_test.exs @@ -0,0 +1,87 @@ +defmodule ExFactorTest do + use ExUnit.Case + + test "it should report public fns" do + {_ast, [f1]} = """ + defmodule CredoSampleModule do + @somedoc "This is somedoc" + # no aliases + def pub1(arg1) do + :ok + end + end + """ + |> Code.string_to_quoted() + |> ExFactor.public_functions() + + assert f1.name == :pub1 + end + + test "it should report TWO public fns" do + {_ast, [f1, f2]} = """ + defmodule CredoSampleModule do + @somedoc "This is somedoc" + # no aliases + def pub1(arg1) do + :ok + end + + def pub2(arg2) do + :yes + end + + defp pub3(arg3) do + :private + end + end + """ + |> Code.string_to_quoted() + |> ExFactor.public_functions() + assert f2.name == :pub1 + assert f1.name == :pub2 + end + + test "it should report private fns" do + {_ast, [f1]} = """ + defmodule CredoSampleModule do + @somedoc "This is somedoc" + # no aliases + defp priv1(arg1) do + :ok + end + end + """ + |> Code.string_to_quoted() + |> ExFactor.private_functions() + + assert f1.name == :priv1 + end + + test "it should report TWO private fns" do + {_ast, [f1, f2]} = """ + defmodule CredoSampleModule do + @somedoc "This is somedoc" + # no aliases + def pub1(arg1) do + :ok + end + + def pub2(arg2) do + :yes + end + + defp priv3(arg3) do + :private + end + + defp priv4(arg4) do + :private + end + end + """ + |> Code.string_to_quoted() + |> ExFactor.private_functions() + assert f2.name == :priv3 + assert f1.name == :priv4 + end +end diff --git a/test/test_helper.exs b/test/test_helper.exs new file mode 100644 index 0000000..869559e --- /dev/null +++ b/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start()