Saturday, June 14, 2014

Kata: Berlin Clock in Clojure with Midje

I did the Berlin Clock kata in Clojure using Midje.

These are the tests:

(ns berlin_clock.t-core
(:use midje.sweet)
(:use [berlin_clock.core]))
(use '[clojure.string :only (join)])
(facts "about Berlin Clock"
(facts "seconds lamp"
(fact "It turns on for one second (Y)"
(show "00:00:00") => (join "\n"
["Y"
"OOOO"
"OOOO"
"OOOOOOOOOOO"
"OOOO"]))
(fact "It turns off for the next second (O)"
(show "00:00:01") => (join "\n"
["O"
"OOOO"
"OOOO"
"OOOOOOOOOOO"
"OOOO"])))
(facts "hours lamps first row"
(fact "it contains 4 lamps that represent 5 hours each when red (R)"
(show "05:00:00") => (join "\n"
["Y"
"ROOO"
"OOOO"
"OOOOOOOOOOO"
"OOOO"])
(show "10:00:00") => (join "\n"
["Y"
"RROO"
"OOOO"
"OOOOOOOOOOO"
"OOOO"])
(show "15:00:00") => (join "\n"
["Y"
"RRRO"
"OOOO"
"OOOOOOOOOOO"
"OOOO"])))
(facts "hours lamps second row"
(fact "it contains 4 lamps that represent 1 hour each when red (R)"
(show "06:00:00") => (join "\n"
["Y"
"ROOO"
"ROOO"
"OOOOOOOOOOO"
"OOOO"])
(show "22:00:00") => (join "\n"
["Y"
"RRRR"
"RROO"
"OOOOOOOOOOO"
"OOOO"])
(show "14:00:00") => (join "\n"
["Y"
"RROO"
"RRRR"
"OOOOOOOOOOO"
"OOOO"])))
(facts "minutes lamps first row"
(fact "it contains 11 lamps that repesents 5 minute each,
every 3rd lamp is red but the rest are yellow"
(show "00:15:00") => (join "\n"
["Y"
"OOOO"
"OOOO"
"YYROOOOOOOO"
"OOOO"])
(show "00:50:00") => (join "\n"
["Y"
"OOOO"
"OOOO"
"YYRYYRYYRYO"
"OOOO"])))
(facts "minutes lamps second row"
(fact "it contains 4 yellow lamps that represents 1 minute each"
(show "00:16:00") => (join "\n"
["Y"
"OOOO"
"OOOO"
"YYROOOOOOOO"
"YOOO"])
(show "00:18:00") => (join "\n"
["Y"
"OOOO"
"OOOO"
"YYROOOOOOOO"
"YYYO"])
(show "00:19:00") => (join "\n"
["Y"
"OOOO"
"OOOO"
"YYROOOOOOOO"
"YYYY"]))))

And this is the final version of the code:

(ns berlin_clock.core)
(use '[clojure.string :only (join split)])
(defn show [time]
(let
[[h m s] (map #(Integer. %) (split time #":"))
turn-on-red (fn [num-lamps] (repeat num-lamps "R"))
turn-on-yellow (fn [num-lamps] (repeat num-lamps "Y"))
turn-off (fn [num-lamps] (repeat num-lamps "O"))
turn-on-YYR (fn [num-lamps-on]
(take num-lamps-on (cycle ["Y" "Y" "R"])))
show (comp (partial apply str) concat)
show-lamps (fn [num-lamps-on num-lamps turn-on]
(let [num-lamps-off (- num-lamps
num-lamps-on)]
(show (turn-on num-lamps-on)
(turn-off num-lamps-off))))
seconds (if (zero? (rem s 2)) "Y" "O")
hours-first-row (show-lamps (quot h 5) 4 turn-on-red)
hours-second-row (show-lamps (rem h 5) 4 turn-on-red)
minutes-first-row (show-lamps (quot m 5) 11 turn-on-YYR)
minutes-second-row (show-lamps (rem m 5) 4 turn-on-yellow)]
(join "\n"
[seconds
hours-first-row
hours-second-row
minutes-first-row
minutes-second-row])))

I used a mix of TDD and REPL-driven development.

To document the process I commited the code after every passing test and every refactor.
I also commited the .lein-repl-history file so that you can see all the micro-tests I did on the REPL to create some of the features and learn about Clojure including many beginner mistakes :)

You can find the resulting code in this GitHub repository.

No comments:

Post a Comment