Created
January 5, 2015 14:31
-
-
Save geofflane/ee8283f7f990e9fe2d6e to your computer and use it in GitHub Desktop.
key-drone
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns key-drone.core-test | |
(:use clj-drone.core) | |
(:require [clojure.test :refer :all] | |
[key-drone.core :refer :all])) | |
(deftest key-handler-test | |
(def navigation-keymap | |
{ | |
\h :tilt-left | |
\H :tilt-left | |
\l :tilt-right | |
\L :tilt-right | |
\u :up | |
\U :up | |
\d :down | |
\D :down | |
\j :tilt-back | |
\J :tilt-back | |
\k :tilt-front | |
\K :tilt-front | |
\t :take-off | |
\T :take-off | |
\g :land | |
\G :land | |
\s :spin-right | |
\S :spin-right | |
\A :spin-left | |
\a :spin-left | |
\E :emergency | |
\e :emergency | |
} | |
) | |
(doseq [keymap navigation-keymap] | |
(let [key-char (first keymap) | |
expected-nav-plan (second keymap)] | |
(testing (str "should navigate " expected-nav-plan " with " key-char) | |
(with-redefs [drone (fn [actual-nav-plan & args] (is (= expected-nav-plan actual-nav-plan)))] | |
(is (= :continue (key-handler (int key-char)))))))) | |
(testing "should quit program" | |
(is (= :quit (key-handler (int \q)))) | |
(is (= :quit (key-handler (int \Q))))) | |
(testing "should handle invalid keystroke" | |
(is (= :invalid (key-handler (int \X)))))) | |
(deftest navigate-test | |
(testing "should catch io exceptions and log message" | |
(with-redefs [drone (fn [nav-plan & args] (throw (java.io.IOException. "OOPS: expected exception")))] | |
(navigate :up 1)))) | |
(deftest control-loop-test | |
(testing "exit after quit is returned" | |
(control-loop (fn [] :quit)))) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns key-drone.core | |
(:require [clj-drone.core :refer :all] | |
[clojure.java.io :as io]) | |
(:import [jline.console ConsoleReader]) | |
(:gen-class :main true)) | |
(defn log | |
[message] | |
(println message)) | |
(defn navigate | |
[nav-plan & args] | |
(try | |
(log (str "Drone " nav-plan " at " args)) | |
(apply drone nav-plan args) | |
(catch java.io.IOException e | |
(log (str "caught exception: " (.getMessage e)))))) | |
(defn- navigate-and-continue | |
[plan & args] | |
(do | |
(navigate plan args) | |
:continue)) | |
(defn- invalid-key | |
[] | |
(do | |
(log "Invalid key pressed") | |
:invalid)) | |
(defn- quit | |
[] | |
(do | |
(log "Closing down") | |
:quit)) | |
;input: ascii code of key | |
;transform: apply function associated with key | |
;output: :continue, :quit | |
;implements interfaces: | |
; - control handler (output :quit or anything else) | |
; - key press handler (input asciiCode, output: true/false) | |
(defn key-handler | |
[asciiCode] | |
(let [keypressed (Character/toUpperCase (char asciiCode))] | |
(cond | |
(= keypressed \T) (navigate-and-continue :take-off) | |
(= keypressed \G) (navigate-and-continue :land) | |
(= keypressed \H) (navigate-and-continue :tilt-left 1) | |
(= keypressed \L) (navigate-and-continue :tilt-right 1) | |
(= keypressed \K) (navigate-and-continue :tilt-front 1) | |
(= keypressed \J) (navigate-and-continue :tilt-back 1) | |
(= keypressed \S) (navigate-and-continue :spin-right 1) | |
(= keypressed \A) (navigate-and-continue :spin-left 1) | |
(= keypressed \U) (navigate-and-continue :up 1) | |
(= keypressed \D) (navigate-and-continue :down 1) | |
(= keypressed \E) (navigate-and-continue :emergency) | |
(= keypressed \Q) (quit) | |
:else (invalid-key)))) | |
;input: key press handler | |
;transform: input key strokes | |
;output; true/false from handler | |
;requires interface: | |
; - key press handler | |
(defn key-reader | |
"generates keystrokes" | |
[key-press-handler] | |
(let [reader (ConsoleReader.)] | |
(fn [] | |
(let [asciiCode (.readCharacter reader)] | |
(key-press-handler asciiCode))))) | |
;input: control handler | |
;transform: call handler until quit is pressed | |
;output: false | |
;requires interface: | |
; - control handler | |
(defn control-loop | |
[key-reader-fn] | |
(let [result (key-reader-fn)] | |
(if (= result :quit) | |
0 | |
(recur key-reader-fn)))) | |
;input: none | |
;transform: started application into drone control | |
;output: exit code 0 for success else failure | |
(defn -main | |
"Command line entry point for key-drone" | |
[& args] | |
(do | |
(log "Starting Key Drone (q to quit)") | |
(drone-initialize) | |
(control-loop (key-reader key-handler)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment