Skip to content
Browse files

Extracted koan logic out into koan-engine.

  • Loading branch information...
1 parent e2b5f87 commit 337d39684a30e87d2dc124be3b62a68b7221edb9 @sritchie sritchie committed with trptcolin
Showing with 214 additions and 433 deletions.
  1. +1 −0 .gitignore
  2. +4 −4 project.clj
  3. +199 −0 resources/koans.clj
  4. +1 −1 script/repl
  5. +1 −1 script/run
  6. +3 −3 script/run.clj
  7. +2 −1 script/test
  8. +3 −3 script/test.clj
  9. +0 −279 src/path_to_answer_sheet.clj
  10. +0 −49 src/path_to_enlightenment.clj
  11. +0 −34 src/runner/freshness.clj
  12. +0 −58 src/runner/koans.clj
View
1 .gitignore
@@ -4,3 +4,4 @@ lib
releases
*.jar
.DS_Store
+.lein-deps-sum
View
8 project.clj
@@ -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"]])
View
199 resources/koans.clj
@@ -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 %)
+ ]
+ }]]
View
2 script/repl
@@ -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
View
2 script/run
@@ -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
View
6 script/run.clj
@@ -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"))
View
3 script/test
@@ -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
View
6 script/test.clj
@@ -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"))
View
279 src/path_to_answer_sheet.clj
@@ -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))
-
-
View
49 src/path_to_enlightenment.clj
@@ -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))
-
View
34 src/runner/freshness.clj
@@ -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))
View
58 src/runner/koans.clj
@@ -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."))
-

0 comments on commit 337d396

Please sign in to comment.
Something went wrong with that request. Please try again.