PAB@Scalaでお仕事はじめました

求職活動中とありますが、活動報告というよりは、技術の話題を多めでいきます。Scalaが大好きなので特にScalaの話が中心になると思います。

今回は前回まで作っていたスクリプトをまとめて、Dispatchを使ってTumblrのAPIを叩くライブラリを作りたいと思います。

前回までの記事一覧

sbt

前回まではScalasスクリプトでコードを書いていましたが、今回からはsbtを導入していきいたいと思います。

Home · harrah/xsbt Wiki

sbtはAnt、Mave、Ivyなどと同じビルドツールなんですが、以下の特徴があります。

  1. Mavenの規約の方針と、Ivyの依存関係の解決法を引き継いでいる。
  2. 設定ファイルの記述はXMLではなくScalaの内部DSL。
  3. プラグインなどの拡張性も高いが、最小限の設定だけでも動く。

1は、MavenとIvyのいいところ取りと言ったら言い過ぎかもしれませんが、 全体的には簡単に書けるようになったMavenという感じです。

2は、XMLで書かなくていいというのは非常に嬉しいです。 僕はテキストエディタ派なのでタイピングの量がかなり減りますからね。

3は、Mavenでも規約を使うことで設定を減らしていたのですが、sbtはさらに徹底されている感じです。 どのくらい最小限かというと、実は設定ファイルを書く必要すらありません。 空のフォルダにHelloWorld.scalaだけを作ってsbt runと打ってみると動くくらいです。 実際は依存するライブラリを書かなきゃいけなかったりするので、 こういうことはないのですが、本当に必要なことだけを書けばいいという感じです。

より詳しいことはsbtのドキュメントを翻訳してくださった方がいらっしゃるのでそちらを見てください。

始める sbt - ようこそ

ディレクトリ構成

dispatch-tumblr
├── build.sbt
└── src
       ├── main
       │     └── scala
       │            └── Tumblr.scala
       └── test
              └── scala
                     └── TumblrSpec.scala

ディレクトリ構成自体はMavenから引き継いだ規約によるもので、ファイルについての設定はまったく必要ありません。 作るファイルはbuild.sbtTumblr.scalaTumblrSpec.scalaの三つだけです。 build.sbtはsbtの設定ファイル。 Tumblr.scalaはライブラリ本体。 TumblrSpec.scalaはspecsというScalaのテストフレームワークを使ったテストコードです。

僕はよくこういうファイル三つだけの構成のプロジェクト作ります。 あと、プラグイン用のbuild.sbtを付け加えるくらいで。 簡単に作れるのがsbtプロジェクトのいいところです。

設定ファイル build.sbt

各項目簡単に説明します

organization、name、version
このへんはIvyから引き継いでいるものです。作っているところ、ライブラリの名前、バージョンということでしょう。 package名もそうなんですが、githubを使うようになってからgithub名を書けるようになったので悩まなくてよくなりました。 ライブラリを作る場合は書かないといけません。
scalaVersion
使うScalaのバージョンです。本当は2.9.1-1が最新なのですが、対応してないライブラリもあるので2.9.1に。
scalacOptions
文字通り`scalac`に渡すオプション。 `-deprecation`は非推奨のメソッドを使った場合の警告を詳しく表示するオプションです。 なんでデフォルトでオンにしてくれないんですかね。
libraryDependencies
依存するライブラリ。主要部分ですね。今まで使った`dispatch-http-json`と`dispatch-oauth`に加えて、 テスト時に`specs2`を使うことを指定しています。

ライブラリ設計 Tumblr.scala

ライブラリを作るというと、APIをどう設計するのかが悩ましいところ。 でも今回はTwitter用の n8han/dispatch-twitter というライブラリが先にあるので、これを真似していきたいと思います。

方針としては以下の三つです。

  1. REST APIを関数にする。
  2. REST APIに渡すクエリーを組み立てやすくする。
  3. レスポンスのJSONをパーズしやすくする。

1は、最低限やらないといけないことですね。

2は、DispatchのBuilderという仕組みを使います。まんまGoFのビルダーパターンです。

3は、前に紹介したdispatch-jsonを使います。

では、ソースコードを見ていきます。

ざっと説明していきます。

AuthオブジェクトはOAuth、xAuthの処理がまとめられています。単にメソッド化しただけです。

