From 2b7b09d608ae645f771dca03ed7b79976f5415d6 Mon Sep 17 00:00:00 2001 From: Christian Koch Date: Wed, 27 Jul 2022 19:44:28 -0500 Subject: [PATCH] feature(format): support format CLI opt-out --- README.md | 1 + lib/ex_factor.ex | 24 ++++++++-------- lib/ex_factor/formatter.ex | 10 +++++-- lib/mix/tasks/ex_factor.ex | 9 ++++++ test/ex_factor/cli_test.exs | 37 +++++++++++++++++++++++- test/ex_factor/formatter_test.exs | 15 ++++++++++ test/ex_factor_test.exs | 48 +++++++++++++++++++++++++++++++ 7 files changed, 128 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 718ac7c..07ff1d5 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Use at your peril, _for now._ - [X] Add Mix.Task tests - [X] Add CLI tests - [X] Add and configure CHANGELOG tracking. + - [X] Support opt-out of format-ing ## Roadmap TODO diff --git a/lib/ex_factor.ex b/lib/ex_factor.ex index df9315f..7ffcb81 100644 --- a/lib/ex_factor.ex +++ b/lib/ex_factor.ex @@ -36,38 +36,38 @@ defmodule ExFactor do # remove should be last (before format) removals = Remover.remove(opts) - format(%{additions: emplace, changes: changes, removals: removals}, dry_run) + format(%{additions: emplace, changes: changes, removals: removals}, dry_run, opts) end def path(module) do Path.join(["lib", Macro.underscore(module) <> ".ex"]) end - defp format(%{path: nil} = struct, _dry_run), do: struct + defp format(%{path: nil} = struct, _dry_run, _format), do: struct - defp format(output, true), do: output + defp format(output, true, _format), do: output - defp format(%{additions: adds, changes: changes, removals: removals} = output, false) do + defp format(%{additions: adds, changes: changes, removals: removals} = output, false, opts) do %{ - additions: format(adds), - changes: format(changes), - removals: format(removals) + additions: format(adds, opts), + changes: format(changes, opts), + removals: format(removals, opts) } output end - defp format(list) when is_list(list) do + defp format(list, opts) when is_list(list) do Enum.map(list, fn elem -> - format(elem) + format(elem, opts) Map.get_and_update(elem, :state, fn val -> {val, [:formatted | val]} end) end) end - defp format(%{state: [:unchanged]} = struct), do: struct + defp format(%{state: [:unchanged]} = struct, _opts), do: struct - defp format(struct) do - Formatter.format([struct.path]) + defp format(struct, opts) do + Formatter.format([struct.path], opts) Map.get_and_update(struct, :state, fn val -> {val, [:formatted | val]} end) end end diff --git a/lib/ex_factor/formatter.ex b/lib/ex_factor/formatter.ex index 798f380..778d486 100644 --- a/lib/ex_factor/formatter.ex +++ b/lib/ex_factor/formatter.ex @@ -3,9 +3,13 @@ defmodule ExFactor.Formatter do `ExFactor.Formatter` Format a list of files """ - def format([nil]), do: nil + def format(args, opts \\ []) - def format(args) do - Mix.Tasks.Format.run(args) + def format([nil], _opts), do: nil + + def format(args, opts) do + if Keyword.get(opts, :format, true) do + Mix.Tasks.Format.run(args) + end end end diff --git a/lib/mix/tasks/ex_factor.ex b/lib/mix/tasks/ex_factor.ex index 899c2f0..27a86f6 100644 --- a/lib/mix/tasks/ex_factor.ex +++ b/lib/mix/tasks/ex_factor.ex @@ -27,12 +27,20 @@ defmodule Mix.Tasks.ExFactor do - `:source_path` Specify an alternate (non-standard) path for the destination file. - `:dryrun` Don't write any updates, only return the built results. - `:verbose` (Default false) include the :state and :file_contents key values. + - `:format` (Default true) when false don't run the formatter Example Usage: ``` mix ex_factor --module MyModule.ToChange --function fn_to_change --arity 2 --target YourModule.ChangeTo ``` + + Example Usage: + ``` + mix ex_factor --module MyModule.ToChange --function fn_to_change + --arity 2 --target YourModule.ChangeTo + --no-format --no-dryrun --no-verbose + ``` """ use Mix.Task @@ -44,6 +52,7 @@ defmodule Mix.Tasks.ExFactor do arity: :integer, dryrun: :boolean, verbose: :boolean, + format: :boolean, function: :string, key: :string, module: :string, diff --git a/test/ex_factor/cli_test.exs b/test/ex_factor/cli_test.exs index df20004..7e6c4ca 100644 --- a/test/ex_factor/cli_test.exs +++ b/test/ex_factor/cli_test.exs @@ -2,7 +2,7 @@ defmodule ExFactor.CLITest do use ExUnit.Case import ExUnit.CaptureIO - setup_all do + setup do File.mkdir_p("test/tmp") on_exit(fn -> @@ -60,4 +60,39 @@ defmodule ExFactor.CLITest do # no new file gets written assert {:error, :enoent} = File.read(target_path) end + + test "with --no-format" do + content = """ + defmodule ExFactorSampleModule do + @somedoc "This is somedoc" + # a comment and no aliases + _docp = "here's an arbitrary module underscore" + @spec pub1(term()) :: term() + def pub1(arg1) do + :pub1_ok + end + end + """ + + File.write("test/tmp/source_module.ex", content) + target_path = "test/tmp/target_module.ex" + + opts = [ + target_path: target_path, + target: "ExFactor.NewMod", + module: "ExFactorSampleModule", + source_path: "test/tmp/source_module.ex", + function: :pub1, + arity: 1, + format: false + ] + + argv = OptionParser.to_argv(opts) + |> IO.inspect(label: "") + + {_cli_output, exit_status} = System.cmd("mix", ["ex_factor" | argv]) + assert exit_status == 0 + file = File.read!(target_path) |> IO.inspect(label: "") + assert file =~ "\n@spec pub1(term()) :: term()\ndef pub1(arg1) do\n :pub1_ok\nend\nend" + end end diff --git a/test/ex_factor/formatter_test.exs b/test/ex_factor/formatter_test.exs index aef5255..3915e35 100644 --- a/test/ex_factor/formatter_test.exs +++ b/test/ex_factor/formatter_test.exs @@ -25,5 +25,20 @@ defmodule ExFactor.FormatterTest do assert formatted_file =~ "\n # unindented line" assert formatted_file =~ "\n # overindented line" end + + test "it should not format the specified files when format false" do + content = """ + defmodule ExFactorSampleModule do + # unindented line + # overindented line + end + """ + + File.write("test/tmp/test_module.ex", content) + Formatter.format(["test/tmp/test_module.ex"], [format: false]) + {:ok, formatted_file} = File.read("test/tmp/test_module.ex") + assert formatted_file =~ "# unindented line" + assert formatted_file =~ "\n # overindented line" + end end end diff --git a/test/ex_factor_test.exs b/test/ex_factor_test.exs index 2efe8ec..bbebf2d 100644 --- a/test/ex_factor_test.exs +++ b/test/ex_factor_test.exs @@ -72,6 +72,54 @@ defmodule ExFactorTest do refute file =~ "def refactor1([]) do" end + test "it skips formatting when specified in opts" do + File.rm("lib/ex_factor/tmp/source_module.ex") + File.rm("lib/ex_factor/tmp/target_module.ex") + + content = """ + defmodule ExFactor.Tmp.SourceModule do + @doc "this is some documentation for refactor1/1" + def refactor1([]) do + :empty + end + def refactor1(arg1) do + arg1 + end + end + """ + + File.write("lib/ex_factor/tmp/source_module.ex", content) + + content = """ + defmodule ExFactor.Tmp.TargetModule do + @doc "some docs" + def pub_exists(:error) do + :error + end + def pub_exists(arg_exists) do + arg_exists + end + end + """ + + File.write("lib/ex_factor/tmp/target_module.ex", content) + + opts = [ + target_module: "ExFactor.Tmp.TargetModule", + source_module: "ExFactor.Tmp.SourceModule", + source_function: :refactor1, + arity: 1, + format: false + ] + + %{additions: _, changes: _, removals: _} = _results = ExFactor.refactor(opts) + + file = File.read!("lib/ex_factor/tmp/target_module.ex") + + assert file =~ "\ndef refactor1(arg1) do" + assert file =~ "defmodule ExFactor.Tmp.TargetModule do\n @doc \"some docs\"" + end + test "it returns the results of the dry_run changes" do File.rm("lib/ex_factor/tmp/source_module.ex") File.rm("lib/ex_factor/tmp/target_module.ex")