Endless Parentheses

Ramblings on productivity and technical subjects.

profile for Malabarba on Stack Exchange

clj-refactor — Unleash your Clojure wizard.

When I first started learning Clojure, I was charmed by how well integrated CIDER was with Emacs. In many ways, it felt just like writing Emacs-lisp. Nowadays, that feeling has gone slightly past the goal mark, and there are actually features I miss when I’m writing elisp. Clj-refactor is one of them.

This package is a Swiss knife of refactoring utilities for Clojure. From simple operations like turning a form into a -> thread, to the more complex situations like renaming entire namespaces, it’s hard to find something clj-refactor can’t do.

I won’t list all of them here, they already have a nice wiki page for that. The point here is to expose a few features (the ones I find most useful) and hopefully that’ll get you started on the road to enlightenment. To see some of the features in play (at a pretty quick pace), you can check out Magnar’s Parens of the dead videos. I also plan on doing a proper and thorough video review of this package in the future.

First, and most importantly, are the threading commands. These allow you to instantly turn something like (filter odd? (map inc (range n))) into

(->> (range n)
     (map inc)
     (filter odd?))

or back again. Clj-refactor default keybinds are pretty well thought out, but I use these commands so frequently that I felt the need to shorten them to just 2 or 3 keys.

(with-eval-after-load 'clj-refactor
  (setq cljr-thread-all-but-last t)
  (define-key clj-refactor-map "\C-ctf" #'cljr-thread-first-all)
  (define-key clj-refactor-map "\C-ctl" #'cljr-thread-last-all)
  (define-key clj-refactor-map "\C-cu" #'cljr-unwind)
  (define-key clj-refactor-map "\C-cU" #'cljr-unwind-all))

Next is another feature that comes up a lot, but this one doesn’t even take up a keybind. When you type /, clj-refactor will look at the alias you’ve just written, and try to add a require for it in the ns form. The current snapshot release is very smart about it, and actually learns what alias you use for each namespace by looking at other files in the same project. You can also define your preferences with the cljr-magic-require-namespaces variable.

(with-eval-after-load 'clj-refactor
  (add-to-list 'cljr-magic-require-namespaces
               '("s"  . "clojure.string")))

Another command you should definitely memorize is cljr-create-fn-from-example.
Instead of specifying a custom key for this one, we’ll just let the package define all other keys for us.

(with-eval-after-load 'clj-refactor
  (cljr-add-keybindings-with-prefix "\C-cr"))

The nice thing about the default keys is that they’re mnemonic, and you might remember I have an entire series on this topic. The point being: it’s very easy to remember that cljr-create-fn-from-example is bound to C-c r f e when you can actually sing “clojure refactor from example” as you’re typing.

A few others I use a lot (and the keys they’re bound to) are introduce-let (i l), move-to-let (m l), and promote-function (p f).

Lastly, some miscellaneous configurations that simply reflect my personal preferences, but which you should be aware of nonetheless.

(setq cljr-auto-sort-ns t)
(setq cljr-favor-prefix-notation nil)
(setq cljr-favor-private-functions nil)
(setq cljr-clojure-test-declaration
      "[clojure.test :refer :all]")
comments powered by Disqus