■Leiningen Tutorial
AntやMaven に怒って触ったことの無い皆さんへ、JVMに新しいものがあります。パニックにならないで下さい。
Leiningen は、あなたに心地よくデザインされています。このチュートリアルでは、あなたのスタートを助け、Leiningen のプロジェクトをビルドして、JVM上の依存関係を管理する方法を示します。
■Create Project
README に従って、Leiningenがインストールされているという前提で進みます。
新しいプロジェクトを作成するのは、簡単です。
$ lein new myproject
Created new project in: myproject
$ cd myproject
$ tree
.
|-- project.clj
|-- README
|-- src
| `-- myproject
| `-- core.clj
`-- test
`-- myproject
`-- core_test.clj
プロジェクトの README, 実装のコードを含んだ src ディレクトリ, test ディレクトリ, そして、Leiningen にプロジェクトを説明する為の project.clj ファイルが作成されます。
(訳者中:※ Leiningen 1.0 で実行したので、Leiningen のページにある出力結果と、ちょっと違うみたいです。 )
src/myproject/core.clj ファイルは、myproject.core 名前空間に対応します。
シングルセグメントの名前空間はClojureでは推奨されていないので、myprojectのみの変わりに、この名前空間を使っていることに注意してください。
同じく、test/myproject/core_test.clj は、myproject.core-test 名前空間に対応しています。
JVMは、ハイフン(-)のあるファイル名のロードに問題があるので、名前空間の名前に含まれるハイフンは、ディスク上のアンダースコアを持ったファイル名に置き換えられることを忘れないようにする必要があります。
■Packaging
今のところかなり役に立たないのですが、プロジェクトが一区切りしたタイミングで、パッケージングすることができます。
$ lein jar
Created ~/src/myproject/myproject-1.0.0-SNAPSHOT.jar
JVM 向けのライブラリは、JVM仕様のメタデータを含んだZipファイルである jar ファイルとしてパッケージ化されます。
それらは大抵、.class ファイル(JVMバイトコード)と、.clj ソースファイルを含みますが、config ファイルのような他のものも含むことができます。
Leiningen は、それらをリモートリポジトリからダウンロードします。
■ project.clj
$ cat project.clj
(defproject myproject "1.0.0-SNAPSHOT"
:description "FIXME: write"
:dependencies [[org.clojure/clojure "1.1.0"]
[org.clojure/clojure-contrib "1.1.0"]])
Clojarsにアップロード(後で解説します)した後に、あなたのプロジェクトが検索結果で見つけられるように :description に短い文を含めてください。
何らかのポイントでREADMEも更新する必要があるでしょう。しかし、今のところは :dependencies の設定のみで飛ばしておきましょう。
Clojure は、ここが標準的な依存関係であることに注意してください。他の言語と違って、どのClojureのバージョンとの切り替えが簡単です。
Clojure Contrib を使っているなら、Clojure バージョンとマッチするかを確認できます。
単純な ピュア Clojure プロジェクトの場合なら、デフォルトの依存関係はClojure と Contrib のみですが、そうでない場合、dependencies のリストを編集する必要があります。
■依存関係
Clojars は、Clojureコミュニティの中央 jar リポジトリで、あなたがプロジェクトに必要なClojureの依存関係を見つけることができる場所です。
どの依存関係も、それを使うために project.clj に同様に記述する必要があります。
Robert Hookeというライブラリの追加する方法を見てみましょう。
以下に示す記述で、
Clojures上の依存関係はLeiningen を使って有効になります。
[robert/hooke "1.0.1"]
・"robert" は group-id と呼びます。
・"hooke" はartifact-id と呼びます。
・"1.0.1" は、必要とする jar のバージョンです。
Clojars上のプロジェクトでは、しばしば group-id と artifact-id は同じです。その場合、Leiningenの依存関係の記述方法からそれを省くことが出来ます。
Javaライブラリでは、しばしばドメイン名が group-id として使われます。
project.cljのdefprojectフォーオムの先頭にあるgroup名、artifact名と、バージョンは同じルールに従います。
Javaライブラリは
Javana 検索で見つけることができます。しかし、Maven XML からLeiningen の書き方に変更する必要があります。
Lucene の基本的な書き方は以下です。
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>3.0.2</version>
</dependency>
こうなります。
[org.apache.lucene/lucene-core "3.0.2"]
時々、バージョンが"-SNAPSHOT" で終わることがあります。これは、オフィシャルなリリースでく開発ビルドであるという意味です。
スナップショットの依存関係に頼るとガッカリさせられるでしょうが、バグFixが必要な場合など時々必要になる場合があります。
まだ、それらを使ってリリースに進むべきではありません。
プロジェクトにスナップショットの依存関係を追加することは、あなたが lein deps を実行したときに、Leiningenが一日に一度依存関係の最新バージョンを検索に出て行く要因になります。
(通常リリースバージョンであれば、ローカルリポジトリにキャッシュされるのに対して)
ですから、スナップショットをたくさん追加すると、処理を遅くする可能性があります。
ローカルリポジトリに関しても説明しましょう。Leiningenがカバーする下でMaven APIを使うので、LeiningenかMavenを使って取得した全ての依存関係は、$HOME/.m2/repository にキャッシュされます。
次のコマンドで現在のプロジェクトをローカルリポジトリにインストールできます。
$ lein install
Wrote pom.xml
[INFO] Installing myproject-1.0.0-SNAPSHOT.jar to ~/.m2/repository/myproject/myproject/1.0.0-SNAPSHOT/myproject-1.0.0-SNAPSHOT.jar
通常は、Leiningenは、依存関係を必要に応じて取得(fetch)します。しかし、新しい依存を追加して、直ちに取得して適用したい場合も次のように実行できます。
$ lein deps
Copying 4 files to ~/src/myproject/lib
Copied :dependencies into ~/src/myproject/lib.
依存関係は、Clojures、中央Maven(Java)リポジトリ、
オフィシャル Clojure ビルドサーバー、その他、project.clj ファイルに追加した全てのリポジトリからダウンロードされます。
sample.project.clj ファイルの :repositories を見てください。
もし、あなたのプロジェクトが異なるバージョンの依存関係でも動作することが確認できているなら、単一のバージョンの代わりに範囲を指定できます。
[org.clojure/clojure "[1.1,1.2]"] ; <= will match 1.1.0 through 1.2.0.
詳細は
Maven's version range specification を見てください。
■開発の依存関係
時々、開発の利便性の為だけに依存関係を取得したい場合があります。それらは厳密にはプロジェクトの機能に必要ないものです。
Leiningen は、それらを:dev-dependencies と呼びます。
これらを project.clj の標準の dependencies と並べて記述して、lein deps を実行するとダウンロードされます。
しかし、それらは他のプロジェクトがあなたのプロジェクトに依存した場合には、持っていきません。
swank-clojure for Emacs support を使うことは、典型的な例でしょう。
それらをランタイムに含めたいとは思わないでしょうが、プロジェクトのハッキングの際には使っていたいでしょう。
■コードを書く
ここは、Leiningenがあなたを助けることができない章です。ここでは、あなたは一人です。
しかし、これは完全ではありません。Leiningen は、あなたのテストを実行することを助けることができます。
$ lein test
Testing myproject.core-test
FAIL in (replace-me) (core_test.clj:6)
No tests have been written.
expected: false
actual: false
Ran 1 tests containing 1 assertions.
1 failures, 0 errors.
もちろん、私たちはまだ何もテストを書いていません。だから、Leiningen が lein new で私たちのために作成したスケルトンが失敗します。
しかし、いったんテスト一式を書いたなら、より役立つようになります。時々、大きなテスト一式がある場合に、ひとつか二つの名前空間だけをテストしたい時があるでしょう。
$ lein test myproject.parser-test
Testing myproject.parser-test
Ran 2 tests containing 10 assertions.
0 failures, 0 errors.
新しいプロセスを開始する必要があるので、lein test はしばしばテストの実行が必須の開発サイクルにとっては、良いソリューションではありません。
この為、より良いエディタ統合(
clojure-test-mode for Emacs を見てください)を調べるか、repl を開いた状態を保って、そこから run-tests を実行するかのどちらかでしょう。
■コンパイル
あなたがラッキーなら、どんなAOT(ahead-of-time)コンパイルなしに逃れられるでしょう。 しかし、AOTコンパイルが必須のJava互換機能があるので、もしあなたがそれらを使う必要があるなら、あなたのproject.clj ファイルに :aot オプションを追加する必要があります。
そのオプションは、AOT-コンパイルしたい名前空間のリストになるはずです。
sample.project.clj にはサンプルの使い方があります。
依存関係と同様に、コンパイルは自動で実行されますが、必要があれば手動で実行することができます。
$ lein compile
Compiling myproject.core
あなたのコードのコンパイルの為に、それは実行されます。これは、副作用のあるコードをトップレベルに置くべきではないことを意味します。
スタートアップで実行されるべきコードがあるなら、以下の"Uberjar"で解説しているように -main 関数に置いてください。
■ What to do with it/Leiningenを使って何をするか
一般的に言えば、典型的なLeiningenプロジェクトには3つの異なるゴール(目的)があります。
・エンドユーザーへ配布可能なアプリケーション
・ライブラリ
・サーバーサイドアプリケーション
エンドユーザーへ配布可能なアプリケーションとして使用する場合には、uberjarを構築することも可能ですし、またshell-wrapperを使用することもできます。
ライブラリとして使う場合には、Clojarsのような repositoryへpublish したいと思うでしょう。
サーバーサイドアプリケーションとして使う場合には、以下の記述の通り、さまざまな
使用方法があります。
■Uberjar
最もシンプルなのは、uberjar を配布することです。これは、単体で実行可能な jar ファイルです。
動かすためには、あなたの project.clj の :main に namespace を指定する必要があります。
今の時点で、私たちの project.clj は、これに似ているはずです。
(defproject myproject "1.0.0-SNAPSHOT"
:description "This project is MINE."
:dependencies [[org.clojure/clojure "1.1.0"]
[org.clojure/clojure-contrib "1.1.0"]
[org.apache.lucene/lucene-core "3.0.2"]
[robert/hooke "1.0.1"]]
:main myproject.core)
名前空間には、スタンドアロンのjarが実行される際に呼ばれる -main 関数が含まれていなければなりません。
この名前空間には、トップにある ns フォーム に :gen-class の記述が書かれていなければなりません。
-main 関数は、コマンドライン引数を通過させます。
ここで、src/myproject/core.clj の簡単なサンプルを試してみましょう。
(ns myproject.core
(:gen-class))
(defn -main [& args]
(println "Welcome to my project! These are your args:" args))
さあ、ここでuberjarを生成する準備が整いました。
$ lein uberjar
Cleaning up
Copying 4 files to /home/phil/src/leiningen/myproject/lib
Created ~/src/myproject/myproject-1.0.0.jar
Including myproject-1.0.0-SNAPSHOT.jar
Including clojure-contrib-1.1.0.jar
Including hooke-1.0.1.jar
Including clojure-1.1.0.jar
Including lucene-core-3.0.2.jar
Created myproject-1.0.0-standalone.jar
uberjar は、全ての依存関係のコンテンツを含む一つの jar ファイルを作ります。
ユーザーは単純なJavaの起動か、幾つかのシステムでは jar ファイルのダブルクリックで、それを実行することが出来ます。
$ java -jar myproject-1.0.0-standalone.jar Hello world.
Welcome to my project! These are your args: (Hello world.)
java コマンドラインツールで、通常の(uber ではない)jar を実行することも出来ますが、クラスパスを自分自身で構成する必要があるので、エンドユーザーにとっては適したソリューションではありません。
■Shell Wrappers
uberjar には、幾つかのデメリットもあります。他のコマンドラインツールに比べて、やや実行しづらい面があります。
どのようにJVMを起動するのかコントロールをすることも出来ません。
この問題を解決する為に、プロジェクトを開始しようとしている jar ファイルが使うことの出来る Shell Script を加えることが出来ます。
Leiningen は、インストール時にこのシェルスクリプトを ~/.lein/bin ディレクトリに置いています。
単純に、project.clj に :shell-wrapper true のみを含めれば、Leiningenは自動的に簡単なshell script wrapper をjarファイルを作成するときに自動生成します。
しかしながら、さらにコントロールが必要な場合に、map を提供することもできます。
:shell-wrapper {:main myproject.core
:bin "bin/myproject"}
通常、shell wrapperは、projectの :main namespaceの -main 関数を実行しますが、このオプションを指定することが uberjarの為のAOTのトリガーとなるので、これを避けるか、uberjarとは異なるシェルラッパーの為の:main を使いたいと望む場合、:main ns に :shell-wrapper マップを含むことができます。
resources ディレクトリにあるファイルを、デフォルトのshell wrapperの代わりのテンプレートとして使うファイルを指すために、:bin キーを指定することができます。
format 関数は、このファイルの内容と、必要なクラスパス、メインの名前空間と共に呼ばれます。そのため、%s を正しい位置に置いてください。
サンプルとして the default wrapper を見てください。
■Publishing
プロジェクトがlibraryで、ほかの人達もプロジェクト内で依存関係として使用できる様にすることを希望するのであれば、共有リポジトリへ入る必要があるでしょう。
自分のリポジトリを保持したり、Maven centralへ入ることも可能ではありますが、一番簡単な方法は、Clojarsで発行することです。
一旦、アカウントを発行してしまえば、発行は簡単です。
$ lein jar && lein pom
$ scp pom.xml myproject-1.0.0.jar clojars@clojars.org:
いったん、うまく実行できれば、依存する他のプロジェクトにおいてもパッケージとして利用できるようになるでしょう。
Clojars にプロジェクトのgroup-idを発行するための許可をもらう必要がありますが、group-idがまだ存在しない場合でもClojarsは自動的にgroup-idを作って許可を与えてくれます。
時々、オリジナルのメンテナーがそれを発行していないか、まだ適用されていないバグ修正が必要な場合などに、あなたが直接メンテナンスしていないライブラリを発行する必要が発生します。
このような場合には、オリジナルの group-idで発行することは避けたいでしょう。なぜならそうすることによって本当のメンテナーが一旦発行したgroup-idを使用することを防げるからです。
その group-idの代わりに "org.clojars.$USERNAME" を使うべきです。
■Server-side Projects
プロジェクトをサーバー側のアプリケーションとしてデプロイする方法はたくさんあります。
シンプルなプログラムは、
lein-release pluginを利用し、さらに
chefや
pallet、あるいは他の機能を使ってデプロイする shell scriptを付属させた tarballとしてまとめることができます。
Web applicationでも
lein-war pluginを使ってデプロイすることができます。
Hadoop projectでさえ構築することができます。
こうした配置(展開)は幾通りもあるので、Leiningen本体にbuilt-inされているタスクよりも、pluginを使用する方がより扱いやすいでしょう。
■That's IT!
図解の方がよいのであれば、
project management上の Full Disclojure screencastを試してみてください。
さあ!次のプロジェクトへ向けてコードを書いてみましょう!
テーマ:
プログラミング
- ジャンル:
コンピュータ