Clojure Source Files in Quick Look on MacOSX

Do you like to see the content of Clojure source files in Quick Look? I do.

Unfortunately this is not as straightforward as it should be. Having XCode on my machine didn’t help either. It took me a while to get this working. Maybe this will safe you some time. :-)

Here we go..

Quick Look doesn’t know about clj files. Which is ok because it can’t possibly know every programming language out there. The quick look default behaviour for unknown files is to simply show some not so interesting file information:

I found a plugin called QLColorCode (version 2.0.2) which adds Quick Look support for a large number of programming languages including syntax highlighting.

The plugin has some installation notes and how to handle the XCode issue. Nevertheless it takes a couple of manual steps to get it running for clj source files.

First a few words about the way Quick Look works.

Quick Look uses something called UTI (Uniform Type Identifiers Reference) to identify the type of a file and to select the proper plugin for displaying it.

It is possible to check what Quick Look knows about a clojure files by running qlmanage. The -d 1 prints debug information and the -p option takes the file.

Here is the output:

$ qlmanage -d 1 -p src/clj/clojure/core.clj
Testing Quick Look preview with files:
src/clj/clojure/core.clj
[DEBUG] Registering for public.image
[DEBUG] Preview test for src/clj/clojure/core.clj -- /Users/hauner/Development/clojure.git/. Content type UTI: dyn.ah62d4rv4ge80g5dn
[DEBUG] Previewing /Users/hauner/Development/clojure.git/src/clj/clojure/core.clj. Content type UTI: dyn.ah62d4rv4ge80g5dn. Generator used: None

The Content Type UTI (Lines 5 & 6) is only “garbage”. Which means that Quick Look has no idea how to handle clj files.

Back to the installation.

Disabling XCodes “source-code” plugin

The QLColorCode plugin will register itself for the “public.source-code” UTI.

With XCode installed the “public.source-code” UTI is already registered to a plugin provided by XCode (XCode issue) as can be seen by running qlmanage again.

$ qlmanage -m | grep source-code
public.source-code -> /Developer/Applications/Xcode.app/Contents/Library/QuickLook/SourceCode.qlgenerator (1613)

To get rid of it, I used the Disable XCode QL Plugin.app from QLColorCodeScripts-1.0. It will rename the XCode to SourceCode.qlgenerator.disabled which is enough to remove it. Simply renaming it will work too.

Running qlmanage again, it is gone.

$ qlmanage -m | grep source-code

Before installing the QLColorCode plugin is has to be tweaked a littel bit which I will describe next.

Adjusting the plugin

MacOSX doesn’t offer any convinient way to register new or change file types (in this case the clojure files). To register it with MacOSX I added an xml to qlcolorcode’s Info.plist file, which is in QLColorCode-2.0.2/QLColorCode.qlgenerator/Contents/Info.plist.

I simply copied and adjusted the scala entry.

<dict>
    <key>UTTypeConformsTo</key>
    <array>
        <string>public.source-code</string>
    </array>
    <key>UTTypeDescription</key>
    <string>Clojure Source Code</string>
    <key>UTTypeIdentifier</key>
    <string>org.clojure.clojure-source</string>
    <key>UTTypeTagSpecification</key>
    <dict>
        <key>public.filename-extension</key>
        <array>
            <string>clj</string>
        </array>
    </dict>
</dict>

There is another small tweak required to make the plugin use syntax highlighting. The plugin contains highlighting rules for Clojure but expects .clojure as filename extension instead of .clj. To fix it I simply copied clojure.lang to clj.lang in the plugin folder QLColorCode-2.0.2/QLColorCode.qlgenerator/Contents/Resources/highlight/share/highlight/.

Nearly done, only one step left :-)

Installing the QLColorCode plugin

After tweaking the plugin I copied the plugin to ~/Library/QuickLook (/Library/QuickLook would be fine too).

Installation is described in the plugins ReadMe.txt along with some instructions for customizing font, font size and other options.

I had to run

$ qlmanage -r
qlmanage: resetting quicklookd
[/sourcecode]

before Quick Look recognized the new plugin and qlmanage -m reported QLColorCode
as plugin for “source-code”.

$ qlmanage -m | grep source-code
public.source-code -> /Users/hauner/Library/QuickLook/QLColorCode.qlgenerator (2.0.1)

And then finally the reward… :-)


Advertisements

The FizzBuzz Kata in Clojure

My first Clojure code was the Bowling Kata I wrote about in my last post. Today I did the FizzBuzz Kata and the stage 2 requirements. This was a lot simpler than the Bowling Kata.

There is not much to say about it, here is my test code:

(ns fizzbuzztest
 (:use fizzbuzz clojure.test))

