Skip to content

Commit

Permalink
Moved all namespaces into koan-engine heirarchy.
Browse files Browse the repository at this point in the history
  • Loading branch information
sritchie committed Nov 27, 2011
1 parent 8afcd5f commit 903bcd2
Show file tree
Hide file tree
Showing 11 changed files with 219 additions and 173 deletions.
5 changes: 3 additions & 2 deletions project.clj
@@ -1,5 +1,6 @@
(defproject cascalog-koans "0.4.5" (defproject cascalog-koan-engine "0.1.0"
:description "Koans for Cascalog." :description "Koan Engine for Clojure projects."
:main koan-engine.core
:dependencies [[org.clojure/clojure "1.3.0"] :dependencies [[org.clojure/clojure "1.3.0"]
[cascalog "1.8.4"] [cascalog "1.8.4"]
[fresh "1.0.2"] [fresh "1.0.2"]
Expand Down
7 changes: 4 additions & 3 deletions script/run.clj
@@ -1,4 +1,5 @@
(load "path_to_enlightenment") (load "koan_engine/core")
(do (do
(in-ns 'path-to-enlightenment) (in-ns 'koan-engine.core)
(run)) (println "RUNNINBG")
(-main))
6 changes: 3 additions & 3 deletions script/test.clj
@@ -1,4 +1,4 @@
(load "path_to_answer_sheet") (load "koan_engine/checker")
(do (do
(in-ns 'path-to-answer-sheet) (in-ns 'koan-engine.checker)
(run)) (run))
94 changes: 94 additions & 0 deletions src/koan_engine/checker.clj
@@ -0,0 +1,94 @@
(ns koan-engine.checker
(:use cascalog.api
[koan-engine.koans :only [ordered-koans]]
[koan-engine.core :only [meditations ?= __ ___]]
[koan-engine.util :only [fancy-assert]]
[clojure.string :only [join split trim] :as string]))

;; TODO: Use cascalog.api elsewhere.
;; TODO: add ?= back in somewhere!
;; TODO: Move out into resources directory!

(def answers
{"tuples" {"__" [[["truth."]]
[[1]]
[[1]]
[[1]]
[[4]]
'?x
'?name '?name
]}})

(defn replace-with [s k replacements]
(let [unreplaced-texts (split s (re-pattern (str "\\b" k "\\b")))]
(join (butlast
(interleave unreplaced-texts
(concat (map pr-str replacements)
(repeat k)))))))

;; TODO: Get path from root in resources directory.
(defn koan-text [koan]
(slurp (str "src/koans/" koan ".clj")))

(defn answers-for [koan sym]
((answers koan {}) sym []))

(defn fill-in-answers [text koan sym]
(replace-with text sym (answers-for koan sym)))

(defn print-non-failing-error [koan]
(println (str "\n" koan ".clj is passing without filling in the blanks")))

(defmacro ensure-failure [& forms]
(let [pairs (partition 2 forms)
tests (map (fn [[doc# code#]]
`(if (try
(fancy-assert ~code# ~doc#)
false
(catch AssertionError e# true)
(catch Exception e# true))
:pass
(throw (AssertionError. (pr-str ~doc# ~code#)))))
pairs)]
`(do ~@tests)))

;; This needs to occur in the project-koan-specific namespace, else
;; load-string won't have the proper requirements.
;;
;; In the actual koan we prefix form with some use and requires.
(defn ensure-failing-without-answers []
(if (every?
(fn [koan]
(let [form (koan-text koan)
form (string/replace form "(meditations" "(ensure-failure")
fake-err (java.io.PrintStream. (java.io.ByteArrayOutputStream.))
real-err System/err
result (try
(load-string form)
true
(catch AssertionError e (prn e) false)
(catch Exception e (prn e) false))]
(if result
:pass
(print-non-failing-error koan))))
ordered-koans)
(println "\nTests all fail before the answers are filled in.")))

(defn ensure-passing-with-answers []
(try
(dorun (map
(fn [koan]
(load-string
(-> (koan-text koan)
(fill-in-answers koan "__")
(fill-in-answers koan "___"))))
ordered-koans))
(println "\nAll tests pass after the answers are filled in.")
(catch Exception e
(println "\nAnswer sheet fail: " e)
(.printStackTrace e)
(println "Answer sheet fail"))))

(defn run []
(ensure-failing-without-answers)
(ensure-passing-with-answers))
27 changes: 27 additions & 0 deletions src/koan_engine/core.clj
@@ -0,0 +1,27 @@
(ns koan-engine.core
(:use [cascalog.testing :only (test?-)]
[cascalog.util :only (defalias)]
[koan-engine.freshness :only [setup-freshener]])
(:require [koan-engine.util :as u]))

(def __ :fill-in-the-blank)
(def ___ (fn [& args] __))

;; TODO: Place these in a required ns:
;; [cascalog.testing :only (test?-)]
;; [cascalog.util :only (defalias)]

;; TODO: Move out!
;; More concise for koans.
(defalias ?= test?-)

(defmacro meditations [& forms]
(let [pairs (partition 2 forms)
tests (map (fn [[doc# code#]]
`(u/fancy-assert ~code# ~doc#))
pairs)]
`(do ~@tests)))

(defn -main []
(u/require-version (u/parse-required-version))
(setup-freshener))
18 changes: 9 additions & 9 deletions src/runner/freshness.clj → src/koan_engine/freshness.clj
@@ -1,12 +1,12 @@
(ns runner.freshness (ns koan-engine.freshness
(:use [fresh.core :only [clj-files-in freshener]] (:use [fresh.core :only [clj-files-in freshener]]
[clojure.java.io :only [file]] [clojure.java.io :only [file]]
[runner.koans :only [among-paths? [koan-engine.koans :only [among-paths?
namaste namaste
next-koan-path next-koan-path
ordered-koans ordered-koans
ordered-koan-paths ordered-koan-paths
tests-pass?]]) tests-pass?]])
(:import [java.util.concurrent ScheduledThreadPoolExecutor TimeUnit])) (:import [java.util.concurrent ScheduledThreadPoolExecutor TimeUnit]))


(defn files-to-keep-fresh [] (defn files-to-keep-fresh []
Expand All @@ -15,8 +15,8 @@
(defn report-refresh [report] (defn report-refresh [report]
(when-let [refreshed-files (seq (:reloaded report))] (when-let [refreshed-files (seq (:reloaded report))]
(let [these-koans (filter (let [these-koans (filter
(among-paths? refreshed-files) (among-paths? refreshed-files)
(ordered-koan-paths))] (ordered-koan-paths))]
(when (every? tests-pass? these-koans) (when (every? tests-pass? these-koans)
(if-let [next-koan-file (file (next-koan-path (last these-koans)))] (if-let [next-koan-file (file (next-koan-path (last these-koans)))]
(report-refresh {:reloaded [next-koan-file]}) (report-refresh {:reloaded [next-koan-file]})
Expand Down
25 changes: 17 additions & 8 deletions src/runner/koans.clj → src/koan_engine/koans.clj
@@ -1,14 +1,24 @@
(ns runner.koans (ns koan-engine.koans
(:use [clojure.java.io :only [file]])) (:use [clojure.java.io :only [file resource]])
(:require [koan-engine.util :as u]))


;; Add more koan namespaces here. ;; Add more koan namespaces here.
(defn ordered-koans []
(if-let [conf-path (resource "job-conf.clj")]
(try (let [conf (-> conf-path slurp read-string)]
(u/safe-assert (map? conf)
"job-conf.clj must produce a map of config parameters!")
conf)
(catch RuntimeException e
(throw (Exception. "Error reading job-conf.clj!\n\n") e)))
{}))

(def ordered-koans (def ordered-koans
["tuples" ["tuples"])
])


(defn ordered-koan-paths [] (defn ordered-koan-paths []
(map (fn [koan-name] (map (fn [koan-name]
(.getCanonicalPath (file "src" "koans" (str koan-name ".clj")))) (.getCanonicalPath (file "src" "koans" (str koan-name ".clj"))))
ordered-koans)) ordered-koans))


(defn among-paths? [files] (defn among-paths? [files]
Expand All @@ -24,8 +34,8 @@
(defn tests-pass? [file-path] (defn tests-pass? [file-path]
(binding [*ns* (create-ns (gensym "koans"))] (binding [*ns* (create-ns (gensym "koans"))]
(refer 'clojure.core) (refer 'clojure.core)
(use 'cascalog.api) (use 'cascalog.api) ;; TODO: Move out other namespace.
(use '[path-to-enlightenment :only [meditations ?= __ ___]]) (use '[koan-engine.core :only [meditations ?= __ ___]])
(try (load-file file-path) (try (load-file file-path)
true true
(catch Exception e (catch Exception e
Expand All @@ -41,4 +51,3 @@


(defn namaste [] (defn namaste []
(println "\nYou have achieved clojure enlightenment. Namaste.")) (println "\nYou have achieved clojure enlightenment. Namaste."))

50 changes: 50 additions & 0 deletions src/koan_engine/util.clj
@@ -0,0 +1,50 @@
(ns koan-engine.util
(:require [clojure.string :as s]))

(defn version<
"< for Clojure's version map."
[v1 v2]
(let [[major-a major-b] (map :major [v1 v2])
[minor-a minor-b] (map :minor [v1 v2])]
(or (< major-a major-b)
(and (== major-a major-b)
(< minor-a minor-b)))))

(defn require-version [[req-major req-minor]]
(when (version< {:major req-major, :minor req-minor}
*clojure-version*)
(throw (Exception.
(format "Clojure version %s.%s or higher required."
req-major req-minor)))))

(defmacro safe-assert
"Assertion with support for a message argument in all Clojure
versions. (Pre-1.3.0, `assert` didn't accept a second argument and
threw an error.)"
([x] `(safe-assert ~x ""))
([x msg]
(if (version< *clojure-version* {:major 1, :minor 3})
`(assert ~x)
`(assert ~x ~msg))))

(defmacro fancy-assert
"Assertion with fancy error messaging."
([x] (fancy-assert x ""))
([x message]
`(try (safe-assert ~x ~message)
(catch Exception e#
(throw (Exception. (str '~message "\n" '~x )
e#))))))

(defn parse-required-version []
(let [rdr (clojure.lang.LineNumberingPushbackReader.
(java.io.FileReader. (java.io.File. "project.clj")))
project-form (read rdr)
version-string (->> project-form
(drop 3)
(apply hash-map)
:dependencies
(map (fn [xs] (vec (take 2 xs))))
(into {})
('org.clojure/clojure))]
(map read-string (take 3 (s/split version-string #"[\.\-]")))))
18 changes: 12 additions & 6 deletions src/koans/tuples.clj
Expand Up @@ -5,19 +5,25 @@
(= __ [["truth."]]) (= __ [["truth."]])


"Queries produce results..." "Queries produce results..."
(?= __ (<- [?x] (one-tuple ?x))) (?= __ (<- [?x]
(one-tuple ?x)))


"All sorts of sequences do the job." "All sorts of sequences do the job."
(?= __ (<- [?x] ([[1]] ?x))) (?= __ (<- [?x]
([[1]] ?x)))


"Lists, anyone?" "Lists, anyone?"
(?= __ (<- [?x] ((list [1]) ?x))) (?= __ (<- [?x]
((list [1]) ?x)))


"From whence do these tuples come?" "From whence do these tuples come?"
(?= [[4]] (<- [?x] (__ ?x))) (?= [[4]] (<- [?x]
(__ ?x)))


"Name something well to give it power." "Name something well to give it power."
(?= one-tuple (<- [?x] (one-tuple __))) (?= one-tuple (<- [?x]
(one-tuple __)))


"The name itself doesn't matter, just that it match." "The name itself doesn't matter, just that it match."
(?= one-tuple (<- [__] (one-tuple __)))) (?= one-tuple (<- [__]
(one-tuple __))))

0 comments on commit 903bcd2

Please sign in to comment.