Extracted koan logic out into koan-engine.
This commit is contained in:
parent
e2b5f87984
commit
337d39684a
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ lib
|
|||||||
releases
|
releases
|
||||||
*.jar
|
*.jar
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.lein-deps-sum
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
(defproject functional-koans "0.4.5"
|
(defproject functional-koans "0.4.5"
|
||||||
:description "The functional koans"
|
:description "The functional koans."
|
||||||
:dependencies [[org.clojure/clojure "1.3.0"]
|
:dependencies [[org.clojure/clojure "1.3.0"]
|
||||||
[fresh "1.0.2"]
|
[koan-engine "0.1.0"]]
|
||||||
[jline "0.9.94" :exclusions [junit]]]
|
:dev-dependencies [[swank-clojure "1.3.0" :exclusions [org.clojure/clojure]]
|
||||||
: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
|
#!/bin/sh
|
||||||
CLASSPATH=src
|
CLASSPATH=src
|
||||||
|
|
||||||
for f in lib/*.jar; do
|
for f in lib/*.jar lib/dev/*.jar resources/; do
|
||||||
CLASSPATH=$CLASSPATH:$f
|
CLASSPATH=$CLASSPATH:$f
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
CLASSPATH=src
|
CLASSPATH=src
|
||||||
|
|
||||||
for f in lib/*.jar; do
|
for f in lib/*.jar lib/dev/*.jar resources/; do
|
||||||
CLASSPATH=$CLASSPATH:$f
|
CLASSPATH=$CLASSPATH:$f
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
(load "path_to_enlightenment")
|
(load "koan_engine/runner")
|
||||||
(do
|
(do
|
||||||
(in-ns 'path-to-enlightenment)
|
(in-ns 'koan-engine.runner)
|
||||||
(run))
|
(exec "run"))
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
CLASSPATH=src
|
CLASSPATH=src
|
||||||
|
|
||||||
for f in lib/*.jar; do
|
|
||||||
|
for f in lib/*.jar lib/dev/*.jar resources/; do
|
||||||
CLASSPATH=$CLASSPATH:$f
|
CLASSPATH=$CLASSPATH:$f
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
(load "path_to_answer_sheet")
|
(load "koan_engine/runner")
|
||||||
(do
|
(do
|
||||||
(in-ns 'path-to-answer-sheet)
|
(in-ns 'koan-engine.runner)
|
||||||
(run))
|
(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."))
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user