Permalink
Browse files

Moved all namespaces into koan-engine heirarchy.

  • Loading branch information...
1 parent 8afcd5f commit 903bcd221aad47a2963b5a9844fe8c056a83a346 @sritchie sritchie committed Nov 27, 2011
View
@@ -1,5 +1,6 @@
-(defproject cascalog-koans "0.4.5"
- :description "Koans for Cascalog."
+(defproject cascalog-koan-engine "0.1.0"
+ :description "Koan Engine for Clojure projects."
+ :main koan-engine.core
:dependencies [[org.clojure/clojure "1.3.0"]
[cascalog "1.8.4"]
[fresh "1.0.2"]
View
@@ -1,4 +1,5 @@
-(load "path_to_enlightenment")
+(load "koan_engine/core")
(do
- (in-ns 'path-to-enlightenment)
- (run))
+ (in-ns 'koan-engine.core)
+ (println "RUNNINBG")
+ (-main))
View
@@ -1,4 +1,4 @@
-(load "path_to_answer_sheet")
+(load "koan_engine/checker")
(do
- (in-ns 'path-to-answer-sheet)
- (run))
+ (in-ns 'koan-engine.checker)
+ (run))
@@ -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))
View
@@ -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))
@@ -1,12 +1,12 @@
-(ns runner.freshness
+(ns koan-engine.freshness
(:use [fresh.core :only [clj-files-in freshener]]
[clojure.java.io :only [file]]
- [runner.koans :only [among-paths?
- namaste
- next-koan-path
- ordered-koans
- ordered-koan-paths
- tests-pass?]])
+ [koan-engine.koans :only [among-paths?
+ namaste
+ next-koan-path
+ ordered-koans
+ ordered-koan-paths
+ tests-pass?]])
(:import [java.util.concurrent ScheduledThreadPoolExecutor TimeUnit]))
(defn files-to-keep-fresh []
@@ -15,8 +15,8 @@
(defn report-refresh [report]
(when-let [refreshed-files (seq (:reloaded report))]
(let [these-koans (filter
- (among-paths? refreshed-files)
- (ordered-koan-paths))]
+ (among-paths? refreshed-files)
+ (ordered-koan-paths))]
(when (every? tests-pass? these-koans)
(if-let [next-koan-file (file (next-koan-path (last these-koans)))]
(report-refresh {:reloaded [next-koan-file]})
@@ -1,14 +1,24 @@
-(ns runner.koans
- (:use [clojure.java.io :only [file]]))
+(ns koan-engine.koans
+ (:use [clojure.java.io :only [file resource]])
+ (:require [koan-engine.util :as u]))
;; 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
- ["tuples"
- ])
+ ["tuples"])
(defn ordered-koan-paths []
(map (fn [koan-name]
- (.getCanonicalPath (file "src" "koans" (str koan-name ".clj"))))
+ (.getCanonicalPath (file "src" "koans" (str koan-name ".clj"))))
ordered-koans))
(defn among-paths? [files]
@@ -24,8 +34,8 @@
(defn tests-pass? [file-path]
(binding [*ns* (create-ns (gensym "koans"))]
(refer 'clojure.core)
- (use 'cascalog.api)
- (use '[path-to-enlightenment :only [meditations ?= __ ___]])
+ (use 'cascalog.api) ;; TODO: Move out other namespace.
+ (use '[koan-engine.core :only [meditations ?= __ ___]])
(try (load-file file-path)
true
(catch Exception e
@@ -41,4 +51,3 @@
(defn namaste []
(println "\nYou have achieved clojure enlightenment. Namaste."))
-
View
@@ -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 #"[\.\-]")))))
View
@@ -5,19 +5,25 @@
(= __ [["truth."]])
"Queries produce results..."
- (?= __ (<- [?x] (one-tuple ?x)))
+ (?= __ (<- [?x]
+ (one-tuple ?x)))
"All sorts of sequences do the job."
- (?= __ (<- [?x] ([[1]] ?x)))
+ (?= __ (<- [?x]
+ ([[1]] ?x)))
"Lists, anyone?"
- (?= __ (<- [?x] ((list [1]) ?x)))
+ (?= __ (<- [?x]
+ ((list [1]) ?x)))
"From whence do these tuples come?"
- (?= [[4]] (<- [?x] (__ ?x)))
+ (?= [[4]] (<- [?x]
+ (__ ?x)))
"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."
- (?= one-tuple (<- [__] (one-tuple __))))
+ (?= one-tuple (<- [__]
+ (one-tuple __))))
Oops, something went wrong.

0 comments on commit 903bcd2

Please sign in to comment.