(deftest nonefizzbuzz-numbers-return-itself
 (is (= (fizzbuzz '(1 2 4 7)) '(1 2 4 7))))

(deftest multiple-of-three-and-not-five-return-fizz
 (is (= (fizzbuzz '(3 6 9 12 18 21 24 27)) (take 8 (repeat "fizz")) )))

(deftest multiple-of-five-and-not-three-return-buzz
 (is (= (fizzbuzz '(5 10 20 25 40 50 55 65)) (take 8 (repeat "buzz")) )))

(deftest multiple-of-three-and-five-return-fizzbuzz
 (is (= (fizzbuzz '(15 30 45 60 75 90 105 120)) (take 8 (repeat "fizzbuzz")) )))

(deftest three-in-number-returns-fizz
 (is (= (fizzbuzz '(3 13 23 31 103)) (repeat 5 "fizz"))))

(deftest five-in-number-returns-buzz
 (is (= (fizzbuzz '(5 52 58 151 502)) (repeat 5 "buzz"))))

(run-tests)

and here is the implementation:

(ns fizzbuzz)

(defn- numeric-fizz? [n]
 (= (rem n 3) 0))

(defn- string-fizz? [n]
 (some #(= % \3) (str n)))

(defn- fizz? [n]
 (or (numeric-fizz? n) (string-fizz? n)))

(defn- numeric-buzz? [n]
 (= (rem n 5) 0))

(defn- string-buzz? [n]
 (some #(= % \5) (str n)))

(defn- buzz? [n]
 (or (numeric-buzz? n) (string-buzz? n)))

(defn- fizzbuzz? [n]
 (and (fizz? n) (buzz? n)))

(defn- replace-fizz-buzz [n]
 (cond
 (fizzbuzz? n) "fizzbuzz"
 (fizz? n) "fizz"
 (buzz? n) "buzz"
 (number? n) n))

(defn fizzbuzz [numbers]

 (map replace-fizz-buzz numbers))

I like the function that checks if a number contains a ‘3’ character. Although it looks weird it is not so hard to read after  getting a little used to Clojure code.

(defn- string-fizz? [n]
 (some #(= % \3) (str n)))

This functions gets a number n as parameter, which is converted to a string with (str n). The some calls the anonymous function #(= % \3) on each element (i.e. character) of n as string. If the anonymous function returns true, some return true as well. The anonymous function simply checks if its parameter (the %) is the character 3.

There is one issue with the cond in replace-fizz-buzz:the last condition (number? n) is just a dummy condition. Actually I don’t want it. If none of the other conditions match, it should just return the n. But that is not possible with cond. I’m looking for a better solution…

I also created my first Leiningen build script to run the tests. Leiningen is a build tool for Clojure. Here is the build script (named project.clj and placed in the project root folder):


(defproject fizzbuzz "1.0.0"
 :description "A cloure implmementation of the FizzBuzz kata."
 :dependencies [[org.clojure/clojure "1.1.0"]])

Quite simple ;-)

Running the following command:

$ lein test fizzbuzztest

prints:

 [null] Testing fizzbuzztest
 [null] Ran 6 tests containing 6 assertions.
 [null] 0 failures, 0 errors.
 [null] --------------------
 [null] Total:
 [null] Ran 6 tests containing 6 assertions.
 [null] 0 failures, 0 errors.

Works, but I have no idea, why it prints the [null] stuff.

The Bowling Kata in Clojure

I have bee reading Programming Clojure lately to learn about functional programming. Interest in functional programming is increasing so it might be a good idea to get familiar with it. :-)

Clojure is a Lisp like programming language that runs on the Java VM and also on the .NET CLR.

I didn’t have much knowledge about functional programming before and the book still left me with a lot of questions. After practicing OOP for most of my programming life, Clojure is very strange at first.

To get a little bit practice at it I spend a couple of hours (reading documentation, playing with the REPL) tdd’ing the Bowling Kata in Clojure.

There are already a few versions of the Clojure Bowling Kata on the net: Uncle Bob, Micah, Halloway. There is a lot of info in the comments of the first article and the third link points to a version from the author of the Clojure book mentioned above.

Here is mine :-)

I didn’t read the links in detail before I started because the idea was to do this on my own. So I guess there is still some potential for improvements.

If you are looking for an environment, you may try Intellij IDEA’s Community Edition and their Clojure plugin La-Clojure. That’s what I have used.

Unfortunately WordPress’s [sourcode] tag doesn’t seem to know Clojure yet. So no highlighting.

The tests:

(ns test
  (:use
    bowling
    clojure.contrib.test-is))

(defn- zero
  ([] (repeat 2 0))
  ([n] (repeat (* n 2) 0)))

(defn- spare
  ([] (repeat 2 5))
  ([n] (repeat (* n 2) 5)))

(deftest the-score-of-a-gutter-game-is-zero
  (is (= 0 (score (zero 10)))))

(deftest the-score-of-one-rolls-only-is-twenty
  (is (= 20 (score (repeat 20 1)))))

(deftest the-score-of-a-spare-includes-the-next-roll
  (is (= 16 (score (concat (spare) '(3 0)  (zero 8)))))
  (is (= 16 (score (concat (zero)   (spare) '(3 0) (zero 7)))))
  (is (= 16 (score (concat (zero 2) (spare) '(3 0) (zero 6)))))
  )

(deftest two-spares-in-a-row
  (is (= 31 (score (concat (spare 2) '(3 0) (zero 7))))))

(deftest three-spares-in-a-row
  (is (= 46 (score (concat (spare 3) '(3 0) (zero 6))))))

(deftest the-score-of-a-strike-includes-the-next-two-rolls
  (is (= 24 (score (concat '(10) '(3 4) (zero 8))))))

(deftest spare-in-last-frame
  (is (= 16 (score (concat (zero 9) (spare) '(3))))))

(deftest strike-in-last-frame
  (is (= 17 (score (concat (zero 9) '(10) '(3 4))))))

(deftest the-score-of-a-perfect-game-is-300
  (is (= 300 (score (repeat 12 10)))))

(run-tests)

and the code:

(ns bowling)

(defn- sum [rolls]
  (reduce + rolls))

(defn- spare? [rolls]
  (= 10 (sum (take 2 rolls))))

(defn- strike? [rolls]
  (= 10 (first rolls)))

(defn- more? [rolls]
  (seq rolls))

(defn- score-strike [rolls]
  (sum (take 3 rolls)))

(defn- score-spare [rolls]
  (sum (take 3 rolls)))

(defn- score-frame [rolls]
  (sum (take 2 rolls)))

(def score)

(defn- score-after-strike [rolls]
  (score
    (if (= 3 (count rolls))
      (drop 3 rolls)
      (drop 1 rolls)
    )))

(defn- score-after-frame [rolls]
  (score (drop 2 rolls)))

(defn score
  "calculate the bowling score of a [rolls] sequence"
  [rolls]
  (cond
    (empty? rolls)     0
    (strike? rolls)    (+ (score-strike rolls) (score-after-strike rolls))
    (spare?  rolls)    (+ (score-spare rolls)  (score-after-frame rolls))
    (more?   rolls)    (+ (score-frame rolls)  (score-after-frame rolls))
    )
  )

A few notes:

The last test I added (the-score-of-a-perfect-game-is-300) made me insert that strange if to (score-after-strike). This didn’t happen on the Java version. Because there is no loop that counts the frames in the Clojure version, one has to detect the last frame some other way. Without it, the last two strikes would not only be counted as the bonus for the 10th strike but also as an 11th and 12th frame.

I think my solution is not too bad for my first piece of Clojure code.

What I dislike is that every call in the (score) function has the rolls sequence as parameter. That is a lot of duplication noise. I see an object here ;-)

In the test I’m not sure if the (spare) and (zero) helper methods improve the readability. Maybe simply writing out every single roll would be easier to understand.

What do you think of my Clojure Bowling Kata? Is there anything that’s totally not the Clojure way? ;)

Update (10.2.2010)

After some feedback on the clojure group, I fixed the forward declaration of the (score) function. It should use (declare) and instead of (def) and I modified the score function to use (condp) with (apply). That is a small trick to avoid the rolls parameter on the predicate functions (empty? etc.). From a readability point, I think I still prefer the simple (cond) from my first version.

(ns bowling)

(defn- sum [rolls]
  (reduce + rolls))

(defn- spare? [rolls]
  (= 10 (sum (take 2 rolls))))

(defn- strike? [rolls]
  (= 10 (first rolls)))

(defn- more? [rolls]
  (seq rolls))

(defn- score-strike [rolls]
  (sum (take 3 rolls)))

(defn- score-spare [rolls]
  (sum (take 3 rolls)))

(defn- score-frame [rolls]
  (sum (take 2 rolls)))

(declare score)

(defn- score-after-strike [rolls]
  (score
    (if (= 3 (count rolls))
      (drop 3 rolls)
      (drop 1 rolls)
    )))

(defn- score-after-frame [rolls]
  (score (drop 2 rolls)))

(defn score
  "calculate the bowling score of a [rolls] sequence"
  [rolls]
  (condp apply [rolls]
    empty?   0
    strike?  (+ (score-strike rolls) (score-after-strike rolls))
    spare?   (+ (score-spare rolls)  (score-after-frame rolls))
    more?    (+ (score-frame rolls)  (score-after-frame rolls))
    )
  )