Clojure Advent Calendar 2013の24日目の記事です。
先がけて、Light Tableの簡単な使い方について書きましたので、未読の方はまずそちらをご覧ください。
Clojureが、従来のLisp言語とは異なり、使えるライブラリが豊富にあるということで、その高い実用性が評価されています。
このあたりはおいしいClojure入門 に、いろんな事例が載っているのでそちらを読んでいただけるとよいかと思います。
この豊富なライブラリたちを使ってアプリケーションを作るのは、Clojureではふつうleiningenを使います。JavaでいうMaven、Rubyでいうbundle + rake 相当のものです。
leiningenはコマンドラインから使っても非常に分かりやすいツールなのですが、Light Tableはleiningenの機能を一部内包していて、依存関係の解決やREPLの機能をleiningenコマンドを意識すること無く利用することができます。Light Tableを使ってleiningenプロジェクトを作ってみましょう。
まず、メニューから「View」->「Workspace」を選択し、ワークスペースパネルを開きます。その上で右クリックしコンテキストメニューを開き、Add folderを選択します。適当な場所に、exampleというフォルダを作ります。
leiningenでは、プロジェクト直下にプロジェクトの構成・ビルド手順などを記述したファイルとしてproject.cljを作ります。Mavenのpom.xmlにあたるものですね。ここではexampleという名前でプロジェクトを作ってみましょう。ミニマムなproject.cljは名前とバージョンがあればよいです。
プロジェクトができたら、Light Tableから接続すると、依存関係の解決やREPLの機能が使えるようになります。メニューから「View」 -> 「Connections」を選択すると、コネクションパネルが右側に現れますので、一番上の「Add Connection」をクリックします。
そうすると、Light Tableから接続可能なアプリケーションの一覧が表示されますので、Clojureを選択します。
ファイル選択ダイアログが開くので接続するleiningenプロジェクトのproject.cljを選択します。ここでは先ほど作ったexampleのproject.cljを指定します。
接続成功したらコネクションパネルには、exampleプロジェクトが表示されるようになります。この状態でプロジェクトの中でInstareplが動作するようになります。
試しに、exampleプロジェクトの下に、src/example/core.cljというファイルを作ってみます。「src」の下にClojureのソースファイルを配置するのが、leiningenプロエジェクトのデフォルトです。「core.clj」というファイル名も慣例としてmainを含むものに付けられます。
このcore.cljでInstareplが使えるようにしてみましょう。「View」 -> 「Commands」でコマンドパネルを開いて、Instareplと入力し、「Instarepl: Make curent editor an instarepl」を選択します。現在開いてるタブでInstareplを有効にする、という意味です。これで前回の記事と同様Instareplの機能が有効になります。
せっかくなので、実用的なプログラムを書いてみましょう。SIerではHello World!の次のステップとしておなじみのExcelパースプログラムです。
project.cljに依存ライブラリを追加します。Excelを読み書きするための、Apache POIはJavaのプロジェクトとしてMavenセントラルリポジトリに登録されていますが、leiningenからは他のClojureライブラリと同じように、依存関係を記述できます。
Mavenのdependenciesとは、次のような対応関係にあります。
[groupId/artifactId "version"]
こうしてleiningenのdependenciesに依存ライブラリを書いておけば、MavenリポジトリまたはClojureライブラリのリポジトリ から自動的に取得してくれるようになります。
これでPOIを使えるようになったわけですが、現バージョンのLight Tableでは、残念ながらproject.cljを更新しただけでは依存関係の読み直しをしてくれないようです。一度コネクションを切断してから再接続してください。
さて、ではExcelファイルを読んでみます。Excelファイルが山のように登録されているサイトのデータを使います。
ClojureでJavaのクラスを利用する場合には、importを使います。ネームスペースにimportする場合は、次のように書きます。Javaと同じ感じですね。
(ns example.core
:import [org.apache.poi.ss.usermodel WorkbookFactory])
POIのWorkbookFactoryを用いてブックを開いて、シートのデータを読みます。
(defn read-excel [input-file]
(with-open [in (io/input-stream input-file)]
(let [wb (WorkbookFactory/create in)
sheet (. wb getSheetAt 0)]
(->> sheet
.rowIterator ;; 行のイテレータを取得
iterator-seq ;; JavaのイテレータをClojureの遅延シーケンスに変換
(drop 1) ;; 1行めを読み飛ばす
(map #(.getCell % 4)))))) ;; E列を抜き出す
ExcelパースはClojureのスレッディングマクロと非常に相性がよく、このように簡単に流れるように書けてしまいます。
さてこれをInstaparseで実行すると…
このようにリアルタイムでセルの中身が表示されます。".getCell % 4"の4のところを変えてみると、その瞬間に別の列の中身が表示されます。
InstareplとPOIの組み合わせは、Excelパースするお仕事の方にはたまらないものですね!