コミュニティが寄付した拡張
scala-0.6 は、このバージョンでテストされています: Tested with 1.1r902
play 1.1 リリースには、プログラミング言語 Scala のサポートが含まれる予定です。play フレームワークの柔軟なアーキテクチャのおかげで、Scala のサポートはシンプルなモジュールとして提供されます。必要なのは conf/application.conf ファイルで scala モジュールを有効にすることだけです。
module.scala=${play.path}/modules/scala
こうすることで、アプリケーションの全部または一部を scala を使って書くことができるようになります。もちろん Java と混在させることも可能です。
我々はこのモジュールをとてもとても活発に開発しています。このモジュールを実験的な機能として試すことはできます。現時点で完全な play アプリケーションを Scala で書くことは期待しないでください。
scala サポートをざっと眺めてみたい場合は、Scala スクリーンキャスト を見てみてください。
play new コマンドの --with オプションを使うことで、scala を使う準備が整ったアプリケーションを自動的に作成することが可能です。とにかく試してみてください:
play new myApp --with scala
play アプリケーションはいつも通り作成されますが、 controllers パッケージを見てみると Application.java ファイルが Application.scala ファイルに置き換えられています:
package controllers
import play._
import play.mvc._
object Application extends Controller {
def index = render()
}
これは Java 版のデフォルト Application コントローラととても似ています。
いつものように play run を使ってアプリケーションを実行すれば、いつものウェルカムページが表示されます。ここで render() 呼び出しを置き換えるように Application.scala ファイルを編集してみてください。
def index = "Hello scala!"
ページを更新すると、魔法が見られます。
もっと明白なスタイルが好ましい場合は、レスポンスオブジェクトを直接書くために renderHtml メソッドを使用することができます。
いつも通り、間違いがあった場合、play は完璧な方法でエラーの内容を表示します; (今回、後に続くセミコロンを忘れることは、これまでより難しくなりました)
上記のように、アクションの結果を送出するために推論された返却型を直接使用することができます。例えば、String を使う場合は以下のようになります:
def index = "<h1>Hello world</h1>"
XHTML をリテラルとして書くために、組込みの XML サポートを使うこともできます:
def index = <h1>Hello world</h1>
返却型がバイナリストリームのように見える場合、play は自動的に renderBinary() を使います。このため、組込みの Captcha ヘルパを使ったキャプチャの生成を、次のように書くことができます:
def index = Images.captcha
Java と同じやり方で、いくつかのアクションパラメータを宣言することができます:
def index(name: String) = <h1>Hello {name}</h1>
scala の大きな利点は、これらのパラメータにデフォルト値を定義できることです:
def index(name: String = "Guest") = <h1>Hello {name}</h1>
こうすると、もし name HTTP パラメータが見つからない場合、play はデフォルト引数値を使います。
コントローラは、複数のインターセプタを結び付けるために複数のトレイトを使用することができます。
Secure トレイトを定義しましょう:
package controllers
import play._
import play.mvc._
trait Secure {
self: Controller =>
@Before
def check {
session("user") match {
name: String => info("Logged as %s", name)
_ => Security.login
}
}
}
そして、これを Application コントーラで使用することができます:
package controllers
object Application extends Controller with Secure {
def index = "Hello world"
}
モデルを java だけではなく、scala でも同様に定義することができます。
以下に例を示します:
@Entity
class User(
//fields
@Email
@Required
var email: String,
@Required
var password: String,
var fullname: String
) extends Model {
//instance methods
var isAdmin = false
override def toString = email
}
object User extends QueryOn[User] {
//extra finder methods (if any) come here
}
この API は、java のものと本当に似ているので、例えば (対となるオブジェクトを適切に定義していると仮定すれば) User クラスの count を呼び出すだけでユーザの数を数えることができます:
User.count
あるいは、値の紐付けを伴う複雑なクエリを実行する場合、以下のような感じになるでしょう:
QueryOn[Post].find("select distinct p.id from Post p join p.tags as t where t.name in (:tags) group by p.id having count(t.id) = :size", Map("tags" -> tags.toArray, "size" -> tags.size)).fetch
モデルにアクセスする別の手段として play.db.jpa.QueryOn を利用することができるので、先ほどの例を使うと: User.count は QueryOn[User].count となります。
通常は、対となるオブジェクトを使ってクエリ機能を提供する (例えば User.count) ことが推奨されます。より包括的な QueryOn アプローチの主な利点は scala と java モデルの両方で動作することです。
scala 版の キャッシュ api を使うことで、以下のようにすることができます。
Cache.get[People]("person-key-25") match {case Some(p) => println (p.name); case None => println("boo")}
ScalaTest サポートは Play に統合されており、例えば以下のようにして、ScalaTest を使って容易に単体、そして機能テストを書くことができます:
class SpecStyle extends UnitFlatSpec with ShouldMatchers {
"Creating a user" should "be succesfull" in {
val user = new User("bob@gmail.com", "secret", "Bob").save()
bob = User.find("byEmail", "bob@gmail.com").first
bob should not be (null)
bob.fullname should be ("Bob")
}
}
class RenderMethodsTest extends FunctionalTestCase with Matchers{
val response = GET("/application/json1")
response shouldBeOk()
response contentTypeShouldBe("application/json")
response charsetShouldBe("utf-8")
response contentShouldBe("{'name':'guillaume'}")
}
play-scala には、アプリケーションの様々な層を試すために本当に便利なコンソールが含まれています。
以下に例を示します:
kola:yabe-with-scala phausel$ play scala:console
~ _ _
~ _ __ | | __ _ _ _| |
~ | '_ \| |/ _' | || |_|
~ | __/|_|\____|\__ (_)
~ |_| |__/
~
~ play! 1.1-unstable-localbuild, http://www.playframework.org
~
15:43:17,805 INFO ~ Starting /Users/phausel/workspace/play-scala/samples-and-tests/yabe-with-scala
15:43:17,809 INFO ~ Module secure is available (/opt/local/lib/play-1.1-unstable-r777/modules/secure)
15:43:17,809 INFO ~ Module scala is available (/Users/phausel/workspace/play-scala/samples-and-tests/yabe-with-scala/../..)
15:43:17,810 INFO ~ Module crud is available (/opt/local/lib/play-1.1-unstable-r777/modules/crud)
15:43:19,300 WARN ~ You're running Play! in DEV mode
~
~ Starting up, please be patient
~ Ctrl+D to stop
~
15:43:31,774 INFO ~ Connected to jdbc:hsqldb:mem:playembed
15:43:33,130 INFO ~ Application 'Yet Another Blog Engine' is now started !
Welcome to Scala version 2.8.0.Beta1-prerelease (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_17).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import models._
import models._
scala> User.count
res0: Long = 3
コマンドはトランザクション内で実行されるので、モデルの変更は永続化されます。
Play には 2 つのデフォルトモジュール (secure と crud) が含まれており、scala モジュールはこれらのラッパを提供します。例えば CRUDFor トレイトを合成して CRUD コントローラを作ることができます:
object Companies extends Controller with CRUDFor[Company]
同様に、これに Secured トレイトを合成して認証をかけることができます:
object Companies extends Controller with CRUDFor[Company] with Secured
play.utils.Java と同じように、scala に特化したヘルパメソッドが play.utils.Scala オブジェクトに格納されています。いくつか例を示します:
import play.utils.Scala._
for (stream <- using (new PipeStream()) {
//do something with stream, close() will be called at the end
}
def nuller:String = null
?(nuller.toLowerCase.substring(1)) match { case Some(s) =>s;case None=>"oh no" }
val html = fromURLPath("http://www.playframework.org/@api/play/Play.html").mkString //read and connection timeout can be set too
scala 版のブログアプリケーションは play-scala に同梱されており、ここ にあります。
Mailer クラスを Scala で書くこともできます。ここ にサンプルがあります。
チュートリアルは ここ にあります。