Merge branch 'marg-drop'
This commit is contained in:
commit
ea633a4cd4
7 changed files with 75 additions and 26 deletions
|
@ -48,6 +48,7 @@ Bugs can be reported using the github bug tracker.
|
|||
* Rules for function definitions (make this more of a lint tool)
|
||||
* Rules for collection lookup; "2 is a bad smell" [see this blog post](http://tech.puredanger.com/2011/10/12/2-is-a-smell/)
|
||||
* Extract the "when to use" rules from [Joy of Clojure](http://joyofclojure.com/)
|
||||
* gh-pages of the Marginalia docs as done [here](http://www.maybetechnology.com/2011/08/literate-programming-with-marginalia.html)
|
||||
* Leiningen project.clj setting for rule exclusion
|
||||
* Leiningen project.clj setting for a directory of rules to include
|
||||
* More rules
|
||||
|
|
|
@ -3,5 +3,6 @@
|
|||
:dependencies [[org.clojure/clojure "1.3.0"]
|
||||
[org.clojure/core.logic "0.6.7"]
|
||||
[org.clojure/tools.namespace "0.1.2"]]
|
||||
:dev-dependencies [[lein-marginalia "0.7.0"]]
|
||||
:eval-in-leiningen true
|
||||
:warn-on-reflection false)
|
||||
:warn-on-reflection false)
|
||||
|
|
|
@ -1,24 +1,36 @@
|
|||
(ns jonase.kibit.core
|
||||
"Kibit's core functionality uses core.logic to suggest idiomatic
|
||||
replacements for patterns of code and remove general code lint"
|
||||
(:require [clojure.core.logic :as logic]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as string]
|
||||
[jonase.kibit.arithmetic :as arith]
|
||||
[jonase.kibit.control-structures :as control]
|
||||
[jonase.kibit.misc :as misc])
|
||||
[jonase.kibit.rules :as core-rules])
|
||||
(:import [clojure.lang LineNumberingPushbackReader]))
|
||||
|
||||
(def all-rules (merge control/rules
|
||||
arith/rules
|
||||
misc/rules))
|
||||
;; The rule sets
|
||||
;; -------------
|
||||
;;
|
||||
;; Rule sets are stored in individual files that have a top level
|
||||
;; `(def rules '{...})`. The collection of rules are in the `rules`
|
||||
;; directory.
|
||||
;;
|
||||
;; For more information, see: [rule](#jonase.kibit.rules) namespace
|
||||
(def all-rules core-rules/all-rules)
|
||||
|
||||
(defn read-ns [r]
|
||||
(lazy-seq
|
||||
(let [form (read r false ::eof)
|
||||
line-num (.getLineNumber r)]
|
||||
(when-not (= form ::eof)
|
||||
(cons (with-meta form {:line line-num}) (read-ns r))))))
|
||||
|
||||
(defn unify [expr rule]
|
||||
;; Parsing the lines/forms
|
||||
;; -----------------------
|
||||
;;
|
||||
;; The unifier compares a form/line against a single rule.
|
||||
|
||||
;; The unification generates a map.
|
||||
;;
|
||||
;; The `:rule` is a vector of the matching rule/alt pair that was used
|
||||
;; to produce the `:alt`, the ideal alternative.
|
||||
;; The line number (`:line`) is extracted from the metadata of the line,
|
||||
;; courtesy of LineNumberingPushbackReader (See `read-ns` and `check-file`)
|
||||
(defn unify
|
||||
"TODO jonas"
|
||||
[expr rule]
|
||||
(let [[r s] (#'logic/prep rule)
|
||||
alt (first (logic/run* [alt]
|
||||
(logic/== expr r)
|
||||
|
@ -29,21 +41,43 @@
|
|||
:alt (seq alt)
|
||||
:line (-> expr meta :line)})))
|
||||
|
||||
;; Loop over the rule set, recursively applying unification to find the best
|
||||
;; possible alternative
|
||||
(defn check-form
|
||||
"Given an expression/line/form, return a map containing the alternative suggestion info, or `nil`"
|
||||
([expr]
|
||||
(check-form expr all-rules))
|
||||
([expr rules]
|
||||
(when (sequential? expr)
|
||||
(some #(unify expr %) rules))))
|
||||
|
||||
(defn expr-seq [expr]
|
||||
;; Building the parsable forms
|
||||
;; ---------------------------
|
||||
;;
|
||||
;; We treat each line as a single form, since logic will match any form sequence on the line
|
||||
;; The line numbers are added to the lines/forms' to metadata, `^{:line}`
|
||||
|
||||
(defn read-ns
|
||||
"Generate a lazy sequence of lines from a [`LineNumberingPushbackReader`]( https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LineNumberingPushbackReader.java )."
|
||||
[r]
|
||||
(lazy-seq
|
||||
(let [form (read r false ::eof)
|
||||
line-num (.getLineNumber r)]
|
||||
(when-not (= form ::eof)
|
||||
(cons (with-meta form {:line line-num}) (read-ns r))))))
|
||||
|
||||
(defn expr-seq
|
||||
"TODO jonas, just a quick one"
|
||||
[expr]
|
||||
(tree-seq sequential?
|
||||
seq
|
||||
expr))
|
||||
|
||||
(defn check-file
|
||||
"TODO jonas, just a quick one"
|
||||
([reader]
|
||||
(check-file reader all-rules))
|
||||
([reader rules]
|
||||
(keep check-form
|
||||
(mapcat expr-seq (read-ns (LineNumberingPushbackReader. reader))))))
|
||||
|
||||
|
|
16
src/jonase/kibit/rules.clj
Normal file
16
src/jonase/kibit/rules.clj
Normal file
|
@ -0,0 +1,16 @@
|
|||
(ns jonase.kibit.rules
|
||||
"`rules.clj` provides the core functionality for extracting
|
||||
and merging rules from namespaces. There are shorthand `def`s
|
||||
for rule the core rule sets"
|
||||
(:require [jonase.kibit.rules.arithmetic :as arith]
|
||||
[jonase.kibit.rules.control-structures :as control]
|
||||
[jonase.kibit.rules.misc :as misc]))
|
||||
|
||||
(def rule-map {:control-structures control/rules
|
||||
:arithmetic arith/rules
|
||||
:misc misc/rules})
|
||||
|
||||
;; TODO: Consider a refactor for this into a function
|
||||
;; `(defn rules-for-ns [& namespaces])`
|
||||
(def all-rules (apply merge (vals rule-map)))
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
(ns jonase.kibit.arithmetic)
|
||||
(ns jonase.kibit.rules.arithmetic)
|
||||
|
||||
(def rules
|
||||
'{(+ ?x 1) (inc ?x)
|
||||
|
@ -14,10 +14,8 @@
|
|||
(> ?x 0) (pos? ?x)
|
||||
(<= 1 ?x) (pos? ?x)
|
||||
|
||||
(< ?x 0) (neg? ?x)})
|
||||
|
||||
(comment
|
||||
(< (+ 1 x) 0))
|
||||
|
||||
(< ?x 0) (neg? ?x)
|
||||
|
||||
|
||||
(= ?x ?x) true
|
||||
(== ?x ?x) true})
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
(ns jonase.kibit.control-structures)
|
||||
(ns jonase.kibit.rules.control-structures)
|
||||
|
||||
(def rules
|
||||
'{(if ?x ?y nil) (when ?x ?y)
|
|
@ -1,4 +1,4 @@
|
|||
(ns jonase.kibit.misc)
|
||||
(ns jonase.kibit.rules.misc)
|
||||
|
||||
(def rules
|
||||
'{(apply str (interpose ?x ?y)) (clojure.string/join ?x ?y)
|
||||
|
@ -23,4 +23,3 @@
|
|||
|
||||
(map (fn [x] (inc x)) [1 2 3])
|
||||
(map #(dec %) [1 2 3]))
|
||||
|
Loading…
Reference in a new issue