Extracted koan logic out into koan-engine.
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -4,3 +4,4 @@ lib
 | 
			
		||||
releases
 | 
			
		||||
*.jar
 | 
			
		||||
.DS_Store
 | 
			
		||||
.lein-deps-sum
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
(defproject functional-koans "0.4.5"
 | 
			
		||||
  :description "The functional koans"
 | 
			
		||||
  :description "The functional koans."
 | 
			
		||||
  :dependencies [[org.clojure/clojure "1.3.0"]
 | 
			
		||||
                 [fresh "1.0.2"]
 | 
			
		||||
                 [jline "0.9.94" :exclusions [junit]]]
 | 
			
		||||
  :dev-dependencies [[swank-clojure "1.3.0" :exclusions [org.clojure/clojure]]])
 | 
			
		||||
                 [koan-engine "0.1.0"]]
 | 
			
		||||
  :dev-dependencies [[swank-clojure "1.3.0" :exclusions [org.clojure/clojure]]
 | 
			
		||||
                     [lein-koan "0.1.0"]])
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										199
									
								
								resources/koans.clj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								resources/koans.clj
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,199 @@
 | 
			
		||||
[["equalities" {"__" [true
 | 
			
		||||
                      2
 | 
			
		||||
                      7
 | 
			
		||||
                      5
 | 
			
		||||
                      4/2
 | 
			
		||||
                      false
 | 
			
		||||
                      6/3
 | 
			
		||||
                      3]}]
 | 
			
		||||
 | 
			
		||||
 ["lists" {"__" [1 2 3 4 5
 | 
			
		||||
                 1
 | 
			
		||||
                 [2 3 4 5]
 | 
			
		||||
                 ()
 | 
			
		||||
                 [:a :b :c :d :e]
 | 
			
		||||
                 [0 :a :b :c :d :e]
 | 
			
		||||
                 :a
 | 
			
		||||
                 [:b :c :d :e]
 | 
			
		||||
                 "No dice!"
 | 
			
		||||
                 ()]}]
 | 
			
		||||
 | 
			
		||||
 ["vectors" {"__" [1
 | 
			
		||||
                   []
 | 
			
		||||
                   [1]
 | 
			
		||||
                   [nil]
 | 
			
		||||
                   2
 | 
			
		||||
                   [333]
 | 
			
		||||
                   :peanut
 | 
			
		||||
                   :jelly
 | 
			
		||||
                   :jelly
 | 
			
		||||
                   [:butter :and]
 | 
			
		||||
                   3]}]
 | 
			
		||||
 | 
			
		||||
 ["sets" {"__" [nil
 | 
			
		||||
                3
 | 
			
		||||
                #{1 2 3 4 5}
 | 
			
		||||
                #{1 2 3 4 5}
 | 
			
		||||
                #{2 3}
 | 
			
		||||
                #{1 4}]}]
 | 
			
		||||
 | 
			
		||||
 ["maps" {"__" [{}
 | 
			
		||||
                0
 | 
			
		||||
                1
 | 
			
		||||
                2
 | 
			
		||||
                2
 | 
			
		||||
                1
 | 
			
		||||
                1
 | 
			
		||||
                "Vancouver"
 | 
			
		||||
                nil
 | 
			
		||||
                :key-not-found
 | 
			
		||||
                true
 | 
			
		||||
                false
 | 
			
		||||
                "February"
 | 
			
		||||
                1 "January"
 | 
			
		||||
                2006 2010 2014
 | 
			
		||||
                "Vancouver"]}]
 | 
			
		||||
 
 | 
			
		||||
 ["functions" {"__" [20
 | 
			
		||||
                     10 5
 | 
			
		||||
                     30 2
 | 
			
		||||
                     15
 | 
			
		||||
                     20 *]
 | 
			
		||||
               "___" [(fn [f] (f 5))
 | 
			
		||||
                      (fn [f] (f 5))]}]
 | 
			
		||||
 | 
			
		||||
 ["conditionals" {"__" [:a
 | 
			
		||||
                        []
 | 
			
		||||
                        nil
 | 
			
		||||
                        :glory
 | 
			
		||||
                        4 6 :your-road
 | 
			
		||||
                        'doom 0
 | 
			
		||||
                        :cocked-pistol
 | 
			
		||||
                        :say-what?]}]
 | 
			
		||||
 | 
			
		||||
 ["higher_order_functions" {"__" [4 8 12
 | 
			
		||||
                                  (* x x)
 | 
			
		||||
                                  [false false true false false]
 | 
			
		||||
                                  ()
 | 
			
		||||
                                  [:anything :goes :here]
 | 
			
		||||
                                  (< x 31)
 | 
			
		||||
                                  (* 10 x) (< x 4)
 | 
			
		||||
                                  24
 | 
			
		||||
                                  100
 | 
			
		||||
                                  (count a) (count b)]}]
 | 
			
		||||
 | 
			
		||||
 ["runtime_polymorphism" {"__" [(str (:name a) " eats veggies.")
 | 
			
		||||
                                (str (:name a) " eats animals.")
 | 
			
		||||
                                (str "I don't know what " (:name a) " eats.")
 | 
			
		||||
                                "Hello World!"
 | 
			
		||||
                                "Hello, you silly world."
 | 
			
		||||
                                "Hello to this group: Peter, Paul, Mary!" ]}]
 | 
			
		||||
 | 
			
		||||
 ["lazy_sequences" {"__" [[1 2 3 4]
 | 
			
		||||
                          [0 1 2 3 4]
 | 
			
		||||
                          10
 | 
			
		||||
                          95
 | 
			
		||||
                          (range 20)
 | 
			
		||||
                          :a]
 | 
			
		||||
                    "___" [(fn [x] :foo)]}]
 | 
			
		||||
 | 
			
		||||
 ["sequence_comprehensions" {"__" [[0 1 2 3 4 5]
 | 
			
		||||
                                   (* index index)
 | 
			
		||||
                                   (range 10)
 | 
			
		||||
                                   (odd? index) (* index index)
 | 
			
		||||
                                   [row column]
 | 
			
		||||
                                   ]}]
 | 
			
		||||
 | 
			
		||||
 ["creating_functions" {"__" [true false true
 | 
			
		||||
                              4
 | 
			
		||||
                              :a :b :c :d
 | 
			
		||||
                              :c :d
 | 
			
		||||
                              4
 | 
			
		||||
                              8]
 | 
			
		||||
                        "___" [(complement nil?)
 | 
			
		||||
                               multiply-by-5
 | 
			
		||||
                               (comp dec square)]}]
 | 
			
		||||
 | 
			
		||||
 ["recursion" {"__" [true
 | 
			
		||||
                     acc
 | 
			
		||||
                     (loop [coll coll
 | 
			
		||||
                            acc ()]
 | 
			
		||||
                       (if (seq coll)
 | 
			
		||||
                         (recur (rest coll) (conj acc (first coll)))
 | 
			
		||||
                         acc))
 | 
			
		||||
                     (loop [n n
 | 
			
		||||
                            acc 1]
 | 
			
		||||
                       (if (zero? n)
 | 
			
		||||
                         acc
 | 
			
		||||
                         (recur (dec n) (* acc n))))]
 | 
			
		||||
               "___" [not]}]
 | 
			
		||||
 | 
			
		||||
 ["destructuring" {"__" [":bar:foo"
 | 
			
		||||
                         (format (str "First comes %s, "
 | 
			
		||||
                                      "then comes %s, "
 | 
			
		||||
                                      "then comes %s with the baby carriage")
 | 
			
		||||
                                 a b c)
 | 
			
		||||
                         (apply str
 | 
			
		||||
                                (interpose " "
 | 
			
		||||
                                           (apply list
 | 
			
		||||
                                                  first-name
 | 
			
		||||
                                                  last-name
 | 
			
		||||
                                                  (interleave (repeat "aka") aliases))))
 | 
			
		||||
                         {:original-parts full-name
 | 
			
		||||
                          :named-parts {:first first-name :last last-name}}
 | 
			
		||||
                         (str street-address ", " city ", " state)
 | 
			
		||||
                         city state
 | 
			
		||||
                         (str street-address ", " city ", " state)]
 | 
			
		||||
                   "___" [(fn [[fname lname]
 | 
			
		||||
                              {:keys [street-address city state]}]
 | 
			
		||||
                            (str fname " " lname ", "
 | 
			
		||||
                                 street-address ", " city ", " state))
 | 
			
		||||
                          ]}]
 | 
			
		||||
 | 
			
		||||
 ["refs" {"__" ["hello"
 | 
			
		||||
                "hello"
 | 
			
		||||
                "better"
 | 
			
		||||
                "better!!!"
 | 
			
		||||
                (dosync (ref-set the-world 0))
 | 
			
		||||
                (map :jerry [@the-world @bizarro-world])
 | 
			
		||||
                ]
 | 
			
		||||
          "___" [(fn [x] (+ 20 x))]}]
 | 
			
		||||
 | 
			
		||||
 ["atoms" {"__" [0
 | 
			
		||||
                 1
 | 
			
		||||
                 (swap! atomic-clock (partial + 4))
 | 
			
		||||
                 20
 | 
			
		||||
                 20
 | 
			
		||||
                 atomic-clock 20 :fin
 | 
			
		||||
                 ]}]
 | 
			
		||||
 | 
			
		||||
 ["macros" {"__" [~(first form)
 | 
			
		||||
                  ~(nth form 2)
 | 
			
		||||
                  form
 | 
			
		||||
                  (drop 2 form)
 | 
			
		||||
                  "Hello, Macros!"
 | 
			
		||||
                  10
 | 
			
		||||
                  '(+ 9 1)
 | 
			
		||||
                  '(* 10 2)
 | 
			
		||||
                  '(+ 10 (2 * 3))]}]
 | 
			
		||||
 | 
			
		||||
 ["datatypes" {"__" [(print
 | 
			
		||||
                      (str "You're really the "
 | 
			
		||||
                           (.category this)
 | 
			
		||||
                           ", " recipient "... sorry."))
 | 
			
		||||
                     "peace"
 | 
			
		||||
                     "literature"
 | 
			
		||||
                     "physics"
 | 
			
		||||
                     nil
 | 
			
		||||
                     [true false]
 | 
			
		||||
                     (str "Congratulations on your Best Picture Oscar, "
 | 
			
		||||
                          "Evil Alien Conquerors!")]}]
 | 
			
		||||
 | 
			
		||||
 ["java_interop" {"__" [java.lang.String
 | 
			
		||||
                        "SELECT * FROM"
 | 
			
		||||
                        10
 | 
			
		||||
                        1024
 | 
			
		||||
                        ]
 | 
			
		||||
                  "___" [#(.toUpperCase %)
 | 
			
		||||
                         ]
 | 
			
		||||
                  }]]
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
CLASSPATH=src
 | 
			
		||||
 | 
			
		||||
for f in lib/*.jar; do
 | 
			
		||||
for f in lib/*.jar lib/dev/*.jar resources/; do
 | 
			
		||||
  CLASSPATH=$CLASSPATH:$f
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
CLASSPATH=src
 | 
			
		||||
 | 
			
		||||
for f in lib/*.jar; do
 | 
			
		||||
for f in lib/*.jar lib/dev/*.jar resources/; do
 | 
			
		||||
  CLASSPATH=$CLASSPATH:$f
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
(load "path_to_enlightenment")
 | 
			
		||||
(load "koan_engine/runner")
 | 
			
		||||
(do
 | 
			
		||||
  (in-ns 'path-to-enlightenment)
 | 
			
		||||
  (run))
 | 
			
		||||
  (in-ns 'koan-engine.runner)
 | 
			
		||||
  (exec "run"))
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,8 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
CLASSPATH=src
 | 
			
		||||
 | 
			
		||||
for f in lib/*.jar; do
 | 
			
		||||
 | 
			
		||||
for f in lib/*.jar lib/dev/*.jar resources/; do
 | 
			
		||||
  CLASSPATH=$CLASSPATH:$f
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
(load "path_to_answer_sheet")
 | 
			
		||||
(load "koan_engine/runner")
 | 
			
		||||
(do
 | 
			
		||||
  (in-ns 'path-to-answer-sheet)
 | 
			
		||||
  (run))
 | 
			
		||||
  (in-ns 'koan-engine.runner)
 | 
			
		||||
  (exec "test"))
 | 
			
		||||
 
 | 
			
		||||
@@ -1,279 +0,0 @@
 | 
			
		||||
(ns path-to-answer-sheet
 | 
			
		||||
  (:use [runner.koans :only [ordered-koans]]
 | 
			
		||||
        [path-to-enlightenment :only [meditations fancy-assert __ ___]]
 | 
			
		||||
        [clojure.string :only [join split trim] :as string]))
 | 
			
		||||
 | 
			
		||||
(def answers
 | 
			
		||||
  {"equalities" {"__" [true
 | 
			
		||||
                       2
 | 
			
		||||
                       7
 | 
			
		||||
                       5
 | 
			
		||||
                       4/2
 | 
			
		||||
                       false
 | 
			
		||||
                       6/3
 | 
			
		||||
                       3]}
 | 
			
		||||
 | 
			
		||||
   "lists" {"__" [1 2 3 4 5
 | 
			
		||||
                  1
 | 
			
		||||
                  [2 3 4 5]
 | 
			
		||||
                  ()
 | 
			
		||||
                  [:a :b :c :d :e]
 | 
			
		||||
                  [0 :a :b :c :d :e]
 | 
			
		||||
                  :a
 | 
			
		||||
                  [:b :c :d :e]
 | 
			
		||||
                  "No dice!"
 | 
			
		||||
                  ()]}
 | 
			
		||||
 | 
			
		||||
   "vectors" {"__" [1
 | 
			
		||||
                    []
 | 
			
		||||
                    [1]
 | 
			
		||||
                    [nil]
 | 
			
		||||
                    2
 | 
			
		||||
                    [333]
 | 
			
		||||
                    :peanut
 | 
			
		||||
                    :jelly
 | 
			
		||||
                    :jelly
 | 
			
		||||
                    [:butter :and]
 | 
			
		||||
                    3]}
 | 
			
		||||
 | 
			
		||||
   "sets" {"__" [nil
 | 
			
		||||
                 3
 | 
			
		||||
                 #{1 2 3 4 5}
 | 
			
		||||
                 #{1 2 3 4 5}
 | 
			
		||||
                 #{2 3}
 | 
			
		||||
                 #{1 4}]}
 | 
			
		||||
 | 
			
		||||
   "maps" {"__" [{}
 | 
			
		||||
                 0
 | 
			
		||||
                 1
 | 
			
		||||
                 2
 | 
			
		||||
                 2
 | 
			
		||||
                 1
 | 
			
		||||
                 1
 | 
			
		||||
                 "Vancouver"
 | 
			
		||||
                 nil
 | 
			
		||||
                 :key-not-found
 | 
			
		||||
                 true
 | 
			
		||||
                 false
 | 
			
		||||
                 "February"
 | 
			
		||||
                 1 "January"
 | 
			
		||||
                 2006 2010 2014
 | 
			
		||||
                 "Vancouver"]}
 | 
			
		||||
 | 
			
		||||
   "functions" {"__" [20
 | 
			
		||||
                      10 5
 | 
			
		||||
                      30 2
 | 
			
		||||
                      15
 | 
			
		||||
                      20 '*]
 | 
			
		||||
                "___" ['(fn [f] (f 5))
 | 
			
		||||
                       '(fn [f] (f 5))]}
 | 
			
		||||
 | 
			
		||||
   "conditionals" {"__" [:a
 | 
			
		||||
                         []
 | 
			
		||||
                         nil
 | 
			
		||||
                         :glory
 | 
			
		||||
                         4 6 :your-road
 | 
			
		||||
                         ''doom 0
 | 
			
		||||
                         :cocked-pistol
 | 
			
		||||
                         :say-what?]}
 | 
			
		||||
 | 
			
		||||
   "higher_order_functions" {"__" [4 8 12
 | 
			
		||||
                                   '(* x x)
 | 
			
		||||
                                   [false false true false false]
 | 
			
		||||
                                   ()
 | 
			
		||||
                                   [:anything :goes :here]
 | 
			
		||||
                                   '(< x 31)
 | 
			
		||||
                                   '(* 10 x) '(< x 4)
 | 
			
		||||
                                   24
 | 
			
		||||
                                   100
 | 
			
		||||
                                   '(count a) '(count b)]}
 | 
			
		||||
 | 
			
		||||
   "runtime_polymorphism" {"__" ['(str (:name a) " eats veggies.")
 | 
			
		||||
                                 '(str (:name a) " eats animals.")
 | 
			
		||||
                                 '(str "I don't know what " (:name a) " eats.")
 | 
			
		||||
                                 "Hello World!"
 | 
			
		||||
                                 "Hello, you silly world."
 | 
			
		||||
                                 "Hello to this group: Peter, Paul, Mary!" ]}
 | 
			
		||||
 | 
			
		||||
   "lazy_sequences" {"__" [[1 2 3 4]
 | 
			
		||||
                           [0 1 2 3 4]
 | 
			
		||||
                           10
 | 
			
		||||
                           95
 | 
			
		||||
                           '(range 20)
 | 
			
		||||
                           :a]
 | 
			
		||||
                     "___" ['(fn [x] :foo)]}
 | 
			
		||||
 | 
			
		||||
   "sequence_comprehensions" {"__" [[0 1 2 3 4 5]
 | 
			
		||||
                                    '(* index index)
 | 
			
		||||
                                    '(range 10)
 | 
			
		||||
                                    '(odd? index) '(* index index)
 | 
			
		||||
                                    '[row column]
 | 
			
		||||
                                    ]}
 | 
			
		||||
 | 
			
		||||
   "creating_functions" {"__" [true false true
 | 
			
		||||
                               4
 | 
			
		||||
                              :a :b :c :d
 | 
			
		||||
                              :c :d
 | 
			
		||||
                              4
 | 
			
		||||
                              8]
 | 
			
		||||
                        "___" ['(complement nil?)
 | 
			
		||||
                               'multiply-by-5
 | 
			
		||||
                               '(comp dec square)]}
 | 
			
		||||
 | 
			
		||||
   "recursion" {"__" [true
 | 
			
		||||
                      'acc
 | 
			
		||||
                      '(loop [coll coll
 | 
			
		||||
                              acc ()]
 | 
			
		||||
                         (if (seq coll)
 | 
			
		||||
                           (recur (rest coll) (conj acc (first coll)))
 | 
			
		||||
                           acc))
 | 
			
		||||
                      '(loop [n n
 | 
			
		||||
                              acc 1]
 | 
			
		||||
                         (if (zero? n)
 | 
			
		||||
                             acc
 | 
			
		||||
                             (recur (dec n) (* acc n))))]
 | 
			
		||||
                "___" ['not]}
 | 
			
		||||
 | 
			
		||||
   "destructuring" {"__" [":bar:foo"
 | 
			
		||||
                          '(format (str "First comes %s, "
 | 
			
		||||
                                        "then comes %s, "
 | 
			
		||||
                                        "then comes %s with the baby carriage")
 | 
			
		||||
                                   a b c)
 | 
			
		||||
                          '(apply str
 | 
			
		||||
                             (interpose " "
 | 
			
		||||
                               (apply list
 | 
			
		||||
                                  first-name
 | 
			
		||||
                                  last-name
 | 
			
		||||
                                  (interleave (repeat "aka") aliases))))
 | 
			
		||||
                          '{:original-parts full-name
 | 
			
		||||
                            :named-parts {:first first-name :last last-name}}
 | 
			
		||||
                          '(str street-address ", " city ", " state)
 | 
			
		||||
                          'city 'state
 | 
			
		||||
                            '(str street-address ", " city ", " state)]
 | 
			
		||||
                    "___" ['(fn [[fname lname]
 | 
			
		||||
                                 {:keys [street-address city state]}]
 | 
			
		||||
                              (str fname " " lname ", "
 | 
			
		||||
                                   street-address ", " city ", " state))
 | 
			
		||||
                           ]}
 | 
			
		||||
   "refs" {"__" ["hello"
 | 
			
		||||
                 "hello"
 | 
			
		||||
                 "better"
 | 
			
		||||
                 "better!!!"
 | 
			
		||||
                 '(dosync (ref-set the-world 0))
 | 
			
		||||
                 '(map :jerry [@the-world @bizarro-world])
 | 
			
		||||
                 ]
 | 
			
		||||
           "___" ['(fn [x] (+ 20 x))]}
 | 
			
		||||
 | 
			
		||||
   "atoms" {"__" [0
 | 
			
		||||
                  1
 | 
			
		||||
                  '(swap! atomic-clock (partial + 4))
 | 
			
		||||
                  20
 | 
			
		||||
                  20
 | 
			
		||||
                  'atomic-clock 20 :fin
 | 
			
		||||
                  ]}
 | 
			
		||||
 | 
			
		||||
   "macros" {"__" ['~(first form)
 | 
			
		||||
                   '~(nth form 2)
 | 
			
		||||
                   'form
 | 
			
		||||
                   '(drop 2 form)
 | 
			
		||||
                   "Hello, Macros!"
 | 
			
		||||
                   10
 | 
			
		||||
                   ''(+ 9 1)
 | 
			
		||||
                   ''(* 10 2)
 | 
			
		||||
                   ''(+ 10 (2 * 3))]}
 | 
			
		||||
 | 
			
		||||
   "datatypes" {"__" ['(print
 | 
			
		||||
                         (str "You're really the "
 | 
			
		||||
                              (.category this)
 | 
			
		||||
                              ", " recipient "... sorry."))
 | 
			
		||||
                      "peace"
 | 
			
		||||
                      "literature"
 | 
			
		||||
                      "physics"
 | 
			
		||||
                      nil
 | 
			
		||||
                      [true false]
 | 
			
		||||
                      (str "Congratulations on your Best Picture Oscar, "
 | 
			
		||||
                           "Evil Alien Conquerors!")]}
 | 
			
		||||
 | 
			
		||||
   "java_interop" {"__" ['java.lang.String
 | 
			
		||||
                         "SELECT * FROM"
 | 
			
		||||
                         10
 | 
			
		||||
                         1024
 | 
			
		||||
                         ]
 | 
			
		||||
                   "___" ['#(.toUpperCase %)
 | 
			
		||||
                          ]
 | 
			
		||||
                   }
 | 
			
		||||
 | 
			
		||||
   })
 | 
			
		||||
 | 
			
		||||
(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)))))))
 | 
			
		||||
 | 
			
		||||
(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)))
 | 
			
		||||
 | 
			
		||||
(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))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -1,49 +0,0 @@
 | 
			
		||||
(ns path-to-enlightenment
 | 
			
		||||
  (:use [runner.freshness :only [setup-freshener]])
 | 
			
		||||
  (:require [clojure.set]
 | 
			
		||||
            [clojure.string]))
 | 
			
		||||
 | 
			
		||||
(def __ :fill-in-the-blank)
 | 
			
		||||
(def ___ (fn [& args] __))
 | 
			
		||||
 | 
			
		||||
(defmacro fancy-assert
 | 
			
		||||
  ([x] (fancy-assert x ""))
 | 
			
		||||
  ([x message]
 | 
			
		||||
   `(try
 | 
			
		||||
     (assert ~x ~message)
 | 
			
		||||
     (catch Exception e#
 | 
			
		||||
       (throw (Exception. (str '~message "\n" '~x )
 | 
			
		||||
                          e#))))))
 | 
			
		||||
 | 
			
		||||
(defmacro meditations [& forms]
 | 
			
		||||
  (let [pairs (partition 2 forms)
 | 
			
		||||
        tests (map (fn [[doc# code#]]
 | 
			
		||||
                     `(fancy-assert ~code# ~doc#))
 | 
			
		||||
                   pairs)]
 | 
			
		||||
    `(do ~@tests)))
 | 
			
		||||
 | 
			
		||||
(defn require-version [[required-major required-minor]]
 | 
			
		||||
  (let [{:keys [major minor]} *clojure-version*]
 | 
			
		||||
    (if (or (< major required-major)
 | 
			
		||||
        (and (== major required-major) (< minor required-minor)))
 | 
			
		||||
      (throw (Exception. (str "Clojure version " required-major "."
 | 
			
		||||
                              required-minor " or higher required."))))))
 | 
			
		||||
 | 
			
		||||
(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 (clojure.string/split version-string #"[\.\-]")))))
 | 
			
		||||
 | 
			
		||||
(defn run []
 | 
			
		||||
  (require-version (parse-required-version))
 | 
			
		||||
  (setup-freshener))
 | 
			
		||||
 | 
			
		||||
@@ -1,34 +0,0 @@
 | 
			
		||||
(ns runner.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?]])
 | 
			
		||||
  (:import [java.util.concurrent ScheduledThreadPoolExecutor TimeUnit]))
 | 
			
		||||
 | 
			
		||||
(defn files-to-keep-fresh []
 | 
			
		||||
  (clj-files-in (file "src" "koans")))
 | 
			
		||||
 | 
			
		||||
(defn report-refresh [report]
 | 
			
		||||
  (when-let [refreshed-files (seq (:reloaded report))]
 | 
			
		||||
    (let [these-koans (filter
 | 
			
		||||
                        (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]})
 | 
			
		||||
          (namaste))))
 | 
			
		||||
    (println))
 | 
			
		||||
  :refreshed)
 | 
			
		||||
 | 
			
		||||
(def refresh! (freshener files-to-keep-fresh report-refresh))
 | 
			
		||||
 | 
			
		||||
(def scheduler (ScheduledThreadPoolExecutor. 1))
 | 
			
		||||
 | 
			
		||||
(defn setup-freshener []
 | 
			
		||||
  (println "Starting auto-runner...")
 | 
			
		||||
  (.scheduleWithFixedDelay scheduler refresh! 0 500 TimeUnit/MILLISECONDS)
 | 
			
		||||
  (.awaitTermination scheduler Long/MAX_VALUE TimeUnit/SECONDS))
 | 
			
		||||
@@ -1,58 +0,0 @@
 | 
			
		||||
(ns runner.koans
 | 
			
		||||
  (:use [clojure.java.io :only [file]]))
 | 
			
		||||
 | 
			
		||||
(def ordered-koans
 | 
			
		||||
     ["equalities"
 | 
			
		||||
      "lists"
 | 
			
		||||
      "vectors"
 | 
			
		||||
      "sets"
 | 
			
		||||
      "maps"
 | 
			
		||||
      "functions"
 | 
			
		||||
      "conditionals"
 | 
			
		||||
      "higher_order_functions"
 | 
			
		||||
      "runtime_polymorphism"
 | 
			
		||||
      "lazy_sequences"
 | 
			
		||||
      "sequence_comprehensions"
 | 
			
		||||
      "creating_functions"
 | 
			
		||||
      "recursion"
 | 
			
		||||
      "destructuring"
 | 
			
		||||
      "refs"
 | 
			
		||||
      "atoms"
 | 
			
		||||
      "macros"
 | 
			
		||||
      "datatypes"
 | 
			
		||||
      "java_interop"])
 | 
			
		||||
 | 
			
		||||
(defn ordered-koan-paths  []
 | 
			
		||||
  (map (fn [koan-name]
 | 
			
		||||
           (.getCanonicalPath (file "src" "koans" (str koan-name ".clj"))))
 | 
			
		||||
       ordered-koans))
 | 
			
		||||
 | 
			
		||||
(defn among-paths? [files]
 | 
			
		||||
  (into #{} (map #(.getCanonicalPath %) files)))
 | 
			
		||||
 | 
			
		||||
(defn next-koan-path [last-koan-path]
 | 
			
		||||
  (loop [[this-koan & more :as koan-paths] (ordered-koan-paths)]
 | 
			
		||||
    (when (seq more)
 | 
			
		||||
      (if (= last-koan-path this-koan)
 | 
			
		||||
        (first more)
 | 
			
		||||
        (recur more)))))
 | 
			
		||||
 | 
			
		||||
(defn tests-pass? [file-path]
 | 
			
		||||
  (use '[path-to-enlightenment :only [meditations __ ___]])
 | 
			
		||||
  (try
 | 
			
		||||
    (load-file file-path)
 | 
			
		||||
    true
 | 
			
		||||
    (catch Exception e
 | 
			
		||||
      (println)
 | 
			
		||||
      (println "Problem in" file-path)
 | 
			
		||||
      (println "---------------------")
 | 
			
		||||
      (println "Assertion failed!")
 | 
			
		||||
      (let [actual-error (or (.getCause e) e)
 | 
			
		||||
            message (or (.getMessage actual-error)
 | 
			
		||||
                        (.toString actual-error))]
 | 
			
		||||
        (println (.replaceFirst message "^Assert failed: " "")))
 | 
			
		||||
      false)))
 | 
			
		||||
 | 
			
		||||
(defn namaste []
 | 
			
		||||
  (println "\nYou have achieved clojure enlightenment. Namaste."))
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user