2013年6月15日土曜日

[Play] Play の Welcome Application

Play Framework 2.0.3 で 「play new XXX」で simple Scala application を作成したときに生成される Application.scala は 以下のようになっている。

package controllers

import play.api._
import play.api.mvc._

object Application extends Controller {
  
  def index = Action { 
    Ok(views.html.index("Your new application is ready."))
  }

}

ここで、Application#index メソッドの返り値は、
play.api.mvc.Action[play.api.mvc.AnyContent]
になっている。
何が起きているのか分かりずらいので少し中を見てみることにしよう。



上のコードは例によって apply() が省略されている。
省略せずに書くとこのようになる。

  def index = Action.apply( 
      { 
          Ok(views.html.index("Your new application is ready."))
      }
    );

上で実行されている apply() は、Action オブジェクトのメソッドで以下のように定義されている。

object Action {
  ...
  def apply(block: Request[AnyContent] => Result): Action[AnyContent] = {
    Action(BodyParsers.parse.anyContent)(block)
  }
  ...
  def apply(block: => Result): Action[AnyContent] = {
    this.apply(_ => block)
  }
}

ここで呼ばれるのは2番目の apply()。
ブロックを引数にとって、 Action[AnyContent] を返している。
このため、index() の型が Action[AnyContent] と type parameter が決定されている。

「def index = Action { ... 」 は一見、Action トレイト の匿名サブクラスを作成しているように見えるが、Action.apply が呼ばれているに過ぎない( 実際には Action.apply の実行中に Action トレイトの匿名サブクラスが作成されている)。



引数としてRequest をとる形式の場合は、
object Application extends Controller {
  
  def index = Action { request =>
    Ok(views.html.index("Your new application is ready."))
  }

}

となっているので、Apply.apply の引数は、「引数を一つとる関数」になるので、 先の Apply オブジェクトの1番目の apply が呼び出される。
返り値は同じくAction[AnyContent]。



index() の定義中で使われている Ok() は Controller の親クラスである Status のメンバーで、

  val Ok = new Status(OK)

と定義されている。
Ok(views.html.index("Your new application is ready.")) は、
Ok.apply(....) の省略形で、ここでも apply() が省略されている。
Status クラスの apply は以下のようになっている。

package play.api.mvc
...
class Status {
...
  def apply[C](content: C)(implicit ....




views.html.index は、index.scala.html テンプレートをコンパイルした結果生成されるオブジェクトで、 ここでもapplyが省略されている。
すべてと省略せずに書くとこんな感じになる。
  def index = Action.apply( 
      { 
          Ok.apply(views.html.index.apply(
               "Your new application is ready."))
      }
    );

これでなんとなく構造が理解できた気がする。

0 件のコメント:

コメントを投稿