ネタ記録庫/Scala

概要 †

ScalaにはHTTPインタラクションを簡単に扱うためのDispatchライブラリというのがあります。

このライブラリを使えば非常に小さなコードでHTTPアクセスを実現できますが、implicit definitionやなぞの演算子や記号クラスを使っているために少し慣れが必要になります。

また、単純な通信だけでなく、twitter,google,oauthなどの便利機能も備えています。(2011/07/03時点(v 0.8.3))

セットアップ †

ネタ記録庫/Scala/dispatch/セットアップ?

コード例 †

Httpレスポンスを一行ずつ標準出力に書き出すプログラム(main含む) †

import dispatch.Http
import dispatch.Request
import scala.io.Source

object HelloDispatch {
  def main(args: Array[String]) : Unit = {
    wget("http://proofcafe.org/index.html") {
      source =>
        val lines = source.getLines()
        lines.foreach(println)
    }
  }

  def wget[T](uri : String)(callback : Source => T) : T = {
    val http = new Http()
    val req = new Request(uri)
    http(req >~ callback)
  }
}

ソースコードおよびbuild.sbtはこちら https://github.com/yoshihiro503/hello_dispatch

実行

$ sbt run

Bitly API を利用して短縮URLを生成する関数 †

使用するモジュールは以下の二つです。

  • dispatch-http
  • dispatch-http-json

project/build.scalaはこんな感じ。

...
libraryDependencies ++= Seq (
  ...
 "net.databinder" %% "dispatch-http" % "0.8.5",
 "net.databinder" %% "dispatch-http-json" % "0.8.5"
)
...

shorten関数の型は String => String として定義。つまりurlを文字列で渡すと短縮urlを文字列で返す。以下のように非常に小さいコードで実現できます。しかし慣れないと意味がわからないので以下に解説します。IDとKEYのところにはBitlyアカウントのそれを当てはめましょう。

import dispatch._
import dispatch.json.JsHttp._
 
def shorten(url: String): String = {
  val http = new Http()
  val req = :/("api.bitly.com")/"v3"/("shorten?login=[ID]&apiKey=[KEY]&longUrl="+url+"&format=json")
  http(req ># 'data ? ('url ? str))
}

解説 †

使用している記号とメソッドの対応

:/(...)
dispatcy.:/.apply : String => Request
/
RequestVerbs?#/ : String => Request
>#
JsHandlers?#># : JsHttp?.JsF[T] => Handler[T]
?
JsHttp?.SymOp?#? : Extract[T] => (implicit Option[Obj]) => Child[T, Property[T]]

注意点

  • Requestクラスのオブジェクトは暗黙の変換Request.toRequestVerbs?によってRequestVerbs?型に変換されて、/メソッドが呼ばれている。
  • Requestクラスのオブジェクトは暗黙の変換JsHttp?.requestToJsHandlers?によって JsHandlers?型に変換されてから >#メソッドが呼ばれている。
  • JsHttp?オブジェクトで定義されているimplicit defによって、Request型はJsHandlers?型に変換される
  • ラベル(シングルクォートで始まるリテラル)はscalaのシンボルでSymbol型を持つ
  • Symbol型のオブジェクトは暗黙の変換JsHttp?.sym_add_operatorsによってJsHttp?.SymOp?型に変換される
  • JsHttp?.SymOp?#?メソッドは第二引数引数として暗黙のOption[Obj]を取るが、JsHttp?.ctxが渡されている。
  • strはJsHttp?で定義されている。 JsHttp?.str : Extract[String]
  • ># メソッドの引数として渡しているオブジェクトははChild[String, Property[String]] 型の値だが、暗黙の変換JsHttp?.ext2funによってJsHttp?.JsF[String]へ変換されてから>#に渡されている。そして>#の適用後の型はHandler[String]型となる。
  • Http#apply : Handler[T] => Http.HttpPackage?[T] なので最終的な戻り値の値はHttp.HttpPackage?[String]型つまりString型になる。
  • GAE(google appengine)で使用する場合はnew Http()ではなくnew gae.Http()を使う

以上をふまえて、暗黙の変換やimportなどをいっさい省略せずに使わずに同じコードを書くと以下のようになる。

 import dispatch.Http
 import dispatch.:/
 import dispatch.Request
 import dispatch.json.JsHandlers
 import dispatch.json.JsHttp

 def shorten(url: String): String = {
   val http = new Http()
   val req : Request =
     Request.toRequestVerbs(
       Request.toRequestVerbs((:/.apply("api.bitly.com")))./("v3")
     )./("shorten?login=[ID]&apiKey=[KEY]&longUrl="+url+"&format=json")
   http.apply(
     JsHttp.requestToJsHandlers(req).>#(
       JsHttp.ext2fun(
         JsHttp.sym_add_operators('data).?(
           JsHttp.sym_add_operators('url).?(JsHttp.str)(JsHttp.ctx)
         )(JsHttp.ctx)
       )
     )
   )
 }

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2011-10-10 (月) 06:34:58 (3274d)