Clojure

Intro

I don't know anything about this Lisp dialect yet, but I intend to find out more about it…

Here's an excellent guide on how to get Clojure working with Vim. Although originally written for Clojure 1.2, it's still valid for 1.4. This guide pretty much covers what's also recorded here in this wiki.

If you've got Clojure and Vim working together seamlessly, here's a nice tutorial to get you started with the actual language: Clojure Tutorial For the Non-Lisp Programmer.

After that, take a look at this tutorial: Casting SPELs with Clojure. It's got cartoons in it!

(Yes, it says Lisp, but the tutorial was adapted for Clojure)

Install on Ubuntu

These links pretty much point you in the right direction:

  • Install with Git - Cutting edge, but not necessarily stable.
  • Clojure and Emacs on Ubuntu - I don't intend to learn Emacs (yet), just for the sake of Clojure, but this site gives you some installation hints as well.

And yes, there is an apt-get (well dpkg) package for Clojure, but it's hopelessly out of date. Just use git (to get the latest, non-stable version) or download the official zip (containing the stable release) on clojure.org and compile it yourself using the guidance from the sites mentioned above.

One more thing: clojure-contrib for the latest version (1.3) is no longer Riddell's github site. It's now here: github.com/clojure/clojure-contrib.

Latest Working Install (1.4)

As per clojure.org/getting_started, download the zip here. Unzip, e.g. in ~/local. Then, inside the unzipped directory:

java -cp clojure-1.4.0.jar clojure.main

- to test the repl.

Configuration

The configuration is pretty simple. Inside ~/local, make a symlink called clojure to your unzipped directory. Then just stick this into your .bashrc file:

export CLOJURE_EXT=~/local/clojure

Here's an additional launcher script, which will either invoke the repl or execute a clojure program. Just stick this file in your ~/.scripts directory (or wherever you keep your shell scripts).

# FILE: clj

set -o errexit
#set -o nounset
#set -o xtrace

if [ -n "${CLOJURE_EXT:-}" ]; then
    OLD="$IFS"
    IFS=":"
    EXT="$(find -H $CLOJURE_EXT -mindepth 1 -maxdepth 1 -print0 | tr \\0 \:)"
    IFS="$OLD"
    if [ -n "${CLASSPATH:-}" ]; then
        export CLASSPATH="$EXT$CLASSPATH"
    else
        export CLASSPATH="${EXT%:}"
    fi
fi
JAVA=${CLOJURE_JAVA:-java}
OPTS=${CLOJURE_OPTS:-}
MAIN=${CLOJURE_MAIN:-clojure.main}

