Clojure
Leiningen
ClojureDay 3

Leiningenでプロジェクト専用タスクを作る

More than 3 years have passed since last update.

 Leiningenの3分間コネタTipsを書きます。

 以下の例はLeiningen 2.4.2で確認しました。執筆時点でheroku-buildpack-clojureがLeiningen 2系で指定しているバージョンと同じはずです。

やりたいこと

 たとえばWebアプリでは、実行前に静的ファイルを生成したいことがあります。LESSからCSSを生成したり、CSSやJavaScriptを縮小(minify)したりする場合などです。一般的なタスクについては、Leiningenのプラグインなどが揃ってきています。

 しかし、処理がプロジェクト特有で適切なプラグインがない場合には、プロジェクト内に専用のタスクを作ることになります。

 私の場合は、プロジェクト内で定義された文字列のリストから、そのいずれかにマッチする正規表現を生成してJavaScriptファイルに埋め込む処理を、タスク化することにしました。先頭からトライ木状にマッチする効率のよい正規表現の生成には、Maven Centralに登録されているregexp-trieというJavaライブラリを選びました。

 以上のやりたいことを、箇条書きでまとめます。

  • プロジェクト専用のタスクを作る
  • タスクからMaven CentralのJavaライブラリを使う

タスクを作る

 プロジェクト専用のタスクを作る方法は、Leiningenオフィシャルのプラグイン作成ドキュメント「Leiningen Plugins」に「Project-specific Tasks」として書かれています。

 まずはこれにのっとって、Hello World代わりに「yo」というタスクを作ってみます。

 プロジェクトのルートディレクトリにいるものとします。まず、tasks/leiningenディレクトリを作ります。

$ mkdir -p tasks/leiningen

 yoというタスクなら、tasks/leiningenのyo.cljにleiningen.yoという名前空間でyo関数を書きます。

tasks/leiningen/yo.clj
(ns leiningen.yo)

(defn yo [project]        ; projectにはproject.cljでの定義が渡ってくる
  (println "Yo") )        ; とりあえず文字列を表示するだけ

 プロジェクトのルートディレクトリの.lein-classpathに、tasksディレクトリを追加します。.lein-classpathファイルがないのであれば、「tasks」とだけ書いておきます。

$ echo tasks > .lein-classpath

 もし.lein-classpathがすでにあるのであれば、クラスパス形式で追記します。

 これだけでタスクが作られました。実行してみます。

$ lein yo
Yo

 簡単ですね。

 ちなみに、leiningenのデフォルトテンプレートで作られる.gitignoreには、初期状態で/.lein-*という行が含まれます。gitを使う人はご注意を。

Maven Centralのライブラリを使う

 さて、project.cljの:depenciesにすでに[me.geso/regexp-trie "0.1.10"]を登録してプロジェクト本体で使っているものとします。このregexp-trieをfooというタスクのtasks/leiningen/foo.cljからimportしてみます。

tasks/leiningen/foo.clj
(ns leiningen.foo
  (:import [me.geso.regexp_trie RegexpTrie]) )

;; 以下略

 しかし、実行したらClassNotFoundExceptionになってしまいました。

$ lein foo
clojure.lang.Compiler$CompilerException: java.lang.ClassNotFoundException: me.geso.regexp_trie.RegexpTrie, compiling:(leiningen/foo.clj:1:1)

(以下略)

 Maven Centralのライブラリは参照できないようです。

 そこで、Leiningenが使っているpomegranateのadd-dependenciesを呼んでregexp-trieをクラスパスに追加してから、importしてみます。

tasks/leiningen/foo.clj
(ns leiningen.foo
  (:use [cemerick.pomegranate :only [add-dependencies]]) )  ; まずpomegranateをuse

(add-dependencies                                           ; ライブラリを追加
  :coordinates '[[me.geso/regexp-trie "0.1.10"]]            ; project.cljと似た感じで
  :repositories cemerick.pomegranate.aether/maven-central ) ; maven-centralはpomegranate内で定義されている

(import [me.geso.regexp_trie RegexpTrie])                   ; ここでregexp_trieをimport

;; 以下略

 実行してみます。

$ lein foo

 エラーなく実行できました。よかった。

別解

 Leiningenプラグインのlein-execを使えば、lein exec hoge.cljのようにClojureのスクリプトを実行できます。ただし、今回はタスクとしてまとめたかったので、lein-execは採用しませんでした。

 なお、上で書いたpomegranateでMaven Centralライブラリを呼べるようにする方法は、lein-execを参考にしました。