Skip to content

Instantly share code, notes, and snippets.

@bryanjos
Created April 5, 2019 20:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bryanjos/7f3e0dcd7adb80d9d988e9daf7abbcfa to your computer and use it in GitHub Desktop.
Save bryanjos/7f3e0dcd7adb80d9d988e9daf7abbcfa to your computer and use it in GitHub Desktop.
ExFactor
defmodule ExFactor.CodeError do
defexception [:message]
end
defmodule ExFactor do
@moduledoc """
Documentation for ExFactor.
"""
defstruct code: nil, changes: []
alias ExFactor.CodeError
@spec new() :: ExFactor.t()
def new do
%ExFactor{}
end
@spec with_code(ExFactor.t(), binary()) :: ExFactor.t()
def with_code(ex_factor, code) do
%{ex_factor | code: code}
end
@spec rename_variable(ExFactor.t(), atom(), atom()) :: ExFactor.t()
def rename_variable(ex_factor, from, to) when is_atom(from) and is_atom(to) do
%{
ex_factor
| changes: ex_factor.changes ++ [%{operation: :rename_variable, from: from, to: to}]
}
end
@spec refactor(ExFactor.t()) :: binary()
def refactor(%ExFactor{code: code}) when code in ["", nil] do
raise CodeError, message: "No code given"
end
def refactor(%ExFactor{code: code, changes: []}) do
code
end
def refactor(%ExFactor{code: code, changes: changes}) do
ast = Code.string_to_quoted!(code)
Enum.reduce(changes, ast, fn %{operation: :rename_variable, from: from, to: to}, ast ->
Macro.postwalk(ast, fn
{^from, meta, nil} ->
{to, meta, nil}
node ->
node
end)
end)
|> Macro.to_string()
end
end
defmodule ExFactorTest do
use ExUnit.Case
doctest ExFactor
test "rename variable" do
code = "a = 1"
refactored_code =
ExFactor.new()
|> ExFactor.with_code(code)
|> ExFactor.rename_variable(:a, :b)
|> ExFactor.refactor()
assert refactored_code == "b = 1"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment