From 51427449bf9b5fa116b54fcfd3152645cf4cef6b Mon Sep 17 00:00:00 2001 From: Reid 'arrdem' McKenzie Date: Thu, 10 Nov 2016 10:43:35 -0800 Subject: [PATCH] [#78] Implement with-monkeypatches, use to "fix" core.logic --- src/kibit/driver.clj | 45 ++++++++++++++++++++++++-------------- src/kibit/monkeypatch.clj | 40 +++++++++++++++++++++++++++++++++ test/kibit/test/driver.clj | 4 ++++ test/resources/sets.clj | 4 ++++ 4 files changed, 77 insertions(+), 16 deletions(-) create mode 100644 src/kibit/monkeypatch.clj create mode 100644 test/resources/sets.clj diff --git a/src/kibit/driver.clj b/src/kibit/driver.clj index caab14e..cd4d194 100644 --- a/src/kibit/driver.clj +++ b/src/kibit/driver.clj @@ -1,10 +1,14 @@ (ns kibit.driver + "The (leiningen) facing interface for Kibit. Provides helpers for finding files in a project, and + linting a list of files." (:require [clojure.java.io :as io] - [kibit.rules :refer [all-rules]] - [kibit.check :refer [check-file]] - [kibit.reporters :refer :all] - [clojure.tools.cli :refer [cli]]) - (:import [java.io File])) + [clojure.tools.cli :refer [cli]] + [kibit + [check :refer [check-file]] + [reporters :refer :all] + [rules :refer [all-rules]] + [monkeypatch :refer :all]]) + (:import java.io.File)) (def cli-specs [["-r" "--reporter" "The reporter used when rendering suggestions" @@ -31,18 +35,27 @@ (sort-by #(.getAbsolutePath ^File %) (filter clojure-file? (file-seq dir)))) -(defn run [source-paths rules & args] +(defn run + "Runs the kibit checker against the given paths, rules and args. + + Paths is expected to be a sequence of io.File objects. + + Rules is either a collection of rules or nil. If Rules is nil, all of kibit's checkers are used. + + Optionally accepts a :reporter keyword argument, defaulting to \"text\"." + [source-paths rules & args] (let [[options file-args usage-text] (apply (partial cli args) cli-specs) - source-files (mapcat #(-> % io/file find-clojure-sources-in-dir) - (if (empty? file-args) source-paths file-args))] - (mapcat (fn [file] (try (check-file file - :reporter (name-to-reporter (:reporter options) - cli-reporter) - :rules (or rules all-rules)) - (catch Exception e - (binding [*out* *err*] - (println "Check failed -- skipping rest of file") - (println (.getMessage e)))))) + source-files (mapcat #(-> % io/file find-clojure-sources-in-dir) + (if (empty? file-args) source-paths file-args))] + (mapcat (fn [file] + (with-monkeypatches kibit-redefs + (check-file file + :reporter (name-to-reporter (:reporter options) cli-reporter) + :rules (or rules all-rules)) + (catch Exception e + (binding [*out* *err*] + (println "Check failed -- skipping rest of file") + (println (.getMessage e)))))) source-files))) (defn external-run diff --git a/src/kibit/monkeypatch.clj b/src/kibit/monkeypatch.clj new file mode 100644 index 0000000..fe2d971 --- /dev/null +++ b/src/kibit/monkeypatch.clj @@ -0,0 +1,40 @@ +(ns kibit.monkeypatch + "Various helpers providing a with-monkeypatches form which wraps" + (:require [clojure.core.logic :as c.c.l]) + (:import [clojure.lang + Var + IPersistentSet] + [clojure.core.logic.protocols + ITreeTerm])) + +(defn ^:pivate tree-term? [x] + (and (or (coll? x) + (instance? ITreeTerm x)) + (not (instance? IPersistentSet x)))) + +(def kibit-redefs + {#'c.c.l/tree-term? tree-term?}) + +(defmacro with-monkeypatches + "Builds a try/finally which captures Var bindings (and ^:macro tags) comming in, creates new Var + bindings within the try and in the finally restores the original bindings. This allows users to + establish stack-local patched contexts." + {:style/indent [1]} + [redefs & forms] + (let [redefs (eval redefs) + original-bindings (into {} + (for [k (keys redefs)] + [k (gensym)]))] + `(let [~@(for [[k v] original-bindings + f [v `(deref ~k)]] + f)] + (try ~@(for [[k v] redefs] + `(do (.bindRoot ~k ~v) + ~(if (.isMacro ^Var k) + `(.setMacro ~k)))) + ~@forms + (finally + ~@(for [[k v] redefs] + `(do (.bindRoot ~k ~(get original-bindings k)) + ~(if (.isMacro ^Var k) + `(.setMacro ~k))))))))) diff --git a/test/kibit/test/driver.clj b/test/kibit/test/driver.clj index 2cd3534..ed93f4d 100644 --- a/test/kibit/test/driver.clj +++ b/test/kibit/test/driver.clj @@ -13,5 +13,9 @@ (deftest find-clojure-sources-are (is (= [(io/file "test/resources/first.clj") (io/file "test/resources/second.cljx") + (io/file "test/resources/sets.clj") (io/file "test/resources/third.cljs")] (driver/find-clojure-sources-in-dir (io/file "test/resources"))))) + +(deftest test-set-file + (is (driver/run ["test/resources/sets.clj"] nil))) diff --git a/test/resources/sets.clj b/test/resources/sets.clj new file mode 100644 index 0000000..694f0a3 --- /dev/null +++ b/test/resources/sets.clj @@ -0,0 +1,4 @@ +(ns resources.sets) + +(defn killit [coll] + (not-any? #{"string1" "string2"} (map ffirst coll)))