if [ $# -eq 0 ]; then 
    exec rlwrap --remember -c -b "$breakchars" \
        $JAVA $OPTS $MAIN
else
    exec $JAVA $OPTS $MAIN "$@"
fi

So, if no commandline arguments are used when invoking the clj script, the rlwrap utility is used (install rlwrap through Synaptic Package Manager). If, on the other hand, you're executing clojure code from a file, the rlwrap utility is skipped. Example:

clj test.clj // executes test.clj program
clj // invokes repl

A final note: the clj bash script does not mention any specify jar file. Don't worry about it. Apparently, java looks into each jar file inside the CLOJURE_EXT directory/ies to collect class names, so it will know in which file to find the clojure.main class.

Warning

Some Clojure sites no longer contain accurate information about clojure-contrib - as of version 1.3. The monolithic clojure-contrib.jar file is no longer in vogue.

Instead, you should copy any additional module you want to use. Do this by copying the target/*.jar file inside the module directory to your ~./clojure directory (or use Leiningen, see below).

Apparently, CLOJURE_EXT defines your classpath (a Java concept) for your clojure programs.

Additional Features

Here's a nice install guide, How to setup Clojure from scratch, which also specifies how to add autocompletion to the repl.

Leiningen

Leiningen is a dependency management tool, kinda like Ruby's Bundler, and a project file structure generator. Install it from leiningen.org:

  1. Put the lein script inside your ~/bin directory
  2. Invoke lein self-install

And you're done!

Now you can create a new project:

cd ~/clojure
lein new musicprogram

This will create a directory structure for your new project, prepopulated with a few files Leiningen uses to keep track of dependencies. Just take a look in ~/clojure/musicprogram/project.clj, which will look something like this:

(defproject musicprogram "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.4.0"]])

Nailgun

You can use Nailgun to start a Clojure runtime environment. From the official site:

“Nailgun is a client, protocol, and server for running Java programs from the command line without incurring the JVM startup overhead. Programs run in the server (which is implemented in Java), and are triggered by the client (written in C), which handles all I/O.”

If you're using Vim: Nailgun also comes bundled with the excellent vimclojure plugin. Here's how to install the bundled version of Nailgun:

make -C ~/.vim/lib/vimclojure-nailgun-client

Then tell Leiningen about Nailgun. Add this to the plugins vector of your :user profile located in ~/.lein/profiles.clj (just create the profiles.clj file if it doesn't exist yet):

{:user {:plugins [[lein-tarsier "0.9.1"]]}}

Now reinstall your project:

onno@asus-ubuntu:~/clojure$ lein new musicprogram

And finally use Leiningen to start the Nailgun server through the vimclojure plugin:

onno@asus-ubuntu:~/clojure/musicprogram$ lein vimclojure
Starting VimClojure server on 127.0.0.1, port 2113
Happy hacking!

Vimclojure plugin

The vimclojure plugin provides syntax highlighting, a repl in a Vim buffer, and omnicompletion. I installed this plugin using these sources as documentation:

Convenient shortcuts:

  • ,sr - show repl in a new vim buffer
  • ,ef - evaluate current file
  • ,sw - show source for word under cursor
  • ,lw - list documentation for word under cursor
  • ,eb - evaluate visual block

Noir web framework

Just use Leiningen to create a new Noir project, and Noir will install itself!

lein new noir musicprogram

Importing libraries

We will use Leiningen's project file to add libraries. First, you need to know how to reference the library in the project file. To do this, go to maven.org, “The Central Repository” for clojure libraries. Here, look up the exact name and latest version of your library. E.g. to look up a math library, search for math. Suppose we want to include math.numeric-tower, version 0.0.1, we would have to add [org.clojure/math.numeric-tower “0.0.1”] to the Leiningen's project file. Please note that maven.org may also mention a 'groupid'. Apparently, you have to add this in front of the actual library, followed by a slash forward.

E.g.:

(defproject musicprogram "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.4.0"]
                 [overtone "0.5.0"]
                 [clj-time "0.4.2"]
                 [org.clojure/math.numeric-tower "0.0.1"])

Here, I've added the math library, overtone, and clj-time library, which is a wrapper around Java date/time classes (the Joda date time API).

Now, go to your project's root directory and do lein install. Leiningen will install the specified library for you.

In your REPL, issue the command use:

user=>(use 'clj-time.core)
nil

A simple test:

user=> (now)
#<DateTime 2012-05-08T20:01:25.707Z>

And for the math library you'd have to include clojure.:

user=> (use 'clojure.math.numeric-tower)
nil
user=>(floor 1.3)
1.0

Routes

Routes are matches for urls. If you type in something like http://localhost:8080/welcome, Noir will try to find a matching /welcome route.

You can define routes using the defpage macro. As far as I can tell, it doesn't really matter where defpage is called, as long as it's in a file inside the views directory. Here's an example where we've replaced the default welcome page of Noir:

(ns lalea.views.index
  (:require [lalea.views.common :as common]
            [noir.response :as resp])
  (:use [noir.core :only [defpage]]))

(defpage "/"
  []
  (if (not-logged-in?)
    (resp/redirect "/login")
    (common/layout
      [:p "Welcome to lalea from index.clj"])))

Whenever you type in http://localhost:8080, Noir will match this url with the ”/” route and display the Welcome message - if you're logged in.

In this example, the login logic is contained inside the defpage call. This is not very efficient, because we don't want to repeat this code for each section of the website where logging in is required.

Noir offers a pre-route macro for applying filters. Every time you hit a url without having met certain pre-conditions, such as being logged in, the pre-route will be applied. Pre-routes are applied before any other matches defined with defpage.

Here's an example of a website where everything is shut tight, except for the login page itself:

(ns lalea.views.index
  (:require [lalea.views.common :as common]
            [noir.response :as resp])
  (:use [noir.core :only [defpage pre-route]]))

(pre-route [:any [":anything" :anything #"^(?!\/login$).*"]] {} (when-not (is-logged-in?) (resp/redirect "/login")))


(defpage "/"
  []
  (common/layout
    [:p "Welcome to lalea from index.clj"]))

This is a complicated example, because we're using a regex to define the route. A simpler example could be:

(pre-route "/admin/*" {} (when-not (is-logged-in?)  (resp/redirect "/login")))

This example would apply the filter only to sections of the website that are located in the /admin section.

Now, to use a regex, you need to be aware of how pre-routes work. This is described in more detail on this aptly named website: Routes In Detail.

Our particular regex is explained here on Stackoverflow.

Accessing a (MySQL) Database

JDBC driver

You can use the Java Database Connection driver to access your database. Here's an example consisting of a Leiningen project.clj file and some actual code.

;;;; File: project.clj
(defproject db-app "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.4.0"]
                 [org.clojure/java.jdbc "0.2.3"]
                 [mysql/mysql-connector-java "5.1.6"]])

And the actual retrieval code:

(ns db-app.core
  (:require [clojure.java.jdbc :as sql]))

(def db {:classname "com.mysql.jdbc.Driver"
                  :subprotocol "mysql"
                  :subname "//localhost:3306/your-db-name"
                  :user "your-db-user"
                  :password "your-db-password"})

(defn list-users []
  (sql/with-connection db
    (sql/with-query-results rows
      ["select username, email from mdl_user"]
      (println rows))))

To test this, just call (list-users) in your repl.

Korma

“Korma is a domain specific language for Clojure” which you can use to access your database. Korma's website explains everything in more detail.

Here's a comprehensive example, consisting of a Leiningen project file and an actual script.

Put the following code in your project.clj file, and execute lein install on the command line (within your project directory).

;;;; File: project.clj
(defproject korma-test "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.4.0"]
                 [org.clojure/java.jdbc "0.2.3"]
                 [mysql/mysql-connector-java "5.1.6"]
                 [korma "0.3.0-beta11"]])

And here's a sample script to actually access a database and retrieve some rows from a table:

(ns korma-test.core
  (:use [korma.core]
        [korma.db]))

(defdb db
   (mysql {:host "localhost"
           :port "3306"
           :delimiters "`"
           :db "your-db-name"
           :user "your-db-user"
           :password "your-db-password" }))

(defentity users
  (table :users)
  (database db))

(select users
        (fields :username, :email)
        (where {:lastname "Jones"}))

Nice to know: “you can get a string of the SQL instead of executing by using the sql-only mode”:

(sql-only
  (select users))

Consolidating Configuration Settings In One Location

If you're using a web app framework like Noir, the business logic for each entity of your domain will be stored in a separate file, under a directory models. Obviously, we don't want to store the database settings in each of those files as well.

Here's my solution for Noir:

  • Put the database configuration settings in a file called config.clj, under my-app/src/my-app.
  • Call load-file in each model file (this seems the only way to circumvent certain limitations on indirectly including namespaces, see discussion below).

Example:

(use 'korma.core)
(require '[korma.db :as db])

(defdb db
    (mysql {:host "localhost"
            :port "3306"
            :delimiters "`"
            :db "my-app-db-name"
            :user "db-user"
            :password "db-password" }))
(ns lalea.models.user)
(load-file "./src/my-app/config.clj")


(defentity user
    (table :users))

Please note that using plain load resulted in vague compilation errors for me.

Discussion

I could not get the required korma namespace 'included' (so to speak) indirectly. In other words: it seems impossible to include a namespace A which includes namespace B and then have the functions of B available in the namespace that does the including of A…

But I cannot imagine that Clojure would make you include all of the indirectly included libraries again. Obviously, I have to dive further into this.

Looks as though this discussion might be relevant: How do you organize function names when building clojure libraries for public consumption?

Maybe this is the beginning of a solution: Splitting a Clojure namespace over multiple files.

But then again, this article seems to suggest that it is (yet) impossible to do what we want: Managing namespaces. Here's a quote from the (2010) article:

“I’d like to be able to set up a namespace to my taste and then be able to use it as a basis for deriving other namespaces. With that possibility, I would define a master namespace once per project, being careful to always use the :only option in :refer-clojure and :use. All other namespaces in my project would then be based on this master namespace and only add or remove symbols for their specific local needs.”

That's exactly what I need, but what's apparently not part of the Clojure core… A huge disappointment!


Personal Tools