Skip to content

AlexBaranosky/clj-refactor.el

 
 

Repository files navigation

clj-refactor.el Build Status

A tiny collection of clojure refactoring functions. Please send help.

Installation

I highly recommend installing clj-refactor through elpa.

It's available on marmalade and melpa:

M-x package-install clj-refactor

You can also install the dependencies on your own, and just dump clj-refactor in your path somewhere:

Setup

(require 'clj-refactor)
(add-hook 'clojure-mode-hook (lambda ()
                               (clj-refactor-mode 1)
                               ;; insert keybinding setup here
                               ))

You'll also have to set up the keybindings in the lambda. Read on.

Setup keybindings

All functions in clj-refactor have a two-letter mnemonic shortcut. For instance, rename-file is rf. You get to choose how those are bound. Here's how:

(cljr-add-keybindings-with-prefix "C-c C-m")
;; eg. rename files with `C-c C-m rf`.

If you would rather have a modifier key, instead of a prefix, do:

(cljr-add-keybindings-with-modifier "C-s-")
;; eg. rename files with `C-s-r C-s-f`.

If neither of these appeal to your sense of keyboard layout aesthetics, feel free to pick and choose your own keybindings with a smattering of:

(define-key clj-refactor-map (kbd "C-x C-r") 'cljr-rename-file)

Usage

This is it so far:

  • th: thread another expression
  • uw: unwind a threaded expression
  • ua: fully unwind a threaded expression
  • tf: wrap in thread-first (->) and fully thread
  • tl: wrap in thread-last (->>) and fully thread
  • il: introduce let
  • el: expand let
  • ml: move to let
  • rf: rename file, update ns-declaration, and then query-replace new ns in project.
  • ar: add require to namespace declaration, then jump back (see optional setup)
  • au: add "use" (ie require refer all) to namespace declaration, then jump back
  • ai: add import to namespace declaration, then jump back

Combine with your keybinding prefix/modifier.

Thread / unwind example

Given this:

(map square (filter even? [1 2 3 4 5]))

Start by wrapping it in a threading macro:

(->> (map square (filter even? [1 2 3 4 5])))

And start threading away, using cljr-thread:

(->> (filter even? [1 2 3 4 5])
     (map square))

And again:

(->> [1 2 3 4 5]
     (filter even?)
     (map square))

You can also do all of these steps in one go.

Start again with:

(map square (filter even? [1 2 3 4 5]))

Put your cursor in front of the s-exp, and call cljr-thread-last-all:

(->> [1 2 3 4 5]
     (filter even?)
     (map square))

There is a corresponding cljr-thread-last-all as well.

To revert this, there's cljr-unwind to unwind one step at a time. (Just read the examples in the other direction.) Or there's cljr-unwind-all to unwind th entire expression at once.

Introduce / expand / move to let example

Given this:

(defn handle-request
  {:status 200
   :body (find-body abc)})

With the cursor in front of (find-body abc), I do cljr-introduce-let:

(defn handle-request
  {:status 200
   :body (let [X (find-body abc)]
           X)})

Now I have two cursors where the Xes are. Just type out the name, and press enter. Of course, that's not where I wanted the let statement. So I do cljr-expand-let:

(defn handle-request
  (let [body (find-body abc)]
    {:status 200
     :body body}))

Yay.

Next with the cursor in front of 200, I do cljr-move-to-let:

(defn handle-request
  (let [body (find-body abc)
        X 200]
    {:status X
     :body body}))

Again I have two cursors where the Xes are, so I type out the name, and press enter:

(defn handle-request
  (let [body (find-body abc)
        status 200]
    {:status status
     :body body}))

Pretty handy. And it works with if-let and when-let too.

Optional setup

If you're not using yasnippet, then the "jumping back"-part of adding to namespace won't work. To remedy that, enable the mode with either:

(yas/global-mode 1)

or

(add-hook 'clojure-mode-hook (lambda () (yas/minor-mode 1)))

It is an excellent package, so I recommend looking into it. Here are some snippet packages for Clojure:

Automatic insertion of namespace declaration

When you open a blank .clj-file, clj-refactor inserts the namespace declaration for you.

It will also add the relevant :use clauses in test files, normally using clojure.test, but if you're depending on midje in your project.clj it uses that instead.

Like clojure-mode, clj-refactor presumes that you are postfixing your test files with _test.

Prefer to insert your own ns-declarations? Then:

(setq clj-add-ns-to-blank-clj-files nil)

More stuff to check out

You might also like

  • align-cljlet - which is an Emacs package for aligning let-like forms.

Changelog

From 0.5 to 0.6

  • Add cljr-move-to-let (Alex Baranosky)

Contribute

Yes, please do. There's a suite of tests, so remember to add tests for your specific feature, or I might break it later.

You'll find the repo at:

https://github.com/magnars/clj-refactor.el

To fetch the test dependencies, install cask if you haven't already, then:

$ cd /path/to/clj-refactor
$ cask

Run the tests with:

$ ./run-tests.sh

Contributors

  • AlexBaranosky added support for some-> in thread and unwind, and added cljr-move-to-let

Thanks!

License

Copyright © 2012-2013 Magnar Sveen

Authors: Magnar Sveen magnars@gmail.com Keywords: clojure convenience

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

About

A tiny collection of clojure refactoring functions for Emacs

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Emacs Lisp 94.8%
  • Ruby 3.9%
  • Shell 1.3%