diff --git a/CHANGELOG.md b/CHANGELOG.md index 626981ad..9430cabc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## master (unreleased) +### New features + +* Port cycle privacy, cycle collection type and cycle if/if-not from clj-refactor.el. +* Rework cycle collection type into convert collection to list, quoted list, map, vector, set. + ## 5.4.0 (2016-05-21) ### New features diff --git a/README.md b/README.md index 2d1710d5..2af13556 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,8 @@ specific `clojure-mode` release.** - [Vertical alignment](#vertical-alignment) - [Refactoring support](#refactoring-support) - [Threading macros](#threading-macros-related-features) + - [Cycling things](#cycling-things) + - [Convert collection](#convert-collection) - [Related packages](#related-packages) - [REPL Interaction](#repl-interaction) - [Basic REPL](#basic-repl) @@ -258,6 +260,20 @@ argument do not thread the last form. See demonstration on the Unwind and remove the threading macro. See demonstration on the [clj-refactor.el wiki](https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-unwind-all). +### Cycling things + +* Cycle privacy + +Cycle privacy of `def`s or `defn`s. Use metadata explicitly with setting `clojure-use-metadata-for-privacy` to `t` for `defn`s too. See demonstration on the [clj-refactor.el wiki](https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-cycle-privacy). + +* Cycle if/if-not + +Find the closest if or if-not up the syntax tree and toggle it. Also transpose the "else" and "then" branches, keeping the semantics the same as before. See demonstration on the [clj-refactor.el wiki](https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-cycle-if). + +### Convert collection + +Convert any given collection at point to list, quoted list, map, vector or set. + ## Related packages * [clojure-mode-extra-font-locking][] provides additional font-locking diff --git a/clojure-mode.el b/clojure-mode.el index 2f14ecc4..c511bc7f 100644 --- a/clojure-mode.el +++ b/clojure-mode.el @@ -205,6 +205,20 @@ Out-of-the box clojure-mode understands lein, boot and gradle." (define-key map (kbd "C-c C-r l") #'clojure-thread-last-all) (define-key map (kbd "C-c C-r C-a") #'clojure-unwind-all) (define-key map (kbd "C-c C-r a") #'clojure-unwind-all) + (define-key map (kbd "C-c C-r C-p") #'clojure-cycle-privacy) + (define-key map (kbd "C-c C-r p") #'clojure-cycle-privacy) + (define-key map (kbd "C-c C-r C-(") #'clojure-convert-collection-to-list) + (define-key map (kbd "C-c C-r (") #'clojure-convert-collection-to-list) + (define-key map (kbd "C-c C-r C-'") #'clojure-convert-collection-to-quoted-list) + (define-key map (kbd "C-c C-r '") #'clojure-convert-collection-to-quoted-list) + (define-key map (kbd "C-c C-r C-{") #'clojure-convert-collection-to-map) + (define-key map (kbd "C-c C-r {") #'clojure-convert-collection-to-map) + (define-key map (kbd "C-c C-r C-[") #'clojure-convert-collection-to-vector) + (define-key map (kbd "C-c C-r [") #'clojure-convert-collection-to-vector) + (define-key map (kbd "C-c C-r C-#") #'clojure-convert-collection-to-set) + (define-key map (kbd "C-c C-r #") #'clojure-convert-collection-to-set) + (define-key map (kbd "C-c C-r C-i") #'clojure-cycle-if) + (define-key map (kbd "C-c C-r i") #'clojure-cycle-if) (define-key map (kbd "C-c C-r n i") #'clojure-insert-ns-form) (define-key map (kbd "C-c C-r n h") #'clojure-insert-ns-form-at-point) (define-key map (kbd "C-c C-r n u") #'clojure-update-ns) @@ -213,11 +227,19 @@ Out-of-the box clojure-mode understands lein, boot and gradle." '("Clojure" ["Toggle between string & keyword" clojure-toggle-keyword-string] ["Align expression" clojure-align] + ["Cycle privacy" clojure-cycle-privacy] + ["Cycle if, if-not" clojure-cycle-if] ("ns forms" ["Insert ns form at the top" clojure-insert-ns-form] ["Insert ns form here" clojure-insert-ns-form-at-point] ["Update ns form" clojure-update-ns] ["Sort ns form" clojure-sort-ns]) + ("Convert collection" + ["Convert to list" clojure-convert-collection-to-list] + ["Convert to quoted list" clojure-convert-collection-to-quoted-list] + ["Convert to map" clojure-convert-collection-to-map] + ["Convert to vector" clojure-convert-collection-to-vector] + ["Convert to set" clojure-convert-collection-to-set]) ("Refactor -> and ->>" ["Thread once more" clojure-thread] ["Fully thread a form with ->" clojure-thread-first-all] @@ -1629,6 +1651,8 @@ This will skip over sexps that don't represent objects, so that ^hints and ;; Refactoring support ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; Threading macros related (defcustom clojure-thread-all-but-last nil "Non-nil means do not thread the last expression. This means that `clojure-thread-first-all' and @@ -1824,6 +1848,106 @@ When BUT-LAST is passed the last expression is not threaded." (interactive "P") (clojure--thread-all "->> " but-last)) +;;; Cycling stuff + +(defcustom clojure-use-metadata-for-privacy nil + "If nil, `clojure-cycle-privacy' will use (defn- f []). +If t, it will use (defn ^:private f [])." + :package-version '(clojure-mode . "5.5.0") + :safe #'booleanp + :type 'boolean) + +;;;###autoload +(defun clojure-cycle-privacy () + "Make public the current private def, or vice-versa. +See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-cycle-privacy" + (interactive) + (save-excursion + (ignore-errors (forward-char 7)) + (search-backward-regexp "(defn?\\(-\\| ^:private\\)?\\_>") + (if (match-string 1) + (replace-match "" nil nil nil 1) + (goto-char (match-end 0)) + (insert (if (or clojure-use-metadata-for-privacy + (equal (match-string 0) "(def")) + " ^:private" + "-"))))) + +(defun clojure--convert-collection (coll-open coll-close) + "Convert the collection at (point) by unwrapping it an wrapping it between COLL-OPEN and COLL-CLOSE." + (save-excursion + (while (and + (not (bobp)) + (not (looking-at "(\\|{\\|\\["))) + (backward-char)) + (when (or (eq ?\# (char-before)) + (eq ?\' (char-before))) + (delete-char -1)) + (when (and (bobp) + (not (memq (char-after) '(?\{ ?\( ?\[)))) + (user-error "Beginning of file reached, collection is not found")) + (insert coll-open (substring (clojure-delete-and-extract-sexp) 1 -1) coll-close))) + +;;;###autoload +(defun clojure-convert-collection-to-list () + "Convert collection at (point) to list." + (interactive) + (clojure--convert-collection "(" ")")) + +;;;###autoload +(defun clojure-convert-collection-to-quoted-list () + "Convert collection at (point) to quoted list." + (interactive) + (clojure--convert-collection "'(" ")")) + +;;;###autoload +(defun clojure-convert-collection-to-map () + "Convert collection at (point) to map." + (interactive) + (clojure--convert-collection "{" "}")) + +;;;###autoload +(defun clojure-convert-collection-to-vector () + "Convert collection at (point) to vector." + (interactive) + (clojure--convert-collection "[" "]")) + +;;;###autoload +(defun clojure-convert-collection-to-set () + "Convert collection at (point) to set." + (interactive) + (clojure--convert-collection "#{" "}")) + +(defun clojure--goto-if () + (when (in-string-p) + (while (or (not (looking-at "(")) + (in-string-p)) + (backward-char))) + (while (not (looking-at "\\((if \\)\\|\\((if-not \\)")) + (condition-case nil + (backward-up-list) + (scan-error (user-error "No if or if-not found"))))) + +;;;###autoload +(defun clojure-cycle-if () + "Change a surrounding if to if-not, or vice-versa. + +See: https://github.com/clojure-emacs/clj-refactor.el/wiki/cljr-cycle-if" + (interactive) + (save-excursion + (clojure--goto-if) + (cond + ((looking-at "(if-not") + (forward-char 3) + (delete-char 4) + (forward-sexp 2) + (transpose-sexps 1)) + ((looking-at "(if") + (forward-char 3) + (insert "-not") + (forward-sexp 2) + (transpose-sexps 1))))) + ;;; ClojureScript (defconst clojurescript-font-lock-keywords diff --git a/test/clojure-mode-convert-collection-test.el b/test/clojure-mode-convert-collection-test.el new file mode 100644 index 00000000..7b6dc02a --- /dev/null +++ b/test/clojure-mode-convert-collection-test.el @@ -0,0 +1,75 @@ +;;; clojure-mode-convert-collection-test.el --- Clojure Mode: convert collection type -*- lexical-binding: t; -*- + +;; Copyright (C) 2016 Benedek Fazekas + +;; This file is not part of GNU Emacs. + +;; 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 . + +;;; Commentary: + +;; The convert collection code originally was implemented +;; as cycling collection type in clj-refactor.el and is the work +;; of the clj-reafctor.el team. + +;;; Code: + +(require 'clojure-mode) +(require 'ert) + +(def-refactor-test test-convert-collection-list-map + "(:a 1 :b 2)" + "{:a 1 :b 2}" + (backward-sexp) + (down-list) + (clojure-convert-collection-to-map)) + +(def-refactor-test test-convert-collection-map-vector + "{:a 1 :b 2}" + "[:a 1 :b 2]" + (backward-sexp) + (down-list) + (clojure-convert-collection-to-vector)) + +(def-refactor-test test-convert-collection-vector-set + "[1 2 3]" + "#{1 2 3}" + (backward-sexp) + (down-list) + (clojure-convert-collection-to-set)) + +(def-refactor-test test-convert-collection-set-list + "#{1 2 3}" + "(1 2 3)" + (backward-sexp) + (down-list) + (clojure-convert-collection-to-list)) + +(def-refactor-test test-convert-collection-set-quoted-list + "#{1 2 3}" + "'(1 2 3)" + (backward-sexp) + (down-list) + (clojure-convert-collection-to-quoted-list)) + +(def-refactor-test test-convert-collection-quoted-list-set + "'(1 2 3)" + "#{1 2 3}" + (backward-sexp) + (down-list) + (clojure-convert-collection-to-set)) + +(provide 'clojure-mode-convert-collection-test) + +;;; clojure-mode-convert-collection-test.el ends here diff --git a/test/clojure-mode-cycling-test.el b/test/clojure-mode-cycling-test.el new file mode 100644 index 00000000..5b2371d8 --- /dev/null +++ b/test/clojure-mode-cycling-test.el @@ -0,0 +1,118 @@ +;;; clojure-mode-cycling-test.el --- Clojure Mode: cycling things tests -*- lexical-binding: t; -*- + +;; Copyright (C) 2016 Benedek Fazekas + +;; This file is not part of GNU Emacs. + +;; 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 . + +;;; Commentary: + +;; The cycling privacy and if/if-not code is ported from +;; clj-refactor.el and the work of the clj-reafctor.el team. + +;;; Code: + +(require 'clojure-mode) +(require 'ert) + +(def-refactor-test test-cycle-privacy-public-defn-private-defn + "(defn add [a b] + (+ a b))" + "(defn- add [a b] + (+ a b))" + (clojure-cycle-privacy)) + +(def-refactor-test test-cycle-privacy-from-sexp-beg + "(defn- add [a b] + (+ a b))" + "(defn add [a b] + (+ a b))" + (backward-sexp) + (clojure-cycle-privacy)) + +(def-refactor-test test-cycle-privacy-public-defn-private-defn-metadata + "(defn add [a b] + (+ a b))" + "(defn ^:private add [a b] + (+ a b))" + (let ((clojure-use-metadata-for-privacy t)) + (clojure-cycle-privacy))) + +(def-refactor-test test-cycle-privacy-private-defn-public-defn + "(defn- add [a b] + (+ a b))" + "(defn add [a b] + (+ a b))" + (clojure-cycle-privacy)) + +(def-refactor-test test-cycle-privacy-private-defn-public-defn-metadata + "(defn ^:private add [a b] + (+ a b))" + "(defn add [a b] + (+ a b))" + (let ((clojure-use-metadata-for-privacy t)) + (clojure-cycle-privacy))) + +(def-refactor-test test-cycle-privacy-public-def-private-def + "(def ^:dynamic config + \"docs\" + {:env \"staging\"})" + "(def ^:private ^:dynamic config + \"docs\" + {:env \"staging\"})" + (clojure-cycle-privacy)) + +(def-refactor-test test-cycle-privacy-private-def-public-def + "(def ^:private config + \"docs\" + {:env \"staging\"})" + "(def config + \"docs\" + {:env \"staging\"})" + (clojure-cycle-privacy)) + +(def-refactor-test test-cycle-if-inner-if + "(if this + (if that + (then AAA) + (else BBB)) + (otherwise CCC))" + "(if this + (if-not that + (else BBB) + (then AAA)) + (otherwise CCC))" + (beginning-of-buffer) + (search-forward "BBB)") + (clojure-cycle-if)) + +(def-refactor-test test-cycle-if-outer-if + "(if-not this + (if that + (then AAA) + (else BBB)) + (otherwise CCC))" + "(if this + (otherwise CCC) + (if that + (then AAA) + (else BBB)))" + (beginning-of-buffer) + (search-forward "BBB))") + (clojure-cycle-if)) + +(provide 'clojure-mode-cycling-test) + +;;; clojure-mode-cycling-test.el ends here diff --git a/test/clojure-mode-refactor-threading-test.el b/test/clojure-mode-refactor-threading-test.el index f86381a7..03e896dc 100644 --- a/test/clojure-mode-refactor-threading-test.el +++ b/test/clojure-mode-refactor-threading-test.el @@ -28,30 +28,15 @@ (require 'clojure-mode) (require 'ert) -(defmacro def-threading-test (name before after &rest body) - (declare (indent 3)) - (let ((sym (intern (format "test-thread-%s" name)))) - `(progn - (put ',sym 'definition-name ',name) - (ert-deftest ,sym () - (let ((clojure-thread-all-but-last nil)) - (with-temp-buffer - (insert ,before) - (clojure-mode) - ,@body - (should (equal ,(concat "\n" after) - (concat "\n" (buffer-substring-no-properties - (point-min) (point-max))))))))))) - ;; thread first -(def-threading-test first-one-step +(def-refactor-test test-thread-first-one-step "(-> (dissoc (assoc {} :key \"value\") :lock))" "(-> (assoc {} :key \"value\") (dissoc :lock))" (clojure-thread)) -(def-threading-test first-two-steps +(def-refactor-test test-thread-first-two-steps "(-> (dissoc (assoc {} :key \"value\") :lock))" "(-> {} (assoc :key \"value\") @@ -59,7 +44,7 @@ (clojure-thread) (clojure-thread)) -(def-threading-test first-dont-thread-maps +(def-refactor-test test-thread-first-dont-thread-maps "(-> (dissoc (assoc {} :key \"value\") :lock))" "(-> {} (assoc :key \"value\") @@ -68,7 +53,7 @@ (clojure-thread) (clojure-thread)) -(def-threading-test first-dont-thread-last-one +(def-refactor-test test-thread-first-dont-thread-last-one "(-> (dissoc (assoc (get-a-map) :key \"value\") :lock))" "(-> (get-a-map) (assoc :key \"value\") @@ -77,7 +62,7 @@ (clojure-thread) (clojure-thread)) -(def-threading-test first-easy-on-whitespace +(def-refactor-test test-thread-first-easy-on-whitespace "(-> (dissoc (assoc {} :key \"value\") :lock))" "(-> @@ -85,7 +70,7 @@ (dissoc :lock))" (clojure-thread)) -(def-threading-test first-remove-superfluous-parens +(def-refactor-test test-thread-first-remove-superfluous-parens "(-> (square (sum [1 2 3 4 5])))" "(-> [1 2 3 4 5] sum @@ -93,7 +78,7 @@ (clojure-thread) (clojure-thread)) -(def-threading-test first-cursor-before-threading +(def-refactor-test test-thread-first-cursor-before-threading "(-> (not (s-acc/mobile? session)))" "(-> (s-acc/mobile? session) not)" @@ -101,7 +86,7 @@ (clojure-thread)) ;; unwind thread first -(def-threading-test first-one-step +(def-refactor-test test-thread-unwind-first-one-step "(-> {} (assoc :key \"value\") (dissoc :lock))" @@ -109,7 +94,7 @@ (dissoc :lock))" (clojure-unwind)) -(def-threading-test first-two-steps +(def-refactor-test test-thread-unwind-first-two-steps "(-> {} (assoc :key \"value\") (dissoc :lock))" @@ -117,7 +102,7 @@ (clojure-unwind) (clojure-unwind)) -(def-threading-test first-jump-out-of-threading +(def-refactor-test test-thread-first-jump-out-of-threading "(-> {} (assoc :key \"value\") (dissoc :lock))" @@ -127,13 +112,13 @@ (clojure-unwind)) ;; thread last -(def-threading-test last-one-step +(def-refactor-test test-thread-last-one-step "(->> (map square (filter even? [1 2 3 4 5])))" "(->> (filter even? [1 2 3 4 5]) (map square))" (clojure-thread)) -(def-threading-test last-two-steps +(def-refactor-test test-thread-last-two-steps "(->> (map square (filter even? [1 2 3 4 5])))" "(->> [1 2 3 4 5] (filter even?) @@ -141,7 +126,7 @@ (clojure-thread) (clojure-thread)) -(def-threading-test last-dont-thread-vectors +(def-refactor-test test-thread-last-dont-thread-vectors "(->> (map square (filter even? [1 2 3 4 5])))" "(->> [1 2 3 4 5] (filter even?) @@ -150,7 +135,7 @@ (clojure-thread) (clojure-thread)) -(def-threading-test last-dont-thread-last-one +(def-refactor-test test-thread-last-dont-thread-last-one "(->> (map square (filter even? (get-a-list))))" "(->> (get-a-list) (filter even?) @@ -160,7 +145,7 @@ (clojure-thread)) ;; unwind thread last -(def-threading-test last-one-step +(def-refactor-test test-thread-last-one-step "(->> [1 2 3 4 5] (filter even?) (map square))" @@ -168,7 +153,7 @@ (map square))" (clojure-unwind)) -(def-threading-test last-two-steps +(def-refactor-test test-thread-last-two-steps "(->> [1 2 3 4 5] (filter even?) (map square))" @@ -176,7 +161,7 @@ (clojure-unwind) (clojure-unwind)) -(def-threading-test last-jump-out-of-threading +(def-refactor-test test-thread-last-jump-out-of-threading "(->> [1 2 3 4 5] (filter even?) (map square))" @@ -185,7 +170,7 @@ (clojure-unwind) (clojure-unwind)) -(def-threading-test function-name +(def-refactor-test test-thread-function-name "(->> [1 2 3 4 5] sum square)" @@ -193,7 +178,7 @@ square)" (clojure-unwind)) -(def-threading-test function-name-twice +(def-refactor-test test-thread-function-name-twice "(-> [1 2 3 4 5] sum square)" @@ -201,21 +186,21 @@ (clojure-unwind) (clojure-unwind)) -(def-threading-test issue-6-1 +(def-refactor-test test-thread-issue-6-1 "(defn plus [a b] (-> a (+ b)))" "(defn plus [a b] (-> (+ a b)))" (clojure-unwind)) -(def-threading-test issue-6-2 +(def-refactor-test test-thread-issue-6-2 "(defn plus [a b] (->> a (+ b)))" "(defn plus [a b] (->> (+ b a)))" (clojure-unwind)) -(def-threading-test first-some +(def-refactor-test test-thread-first-some "(some-> (+ (val (find {:a 1} :b)) 5))" "(some-> {:a 1} (find :b) @@ -225,7 +210,7 @@ (clojure-thread) (clojure-thread)) -(def-threading-test last-some +(def-refactor-test test-thread-last-some "(some->> (+ 5 (val (find {:a 1} :b))))" "(some->> :b (find {:a 1}) @@ -235,7 +220,7 @@ (clojure-thread) (clojure-thread)) -(def-threading-test last-first-some +(def-refactor-test test-thread-last-first-some "(some-> {:a 1} (find :b) val @@ -245,7 +230,7 @@ (clojure-unwind) (clojure-unwind)) -(def-threading-test thread-last-some +(def-refactor-test test-thread-thread-last-some "(some->> :b (find {:a 1}) val @@ -255,7 +240,7 @@ (clojure-unwind) (clojure-unwind)) -(def-threading-test first-all +(def-refactor-test test-thread-first-all "(->map (assoc {} :key \"value\") :lock)" "(-> {} (assoc :key \"value\") @@ -263,14 +248,14 @@ (beginning-of-buffer) (clojure-thread-first-all nil)) -(def-threading-test first-all-but-last +(def-refactor-test test-thread-first-all-but-last "(->map (assoc {} :key \"value\") :lock)" "(-> (assoc {} :key \"value\") (->map :lock))" (beginning-of-buffer) (clojure-thread-first-all t)) -(def-threading-test last-all +(def-refactor-test test-thread-last-all "(map square (filter even? (make-things)))" "(->> (make-things) (filter even?) @@ -278,14 +263,14 @@ (beginning-of-buffer) (clojure-thread-last-all nil)) -(def-threading-test last-all-but-last +(def-refactor-test test-thread-last-all-but-last "(map square (filter even? (make-things)))" "(->> (filter even? (make-things)) (map square))" (beginning-of-buffer) (clojure-thread-last-all t)) -(def-threading-test all-thread-first +(def-refactor-test test-thread-all-thread-first "(-> {} (assoc :key \"value\") (dissoc :lock))" @@ -293,7 +278,7 @@ (beginning-of-buffer) (clojure-unwind-all)) -(def-threading-test all-thread-last +(def-refactor-test test-thread-all-thread-last "(->> (make-things) (filter even?) (map square))" @@ -301,7 +286,7 @@ (beginning-of-buffer) (clojure-unwind-all)) -(def-threading-test last-dangling-parens +(def-refactor-test test-thread-last-dangling-parens "(map inc (range))" "(->> (range) @@ -309,7 +294,7 @@ (beginning-of-buffer) (clojure-thread-last-all nil)) -(def-threading-test last-dangling-parens-2 +(def-refactor-test test-thread-last-dangling-parens-2 "(deftask dev [] (comp (serve) (cljs)))" @@ -320,7 +305,7 @@ (clojure-thread-last-all nil)) ;; fix for clojure-emacs/clj-refactor.el#259 -(def-threading-test last-leaves-multiline-sexp-alone +(def-refactor-test test-thread-last-leaves-multiline-sexp-alone "(->> [a b] (some (fn [x] (when x @@ -331,7 +316,7 @@ [a b])" (clojure-unwind-all)) -(def-threading-test last-maybe-unjoin-lines +(def-refactor-test test-thread-last-maybe-unjoin-lines "(deftask dev [] (comp (serve) (cljs (lala) @@ -344,7 +329,7 @@ (clojure-thread-last-all nil) (clojure-unwind-all)) -(def-threading-test empty-first-line +(def-refactor-test test-thread-empty-first-line "(map inc [1 2])" @@ -354,7 +339,7 @@ (goto-char (point-min)) (clojure-thread-first-all nil)) -(def-threading-test first-maybe-unjoin-lines +(def-refactor-test test-thread-first-maybe-unjoin-lines "(map inc [1 2])" diff --git a/test/test-helper.el b/test/test-helper.el index 48463602..02a7402c 100644 --- a/test/test-helper.el +++ b/test/test-helper.el @@ -32,4 +32,20 @@ ;; Load the file under test (load (expand-file-name "clojure-mode" source-directory))) +(defmacro def-refactor-test (name before after &rest body) + (declare (indent 3)) + `(progn + (put ',name 'definition-name ',name) + (ert-deftest ,name () + (let ((clojure-thread-all-but-last nil) + (clojure-use-metadata-for-privacy nil)) + (with-temp-buffer + (insert ,before) + (clojure-mode) + ,@body + (should (equal ,(concat "\n" after) + (concat "\n" (buffer-substring-no-properties + (point-min) (point-max)))))))))) + + ;;; test-helper.el ends here