andyl / rfx

Refactoring Operations for Elixir
MIT License
41 stars 4 forks source link

Rfx : ReFactor Elixir

Rfx provides a catalog of automated refactoring operations for Elixir source code.

Rfx operations are meant to be embedded into editors, tools and end-user apps. See the experimental rfxi for an example app. Rfx depends on the excellent Sourceror to manipulate AST code and comments.

To get started with this pre-release code, clone the repo, then run > mix test. NOTE this code is under heavy development - expect rapid changes and bugs!

Ops Modules

See Rfx.Catalog.OpsCat for a live catalog of Operations.

Module Operations:

Function Operations:

Filesystem Operations:

Credo Operations:

Surface Operations:

PhxGen Operations:

Project Operations:

Prototype Operations:

Change Sets

Each operation returns a change set (Rfx.Change.Set) with a list of of change requests (Rfx.Change.Request). The change set is a data structure that describes all the refactoring changes to be made for an operation.

A change request struct has elements for text edits and file actions (create, rename, delete).

Converter Functions

Rfx provides an extensible catalog of converter functions:

Rfx.Change.Set.convert(changeset, :to_string)    #> Returns the modified source code
Rfx.Change.Set.convert(changeset, :to_patchfile) #> Returns a unix-standard patchfile
Rfx.Change.Set.convert(changeset, :to_lsp)       #> Returns a data structure for LSP
Rfx.Change.Set.convert(changeset, :to_pr)        #> Returns a pull-request data structure

Rfx also provides a function that applies the change requests to the filesystem.

Rfx.Change.Set.apply!(changeset)                 #> Applies the changereqs to the filesystem

Code Organization

Each operation is coded in a standalone module that implements the Rfx.Ops behavior. A refactoring operation may be applied to different scopes:

Each scope will generate a different set of change requests. Consider for example the operation Rfx.Ops.Module.RenameModule.

Rename_Module # of Change Requests Text Edits File Actions
Scope1 code 1 Edit src & docs NA
Scope2 file 1 Edit src & docs Rename Src file
Scope3 project 1 for each related project file Edit src & docs Rename Src & Test file
Scope4 subapp 1 for each related subapp file Edit src & docs Rename Src & Test file
Scope5 tmpfile 1 Edit src & docs NA

Here's a code example:

#!/usr/bin/env elixir

Mix.install([ {:rfx, github: "andyl/rfx"} ])

"x = 1"
|> Rfx.Ops.Proto.CommentAdd.cl_code()
|> Rfx.Change.Set.convert(:to_string)
|> IO.inspect()

# [
#   %Rfx.Change.Request{
#     file_req: nil,
#     text_req: %{diff: "0a1\n> # TestComment\n", input_text: "x = 1"},
#     log: %{convert: %{to_string: "# TestComment\nx = 1"}}
#   }
# ]

Clients

Rfx Operations are intended for use in developer tools:

Installation

def deps do
  [
    {:rfx, github: "andyl/rfx"}
  ]
end