リクエストのヘッダー値に従ってResult
、あるタイプのオブジェクトの表現を含むを計算できるようにしたいと考えています。この機能は、次の型特性でエンコードできます。A
Accept
trait Repr[-A] {
def render(a: A, request: RequestHeader): Result
}
次に、次のヘルパー トレイトを使用して、コントローラーから任意のリソースをレンダリングできます。
trait ReprSupport {
def repr[A](a: A)(implicit request: RequestHeader, repr: Repr[A]) =
repr.render(a, request)
}
object MyApp extends Controller with ReprSupport {
def index = Action { implicit request =>
repr(Foo("bar"))
}
}
WhereFoo
は、次のように定義された単純なケース クラスです。
case class Foo(bar: String)
上記のコードをコンパイルできるようにするにはRepr[Foo]
、暗黙的なスコープに type の値が必要です。最初の実装は次のように記述できます。
object Foo extends AcceptExtractors {
implicit val fooRepr = new Repr[Foo] {
def render(foo: Foo, request: RequestHeader): Result = request match {
case Accepts.Html() => Ok(views.html.foo(foo)) // Assumes there is a foo.scala.html template taking just one parameter of type Foo
case Accepts.Json() => Ok(Json.obj("bar" -> foo.bar))
case _ => NotAcceptable
}
}
}
Repr
ただし、インスタンスを作成するデータ型ごとに、render
メソッドは同じパターンに従います。
implicit val somethingRepr = new Repr[Something] {
def render(value: Something, request: RequestHeader): Result = request match {
// <Some interesting code> (e.g. case Accepts.Html() => Ok(views.html.something(value)))
case _ => NotAcceptable
}
}
このパターンを抽象化することで、ボイラープレートを削減し、ユーザーが最後の「ケース」ステートメントを忘れないようにする必要があります。たとえば、次のヘルパー メソッドを記述して を構築できますRepr[Something]
。
object Repr {
def apply[A](f: PartialFunction[RequestHeader, A => Result]): Repr[A] = new Repr[A] {
def render(a: A, request: RequestHeader): Result =
if (f.isDefinedAt(request)) f(request)(a)
else NotAcceptable
}
}
したがって、次のように記述して を取得するだけですRepr[Foo]
。
implicit val fooRepr = Repr[Foo] {
case Accepts.Html() => foo => Ok(views.html.foo(foo))
case Accepts.Json() => foo => Ok(Json.obj("bar" -> foo.bar))
}