Scalaクラスタの怒りが聞こえる…
Scalaクラスタの怒りに満ちたTLが見えて当該セッションのUstを見れなかったのが悔しいです。何があったかはTogetterからある程度察する事が出来ます。
参考:2011/07/22_Advanced_Tech_Night No.2 「ジャバラーが知っておくべき最近の開発言語のこと」(#atn2011 )
Play framework + Scala に入門してみる
そんな流れがあったのでScalaを触りたい気持ちが強くなりPlay frameworkの勉強と一緒にScalaをやってみようかと思い立ちました。Play frameworkというのははJava版Ruby on Railsといった感じでJavaだけれど非常に効率に良い開発が出来るフレームワークです(らしいです)Wicketとはまた違う爽快感のあるフレームワークのようです。
インストール
インストールは非常に簡単です。zipを落として適当に配置してPATHを通すだけ。ただしplayのコマンドはpythonで書かれているのでpythonが必要になるかもしれません。[play]とだけ打つとセットアップが出来ていれば以下のように結果が返ってくるでしょう。
$ play
~ _ _
~ _ __ | | __ _ _ _| |
~ | '_ \| |/ _' | || |_|
~ | __/|_|\____|\__ (_)
~ |_| |__/
~
~ play! 1.2.2, http://www.playframework.org
~
~ Usage: play cmd [app_path] [--options]
~
~ with, new Create a new application
~ run Run the application in the current shell
~ help Show play help
~
セットアップの確認が出来ればさっそく動作確認してみましょう。
プロジェクトの作成、アプリケーションの実行
以下のように打つとプロジェクトが作成出来ます。作成途中アプリケーションの名前を聞かれます。基本デフォルトのままで良いでしょう。スケルトンが作成されます。
$ play new [project_name] --with scala
~ _ _
~ _ __ | | __ _ _ _| |
~ | '_ \| |/ _' | || |_|
~ | __/|_|\____|\__ (_)
~ |_| |__/
~
~ play! 1.2.2, http://www.playframework.org
~
~ The new application will be created in /path/to/[project_name]
~ What is the application name? [project_name]
~
~ OK, the application is created.
~ Start it with : play run project_name
~ Have fun!
~
以下のようにして作成されたアプリケーションを起動する事が出来ます。9000番ポートで待っているようなのでhttp://localhost:9000/にアクセスしましょう。いかにもな導入ページが返って来たらOKです。
$ play run [project_name]
~ _ _
~ _ __ | | __ _ _ _| |
~ | '_ \| |/ _' | || |_|
~ | __/|_|\____|\__ (_)
~ |_| |__/
~
~ play! 1.2.2, http://www.playframework.org
~
~ Ctrl+C to stop
~
Listening for transport dt_socket at address: 8000
01:35:10,384 INFO ~ Starting /path/to/[project_name]
01:35:11,399 WARN ~ You're running Play! in DEV mode
01:35:11,609 INFO ~ Listening for HTTP on port 9000 (Waiting a first request to start) ...
01:43:01,925 INFO ~ Application '[project_name]' is now started !
Scalaで動作するプロジェクトを作成してみる。
今度はScalaのプロジェクトを作成してみます。ちなみに以下のように conf/dependencies.yml にScalaに依存することを追記して $ play dependencies [project_name] とすることでScala対応のプロジェクトにすることも出来ますが、スケルトンコードがJavaのままなので作り直したいと思います。
$ diff -u [project_name]/conf/dependencies.yml.orig [project_name]/conf/dependencies.yml
--- project_name/conf/dependencies.yml.orig 2011-07-24 02:04:56.000000000 +0900
+++ project_name/conf/dependencies.yml 2011-07-24 02:04:46.000000000 +0900
@@ -2,3 +2,4 @@
require:
- play
+ - play -> scala 0.9.1
$ play dependencies [project_name]
~ _ _
~ _ __ | | __ _ _ _| |
~ | '_ \| |/ _' | || |_|
~ | __/|_|\____|\__ (_)
~ |_| |__/
~
~ play! 1.2.2, http://www.playframework.org
~
~ Resolving dependencies using /path/to/[project_name]/conf/dependencies.yml,
~
~ play->scala 0.9.1 (from playLocalModules)
~
~ Installing resolved dependencies,
~
~ modules/scala-0.9.1 -> /path/to/[play]/modules/scala-0.9.1
~
~ Done!
~
Scala対応のプロジェクトを作成して動作確認する
Scala対応のプロジェクトを作成するにはまず以下のようにしてScalaモジュールをインストールする必要があります。
$ play install scala
~ _ _
~ _ __ | | __ _ _ _| |
~ | '_ \| |/ _' | || |_|
~ | __/|_|\____|\__ (_)
~ |_| |__/
~
~ play! 1.2.2, http://www.playframework.org
~
~ Will install scala-0.9.1
~ This module is compatible with: 1.2.2
~ Do you want to install this version (y/n)? y
~ Installing module scala-0.9.1...
~
~ Fetching http://www.playframework.org/modules/scala-0.9.1.zip
~ [--------------------------100%-------------------------] 60034.6 KiB/s
~ Unzipping...
~
~ Module scala-0.9.1 is installed!
~ You can now use it by adding it to the dependencies.yml file:
~
~ require:
~ play -> scala 0.9.1
~
インストールが済んだら実際にScala対応のプロジェクトを作成してみましょう。
$ play new [project_name] --with scala
~ _ _
~ _ __ | | __ _ _ _| |
~ | '_ \| |/ _' | || |_|
~ | __/|_|\____|\__ (_)
~ |_| |__/
~
~ play! 1.2.2, http://www.playframework.org
~
~ The new application will be created in /path/to/[project_name]
~ What is the application name? [project_name]
~
~ Resolving dependencies using /path/to/[project_name]/conf/dependencies.yml,
~
~ play->scala 0.9.1 (from playLocalModules)
~
~ Installing resolved dependencies,
~
~ modules/scala-0.9.1 -> /path/to/[play]/modules/scala-0.9.1
~
~ Done!
~
~ OK, the application is created.
~ Start it with : play run project_name
~ Have fun!
~
動作確認はJavaの時と同様に $ play run [project_name] で出来ます。
$ play run project_name/
~ _ _
~ _ __ | | __ _ _ _| |
~ | '_ \| |/ _' | || |_|
~ | __/|_|\____|\__ (_)
~ |_| |__/
~
~ play! 1.2.2, http://www.playframework.org
~
~ Ctrl+C to stop
~
Listening for transport dt_socket at address: 8000
02:15:51,036 INFO ~ Starting /path/to/[project_name]
02:15:51,067 INFO ~ Module scala is available (/path/to/[play]/modules/scala-0.9.1)
02:15:54,598 INFO ~ Scala support is active
02:15:54,598 WARN ~ You're running Play! in DEV mode
02:15:54,734 INFO ~ Listening for HTTP on port 9000 (Waiting a first request to start) ...
Compiling:
/path/to/[project_name]/app/controllers.scala
/path/to/[play]/modules/docviewer/app/controllers/PlayDocumentation.java
/path/to/[project_name]/tmp/generated/views.defaults.html.welcome.scala
/path/to/[project_name]/tmp/generated/views.Application.html.index.scala
/path/to/[play]/modules/docviewer/app/DocViewerPlugin.java
/path/to/[project_name]/tmp/generated/views.html.main.scala
/path/to/[play]/modules/docviewer/app/helpers/CheatSheetHelper.java
Traversing /path/to/[project_name]/app/controllers.scala
Traversing /path/to/[project_name]/tmp/generated/views.Application.html.index.scala
Traversing /path/to/[project_name]/tmp/generated/views.defaults.html.welcome.scala
Traversing /path/to/[project_name]/tmp/generated/views.html.main.scala
API phase took : 0.503 s
02:16:21,114 INFO ~ Application '[project_name]' is now started !
プロジェクト構成
Playのプロジェクトは以下のような構成となっています。アプリケーションを構築して行く際は主にapp以下を弄って行く事になるでしょう。
- app
- コントローラ、モデル、ビューなど。
- conf
- アプリケーションの設定。ルーティングの設定もここ。
- lib
- jarファイルなどのlib関係。
- modules
- プロジェクトが依存しているものがこの下に書き出されるのかな?
- public
- 静的ファイルなど。
- test
- テスト関係など。
- tmp
- 生成されたclassファイルの配置やキャッシュなど。
とりあえず中身を眺めてみる
生成されるスケルトンは以下のようになっています。ルーティングとコントローラ/アクションの対応は直感的で分かりやすいですね。Controllerを継承したApplicationがコントローラ、その中で定義したメソッドがアクションのようです。
ただアクションで何を返すかが非常に分りづらいですね(もちろん基本はテンプレートですが)テンプレートそのものも@が出て来て関数定義っぽいし非常に分りづらいです。Webデザイナー殺しですね死ねば良いと思います^^
$ cat [project_name]/conf/routes
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~
# Home page
GET / Application.index
# Ignore favicon requests
GET /favicon.ico 404
# Map static resources from the /app/public folder to the /public path
GET /public/ staticDir:public
# Catch all
* /{controller}/{action} {controller}.{action}
$ cat [project_name]/app/controllers.scala
package controllers
import play._
import play.mvc._
object Application extends Controller {
import views.Application._
def index = {
html.index("Your Scala application is ready!")
}
}
$ cat [project_name]/app/views/Application/index.scala.html
@(title:String)
@main(title) {
@views.defaults.html.welcome(title)
}
$ cat [project_name]/app/views/main.scala.html
@(title:String = "")(body: => Html)
<!DOCTYPE html>
<html>
<head>
<title>@title</title>
<link rel="stylesheet" media="screen" href="@asset("public/stylesheets/main.css")">
<link rel="shortcut icon" type="image/png" href="@asset("public/images/favicon.png")">
<script src="@asset("public/javascripts/jquery-1.5.2.min.js")" type="text/javascript"></script>
</head>
<body>
@body
</body>
</html>
アクションとビュー
とりあえずスケルトンでは以下のような感じで動いているようです。
- views/[レイアウト].scala.html
- レイアウトを定義
- views/[コントローラ]/[アクション].scala.html
- @レイアウト(引数) { HTML }
- レイアウトとHTMLをガッチャンコして返す
HTMLの部分が@views.defaults.html.welcome(title)となってこれが何を差しているのかが分りづらくしています。ここを<h1>@title</h1>とでもすればもう少し見通しが良くなるのではないかと思います。具体的には以下のような感じ。
$ diff -u [project_name]/app/views/Application/index.scala.html.orig [project_name]/app/views/Application/index.scala.html
--- project_name/app/views/Application/index.scala.html.orig 2011-07-24 03:45:31.000000000 +0900
+++ project_name/app/views/Application/index.scala.html 2011-07-24 03:47:38.000000000 +0900
@@ -2,6 +2,6 @@
@main(title) {
- @views.defaults.html.welcome(title)
+ <h1>@title</h1>
-}
\ No newline at end of file
+}
$ diff -u project_name/app/controllers.scala.orig project_name/app/controllers.scala
--- project_name/app/controllers.scala.orig 2011-07-24 03:49:42.000000000 +0900
+++ project_name/app/controllers.scala 2011-07-24 03:48:58.000000000 +0900
@@ -8,7 +8,11 @@
import views.Application._
def index = {
- html.index("Your Scala application is ready!")
+ html.index("index")
}
+ def sample = {
+ html.index("sample")
+ }
+
}
アクションも増やしてみました。これでルーティング設定も確認出来ます。$ play run [project_name] として以下へアクセスするとそれぞれindex、sampleが<h1>で表示されることが確認出来ると思います。
なんとなくではありますがアクションからテンプレートが呼ばれ、引数を使ってレイアウトを解決して表示していることが見えてきた感じがします。
まとめ
とりあえず一旦ここまで。何をしているか理解出来たらまたコントローラ/アクション/テンプレートの関係を文字に起こしてみたいと思います。
Play frameworkですが面白そうではあるもののやはりテンプレート周りが気に入らないですね。テンプレートの中にコードを埋め込んだり、独自の構文でロジックを埋め込んだりというのはどうしても慣れないです。どんなに簡単な構文でそれが可能だとしてもデザイナーとの連携の時にはやはり困ると思うのです。「ここは動的な情報が入るのでこういう書き方をして下さい」なんて絶対混乱します。テンプレートをHTMLで書くならそのテンプレートはプレーンなHTMLであるべきだと自分は思います。