Skip to content

Commit

Permalink
add docs, exceptions, mix task
Browse files Browse the repository at this point in the history
  • Loading branch information
ckoch-cars committed Sep 17, 2021
1 parent aa940c3 commit 108369e
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 8 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ to a new file/module. At this time, ExFactor cannot change the function arity.
mix exfactor -m MyApp.MyMod -f [my_func: 2] -mm MyApp.MyNewMod -mf :my_new_func
```

## Roadmap

- [] Write the module code to rename usages of the refactored function
- [] Update .exs files too?
- [] Write tests to ensure we can find modules within and across umbrella apps.
- [X] Write a mix task to invoke the Refactorer
- [] ElixirLS integration for VSCode?
- [] Add configuration hooks?

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
Expand All @@ -18,7 +27,7 @@ by adding `ex_factor` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:ex_factor, "~> 0.1.0"}
{:ex_factor, "~> 0.1.0", only: [:dev]}
]
end
```
Expand Down
24 changes: 17 additions & 7 deletions lib/ex_factor/extractor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,23 @@ defmodule ExFactor.Extractor do
Given a keyword list of opts, find the function in the specified source.
Add the function (and any accociated attrs: @doc, @spec, ) into the target module. refactor it, the docs,
specs, and any miscellaneous attrs proximate to the source function into the specified module.
Required keys:
- :source_module
- :target_module
- :source_function
- :arity
Optional keys:
- :source_path Specify an alternate (non-standard) path for the source module
- :target_path Specify an alternate (non-standard) path for the destination module
"""

def emplace(opts) do
source_module = Keyword.get(opts, :source_module)
target_module = Keyword.get(opts, :target_module)
source_function = Keyword.get(opts, :source_function)
arity = Keyword.get(opts, :arity)
source_module = Keyword.fetch!(opts, :source_module)
target_module = Keyword.fetch!(opts, :target_module)
source_function = Keyword.fetch!(opts, :source_function)
arity = Keyword.fetch!(opts, :arity)
target_path = Keyword.get(opts, :target_path, path(target_module))
source_path = Keyword.get(opts, :source_path, path(source_module))
{_ast, block_contents} = Parser.block_contents(source_path)
Expand Down Expand Up @@ -52,9 +62,9 @@ defmodule ExFactor.Extractor do
Remove the indicated function and its spec from it's original file.
"""
def remove(opts) do
source_module = Keyword.get(opts, :source_module)
source_function = Keyword.get(opts, :source_function)
arity = Keyword.get(opts, :arity)
source_module = Keyword.fetch!(opts, :source_module)
source_function = Keyword.fetch!(opts, :source_function)
arity = Keyword.fetch!(opts, :arity)
source_path = Keyword.get(opts, :source_path, path(source_module))
|> IO.inspect(label: "REMOVE source_path")

Expand Down
42 changes: 42 additions & 0 deletions lib/mix/tasks/ex_factor/refactor.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
defmodule Mix.Tasks.ExFactor.Refactor do
@shortdoc """
Refactor a module, function, and arity to a new module namespace. Find or create the new module as appropriate.
Required command line args: --module, --function, --arity, --target. (See additional explantion in: #{__MODULE__})
"""

@moduledoc """
`ExFactor` is a refactoring helper.
By identifying a Module, function name, and arity, it will identify all non-test usages
and extract them to a new Module.
If the Module exists, it adds the refactored function to the end of the file and change all calls to the
new module's name. If the Module does not exist ExFactor will conditionally create the path and the module
and the refactored function will be added to the new module.
Required command line args: --module, --function, --arity, --target.
- `:module` is the fully-qualified source module containing the function to move.
- `:function` is the name of the function (as a string)
- `:arity` the arity of function to move.
- `:target` is the fully-qualified destination for the removed function. If the moduel does not exist, it will be created.
Optional command line args: --source_path, --target_path
- `:target_path` Specify an alternate (non-standard) path for the source file.
- `:source_path` Specify an alternate (non-standard) path for the destination file.
"""

use Mix.Task

def run(argv) do
{opts, _extra_opts} = OptionParser.parse(argv, switches: [arity: :integer, module: :string, function: :string, target: :string, key: :string])
|> IO.inspect(label: "OptionParser")
# opts = Mix.shell().info(Enum.join(argv, " "))
opts
|> IO.inspect(label: "PARSED ARGS")

# Mix.Task.run("app.start")

ExFactor.refactor(opts)
end
end
12 changes: 12 additions & 0 deletions test/ex_factor/extractor_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ defmodule ExFactor.ExtractorTest do
alias ExFactor.Extractor

describe "emplace/1" do
test "requires some options" do
opts = [
# target_module: ExFactor.NewMod,
source_module: ExFactorSampleModule,
source_function: :pub1,
arity: 1
]

assert_raise KeyError, "key :target_module not found in: #{inspect(opts)}", fn -> Extractor.emplace(opts) end
# assert message == ""
end

test "write a new file with the function" do
content = """
defmodule ExFactorSampleModule do
Expand Down

0 comments on commit 108369e

Please sign in to comment.