BlogオブジェクトはTumblr APIのBlogメソッドに対応しています。

Tumblr API v2リファレンス和訳(原文:2011/08/07 19:11:23時点) - Walrus, Googling.

「小手調べ編」で使ったのがBlogオブジェクトのavatarメソッド。 「dispatch-json編」で使ったのがinfoメソッド。 それぞれ元のスクリプトからコードが移植されています。

問題はpostメソッドですね。「xAuthで投稿編」で使われたAPIですが、 今回はクエリーの組み立てにBuilderという仕組みが使われています。 productメソッドでHandlerを返す処理を書いておくと、implicit conversionを使ってHandlerに変換されます。 使い方は後でサンプルを見てください。

次に、このBlogオブジェクトはJsというトレイトを継承しています。 「dispatch-json編」で使ったJSONを分解するためのメソッドが使えるようになります。 これでレスポンスの構造に合わせて分解しやすいようなメソッドを用意しておきます。

しかし、BlogオブジェクトがJSONの面倒まで見るというのは、dispatch-twitterの方針に乗っ取ってるんですが、正直微妙な気がしますね。 TwitterとTumblrのAPIの違いからくるものかもしれませんが、リクエストを作るのと、レスポンスの処理は別のものなので、一緒にしないほうがいい気がします。 でも今回は前例に沿ってこの方針でいきます。

今回新しくダッシュボードの情報を取得するメソッドを追加しました。テスト用コードなので、全然埋めてないんですが。 Blogオブジェクトと同じように、UserオブジェクトはBuilderを使ったリクエストを作る処理で、PostオブジェクトはレスポンスのJSONを解析する処理です。

テスト TumblrSpec.scala

specsはScalaのBDDテストフレームワークなんですが、僕は気軽にサンプルコード書く感じで使ってます。 だから全然正しい使い方じゃないと思います。

詳しくはこちらをどうぞ

etorreborre/specs2 @ GitHub

複雑なことはやってないので詳しい説明は省きますが、Afterという仕組みで共通の処理を括り出せます。 大量にテストを書くときには便利です。同じようなものにBeforeBeforeAfterというものがあります。

ライブラリを使ったサンプルコード

sbtで作ったライブラリを他のプロジェクトから使う場合は、sbt publish-localコマンドを使います。 このコマンドを使うとライブラリがIvyのローカルリポジトリにインストールされ、sbtから使えるようになります。 サンプルコードを動かす前にやっておきましょう。

ポイントを説明します。

libraryDependencies += "com.github.hexx" %% "dispatch-tumblr" % "0.0.1"

使うライブラリにbuild.sbtに書いたorganizationnameversionの三つを指定します。 dispatch本体などは芋づる式に依存関係が解決されるので書かなくても大丈夫です。 今回はdispatchも直接使っているので、書いたほうが行儀がいいかもしれません。

val access_token = http(Auth.access_token(consumer, username, password))

xAuthを使ってAccess Tokenを取得する処理です。 Dispatchの謎の呪文wのような処理が隠蔽されてます。

val res = http(User.dashboard(consumer, access_token) posttype "text" limit 5)

これはダッシュボードからテキストタイプのポストを5つ取ってくるという処理です。 ビルダーはこういうふうに使われます。

res map Post.title foreach println

取ってきたダッシュボードのポストのタイトルをプリントする処理です。 Post.titleはレスポンスからタイトルを取り出す関数になります。 これをmapしてやれば、レスポンスからタイトルのリストが取り出され、それをforeachを使って順番にプリントしています

Scalaのメソッドチェーンはこういう形式で書くことも多いです。 Scalaに慣れてない人だと一見何をやってるのかわからないかもしれませんが、 Scalaで.()を省略できるのは1引数のメソッド(要するに二項演算子)だけと覚えておくと、簡単に読めるようになります。

まとめ

以上説明してきたライブラリはgithubに上げてあります。

hexx/dispatch-tumblr

APIが全然足りてないんですが、TumblrのAPIの数は少ないのでそのうち全部埋めておこうと思います。

今回の記事で、ScalaはLL言語ではないけど、sbtによってすごく気楽に開発してる感じが伝わればいいかなと思います。

  1. hirokinfuck-yeah-tumblrからリブログしました
  2. fuck-yeah-tumblrpab-techからリブログしました
  3. pab-techの投稿です