Skip to content

Commit

Permalink
The reading of files and reporting refactored into higher-order pieces
Browse files Browse the repository at this point in the history
  • Loading branch information
ohpauleez committed Mar 20, 2012
1 parent 8e527c2 commit 8a417be
Showing 1 changed file with 73 additions and 11 deletions.
84 changes: 73 additions & 11 deletions src/jonase/kibit/core.clj
Expand Up @@ -4,12 +4,29 @@
(:refer-clojure :exclude [==])
(:require [clojure.java.io :as io]
[clojure.walk :as walk]
[jonase.kibit.rules :as core-rules])
[jonase.kibit.rules :as core-rules]
[jonase.kibit.reporters :as reporters])
(:use [clojure.core.logic :only [prep run* defne project fresh membero ==]])
(:import [clojure.lang LineNumberingPushbackReader]))

;; ### Important notes
;; Feel free to contribute rules to [kibit's github repo](https://github.com/jonase/kibit)

;; The rule sets
;; -------------
;;
;; Rule sets are stored in individual files that have a top level
;; `(defrules rules ...)`. The collection of rules are in the `rules`
;; directory.
;;
;; For more information, see: [rules](#jonase.kibit.rules) namespace
(def all-rules (map prep core-rules/all-rules))

;; Building an alternative form
;; ----------------------------
;;
;; ### Applying unification

(defne check-guards [expr guards]
([_ ()])
([_ [guard . rest]]
Expand All @@ -30,6 +47,13 @@
:alt alt
:line (-> expr meta :line)}))))))

;; This walks across all the forms within an expression,
;; checking each inner form. The outcome is a potential full alternative.
;; We check to see if there is indeed a difference in the alternative,
;; and if so, return a full simplify-map.
;;
;; We build the simplify-map at the end because
;; Clojure 1.3 munges the metadata in transients (so also in clojure.walk).
(defn simplify
([expr]
(simplify expr all-rules))
Expand All @@ -45,18 +69,18 @@
;; Reading source files
;; --------------------

;; `read-ns` is intended to be used with a Clojure source file,
;; `read-file` is intended to be used with a Clojure source file,
;; read in by a LineNumberingPushbackReader. Expressions are
;; extracted using the clojure reader (ala `read`).
;; Line numbers are added as `:line` metadata to the forms.
(defn read-ns
(defn read-file
"Generate a lazy sequence of top level forms from a
LineNumberingPushbackReader"
[^LineNumberingPushbackReader r]
(lazy-seq
(let [form (read r false ::eof)]
(when-not (= form ::eof)
(cons form (read-ns r))))))
(cons form (read-file r))))))

;; `tree-seq` returns a lazy-seq of nodes for a tree.
;; Given an expression, we can then match rules against its pieces.
Expand All @@ -81,12 +105,50 @@
seq
expr))

;; The reader is converted into a LineNumberingPushbackReader.
;; Optional rule sets and verbosity can be set with keyword args,
;; :rules, :verbose -
;;
;; `(check-via-reader my-reader :rules rule-set :verbose true)`
;;
;; Verbosity will report all the sub-expression substituions individually,
;; in addition to reporting them all on the top-level form. This is an
;; an ideal way to carefully inspect your code.
(defn check-via-reader
"Simplifies every expression (including sub-expressions) read in from
a reader and returns a lazy sequence of the result of unification
(`simplify` function)."
([reader]
(check-via-reader reader :rules all-rules))
([reader & kw-opts]
(let [{:keys [rules verbose]
:or {rules all-rules,
verbose false}} (apply hash-map kw-opts)]
(if verbose
(keep #(simplify-one % rules)
(mapcat expr-seq (read-file (LineNumberingPushbackReader. reader))))
(keep #(simplify % rules) (read-file (LineNumberingPushbackReader. reader)))))))

;; The results from simplify get passed to a `reporter`.
;; A reporter can be any function that expects a single map.
;; TODO - talk about optional args
;;
;; The entire sequence of simplify-maps from a given `source-file`
;; are processed with `doseq`, since reporting is side-effect action.
;;
;; For more information on reporters, see: [reporters](#jonase.kibit.reporters) namespace
(defn check-file
"Checks every expression (including sub-expressions) in a clojure
source file against the rules and returns a lazy sequence of the
result of unification"
([reader]
(check-file reader all-rules))
([reader rules]
(keep #(simplify % rules)
(mapcat expr-seq (read-ns (LineNumberingPushbackReader. reader))))))
source file against the rules and processes them with a reporter"
([source-file]
(check-file source-file :rules all-rules))
([source-file & kw-opts]
(let [{:keys [rules verbose reporter]
:or {rules all-rules
verbose false
reporter reporters/cli-reporter}} (apply hash-map kw-opts)]
(with-open [reader (io/reader source-file)]
(doseq [simplify-map (check-via-reader
reader :rules rules :verbose verbose)]
(reporter simplify-map))))))

0 comments on commit 8a417be

Please sign in to comment.