Part 1 of this series can be found here.
In this chapter, we start to see more of _why’s use of Ruby code to do metaphysical things like catch stars and use them to construct star-monkeys. Of course, there is no earthly way to test this code, but I’m including these examples in order to demonstrate Clojure’s syntax as it compares to Ruby’s.
As we get into these more involved examples, it becomes easier to see how Clojure stacks up against Ruby in terms of the simplicity and readibility of the code. Being a functional, Lisp-based language, Clojure tends to be more concise than Ruby in general. But on the other hand, Ruby has a lot of really neat jars of syntactical sugar that you can dip into to make your code more readable. For example, _why uses Ruby’s built-in Dir
class to easily get an array of files matching 'idea-*.txt'
. The syntax is just Dir['idea-*.txt']
. To translate this to Clojure without relying on any third party libraries, I had to resort to using Java inter-op, which ended up being a little wordier and just didn’t have the same level of simplicity that Ruby’s Dir
class methods provide. (See ex. 24.) One wonders whether we might someday get some handy file/directory helper functions in a future version of Clojure. We already have slurp
and spit
, which make reading and writing to files dead simple, so it doesn’t seem like that much of a stretch. In fact, there is already a file-seq
function that returns a lazy sequence of files, but to use it, you have to feed it a Java path object using something like (clojure.java.io/file "/path/to/directory")
. In my translation, I found it simpler to import java.io.File
and use (.listFiles "/path/to/directory")
.
By the way, props to driadan on Reddit for pointing out that Clojure for the Brave and True is a good example of a “fun book” on Clojure, somewhat analagous to what _why’s guide is to Ruby. I hadn’t read it yet, but I just started this past week and it’s definitely a fun read.
Anyway, without further ado, here’s…
Chapter 4
; ex. 1:(def blue-crystal1)(def leaf-tender5); ex. 2:(catch-a-starpipe); ex. 3:(def captive-star(catch-a-starpipe)); ex. 4:(def star-monkey(attachratchetcaptive-monkeycaptive-star)); ex. 5:(def star-monkey(hot-gluedeco-hand-frog(attachratchetcaptive-monkey(catch-a-starpipe)))); ex. 6:(def plastic-cupnil); ex. 7:(if plastic-cup"Plastic cup is on the up 'n' up!"); ex. 8:(if-not plastic-cup"Plastic cup is on the down low."); ex. 9:(if plastic-cup"Yeah, plastic cup is up again!")(if-not plastic-cup"Hardly. It's down."); ex. 10:(if (and plastic-cup(not glass-cup))"We're using plastic 'cause we don't have glass."); ex. 11:(def approaching-guytrue); ex. 12:(if (= approaching-guytrue)"That necklace is classic."); ex. 13:(if (= approaching-guyfalse)"Get in here, you conniving devil."); ex. 14:(= approaching-guytrue); ex. 15:(if (= niltrue)"This will never see realization."); ex. 16:(def at-hoteltrue)(def email(if at-hotel"why@hotelambrose.com""why@drnhowardcham.com")); ex. 17:(def email(let [address"why"](str address"@hotelambrose"".com"))); ex. 18:(cond (nil? at-hotel)"No clue if he's in the hotel."at-hotel"Definitely in."(not at-hotel)"He's out.":else"The system is on the freee-itz."); ex. 19:(print "Type and be diabolical: ")(def idea-backwards(clojure.string/reverse(read-line))); ex. 20: (def idea-backwards(clojure.string/reverse(.toUpperCase(read-line)))); ex. 21:(def code-words{"starmonkeys""Phil and Pete, those prickly chancellors of the New Reich",
"catapult""chucky go-go", "firebomb""Heat-Assisted Living",
"Nigeria""Ny and Jerry's Dry Cleaning (with Donuts)",
"Put the kabosh on""Put the cable box on"}); ex. 22:(require'[clojure.string:asstr])(use'clojure.java.io)(print "Enter your new idea: ")(def idea(read-line))(def safe-idea(reduce (fn [txt[realcode]](str/replacetxtrealcode))ideacode-words)(print "File encoded. Please enter a name for this idea: ")(def idea-name(str/trim(read-line)))(with-open [w(writer(str "idea-"idea-name".txt"))](.writewsafe-idea)); ex. 23:(print "55,000 Starmonkey Salute!"); ex. 24:(require'[clojure.string:asstr)(import 'java.io.File)(doseq [file(->>(.listFiles".")(filter #(re-matches #"idea-.+\.txt"(.getName%))))](let [safe-idea(slurp (.getNamefile))](println(reduce (fn [txt[realcode]](str/replacetxtcodereal))safe-ideacode-words)))); ex. 25/26:(def kitty-toys[{:shape"sock", :fabric"cashmere"}{:shape"mouse", :fabric"calico"}{:shape"eggroll", :fabric"chenille"}])(sort-by :fabrickitty-toys); ex. 27:(doseq [toy(sort-by :shapekitty-toys)](println "Blixy has a"(:shapetoy)"made of"(:fabrictoy))); non-printy version that collects the sentences into a seq:(map #(str "Blixy has a "(:shape%)"made of "(:fabric%))(sort-by :shapekitty-toys)); ex. 28:(def non-eggroll(count (filter #(not= (:shape%)"eggroll")kitty-toys))); ex. 29:(doseq [toy(take-while #(not= (:fabric%)"chenille")kitty-toys)](prn toy))