Clojure Koans

One helpful set of exercises for Clojure newcomers, the Clojure Koans,[26] has its code structure based on a macro called meditations that presents a boilerplate-free interface. Perhaps you’ve already tried these out as I suggested in the Introduction and wondered how it worked under the hood. The koans ask you to fill in the blanks in order to make each test pass:

apis/koans_1.clj
 
(meditations
 
"We shall contemplate truth by testing reality, via equality"
 
(​=​ __ true)
 
 
"To understand reality, we must compare our expectations against reality"
 
(​=​ __ (​+​ 1 1)))

But in the interface that the meditations macro presents, there are no tests! We just see some (more or less helpful) text vaguely describing an expression that we want to make truthy. Under the hood, however, meditations creates assertions (using a helper function from another namespace called fancy-assert whose details we don’t need to see) that allow users to see whether their input is correct:

apis/koans_2.clj
 
(​ns​ koan-engine.core
 
(:require [koan-engine.util :as u]))
 
 
(​def​ __ :fill-in-the-blank)
 
(​def​ ___ (​fn​ [& args] __))
 
 
(​defmacro​ meditations [& forms]
 
(​let​ [pairs (​partition​ 2 forms)
 
tests (​map​ (​fn​ [[doc# code#]]
 
`(u/fancy-assert ~code# ~doc#))
 
pairs)]
 
`(​do​ ~@tests)))

By having a macro like this that maps over pairs of inputs and produces assertion expressions, we avoid littering the code with these fancy-assert bits. For this use case, eliminating the extra code allows the user to focus only on what the koans are trying to teach. The boilerplate we’d see without meditations isn’t terribly noisy code, but it certainly isn’t as tidy as the original version:

apis/koans_3.clj
 
(​do
 
(fancy-assert
 
(​=​ __ true)
 
"We shall contemplate truth by testing reality, via equality"​)
 
 
(fancy-assert
 
(​=​ __ (​+​ 1 1))
 
"To understand reality, we must compare our expectations against reality"​))

It’s important to keep in mind here that macros are not the only way to remove duplicate code: delegating to single-purpose plain old functions also does that job nicely. However, in cases like these where we need full control of the execution of the expressions in order to provide error handling or other context, we need macros to provide that context (as we talked about in Chapter 4, Evaluate Code in Context).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.22.164