leiningenを使った Clojure 開発

leiningen は clojuremavenです。とても便利。
インストールはこのへんを参考にしてください。
現状はlinux版のみ(?)がまともにうごくみたいです。
以降の記事では、clojure 1.1.0 と emacs による開発を想定しています。記事中に間違いなどありましたら指摘をお願いいします。

プロジェクト作成

hogeapp を作ります。$ で始まる行が入力コマンドです。
プロジェクト名 hogeapp は任意ですが、名前に -(ハイフン)を入れるとコンパイルしたファイルが実行時にエラーになってしまうようです。

$ lein new hogeapp
Created new project in: hogeapp

カレント以下に自動でいろいろ作られます。

$ find ./hogeapp
./hogeapp
./hogeapp/test
./hogeapp/test/hogeapp
./hogeapp/test/hogeapp/core_test.clj
./hogeapp/.gitignore
./hogeapp/README
./hogeapp/src
./hogeapp/src/hogeapp
./hogeapp/src/hogeapp/core.clj
./hogeapp/project.clj

このうちプログラミングに直接かかわるのはこの3つ。

./hogeapp/test/hogeapp/core_test.clj
./hogeapp/src/hogeapp/core.clj
./hogeapp/project.clj

project.clj はプロジェクトの設定ファイル。
src/hogeapp/core.clj は「ほぼ空」。ネームスペース定義だけ入ってます。
test/hogeapp/core_test.clj は core.clj 用のユニットテストファイルです。

project.clj ファイルの内容

プロジェクトの設定ファイルも clojure プログラム(S式)です。プロジェクト管理にXMLとかいう別言語を使わないのが lisp流みたい。
中身は次のようになってます。

(defproject hogeapp "1.0.0-SNAPSHOT"
  :description "FIXME: write"
  :dependencies [[org.clojure/clojure "1.1.0"]
                 [org.clojure/clojure-contrib "1.1.0"]])

defproject でプロジェクトの設定を記述します。
:dependencies の右の[...](ベクタ)の中身は、このプロジェクトで利用するライブラリ(jarファイル)です。ここに書いておくと leiningen が依存関係をチェックしてWEB上リポジトリから依存ファイルを自動ダウンロードしてくれます。
org.clojure/clojureclojureのコアが入ったライブラリで、clojure-contrib は有志が開発をしている clojure の準標準ライブラリ群です。とりあえずこの二つだけでも色々作れます。

jarファイルのダウンロード

プロジェクトに必要な依存ファイルを最初に取得します。コマンドは lein deps。
new 以外の lein コマンドはすべて project.clj ファイルがあるデリレクトリで行ってください。

$ cd hogeapp
$ lein deps
Downloading: org/clojure/clojure/1.1.0/clojure-1.1.0.pom from central
Downloading: org/clojure/clojure-contrib/1.1.0/clojure-contrib-1.1.0.pom from central
Downloading: org/clojure/clojure-contrib/1.1.0/clojure-contrib-1.1.0.pom from clojure
Transferring 1K from clojure
Downloading: org/clojure/clojure/1.1.0/clojure-1.1.0.jar from central
Downloading: org/clojure/clojure-contrib/1.1.0/clojure-contrib-1.1.0.jar from central
Downloading: org/clojure/clojure-contrib/1.1.0/clojure-contrib-1.1.0.jar from clojure
Transferring 3215K from clojure
     [copy] Copying 2 files to {path-to}/hogeapp/lib

これは初回実行時の動作です。leiningen は ~/.m2/ デリレクトリ以下にローカルレポジトリを作成し、そこにWEBから必要なファイルをダウンロードします。一度ローカルにダウンロードしてしまえば以降はこのローカルレポジトリからのコピーだけで済むので、download処理は行われません。
jarファイルはプロジェクトのlibデリレクトリに配置されます。

$ ls lib
clojure-1.1.0.jar  clojure-contrib-1.1.0.jar

clojure-x.x.x.jar は clojure プログラムのコア兼ランタイムです。プロジェクト毎に実行環境を丸ごと作成してしまうのが leiningenの特徴です。これによって全ての依存関係をプロジェクト内だけで解決し、外部ファイルを参照することに起因するトラブルを避けようという思想なのだと思います。

Hello World 作成手順1(エントリポイント指定)

ハローワールドを作ります。まず project.clj の修正から。

(defproject hogeapp "1.0.0-SNAPSHOT"
  :description "FIXME: write"
  :dependencies [[org.clojure/clojure "1.1.0"]
                 [org.clojure/clojure-contrib "1.1.0"]]
  :main hogeapp.core)  ;; 追加

プログラムの起点を :main キーワードによって指定します。指定するのはネームスペースです。hogeapp.core は core.clj ので定義されているネームスペースです。
:main を追加するとき、4行目

                 [org.clojure/clojure-contrib "1.1.0"]])

の末尾の ) を削除するのを忘れないようにしてください。

Hello World 作成手順2(本体コード記述)

core.clj を開いて -main 関数を記述します。

(ns hogeapp.core
    (:gen-class))

(defn -main [& args]
  (println "Hello, World!"))

lein でコンパイルしたプログラムは、project.clj の :main で指定したネームスペース(ns)にある、-main 関数を最初に呼出します。
2行目の :gen-class はこのファイルをコンパイル対象にすることを指定しています。この記述がないファイルはコンパイルされません。

Hello World 作成手順3(コンパイル

jar ファイルに依存ファイルを全てパッキングします。

$ lein compile
Compiling hogeapp.core
$ lein uberjar
All :namespaces already compiled.
Created {path-to}/hogeapp/hogeapp.jar
Including hogeapp.jar
Including clojure-1.1.0.jar
Including clojure-contrib-1.1.0.jar

compile は省略していきなり uberjar でも構いません。必要ならばlein が判断して compile も行われます。
カレンドデリレクトリに hogeapp-standalone.jar があればOK
です。

プログラムの実行

java コマンドに -jar オプションをつけて作成した jar ファイルを実行します。

$ java -jar hogeapp-standalone.jar
Hello, World!

Hello, World! の文字列が表示されれば成功です。
必要な依存ファイルはすべて hogeapp-standalone.jar にパックされているため、このファイルだけあればプログラムは実行できます。
javaがインストールされていれば、linuxでもwindowsでも実行することができます。