Slim3をScalaで動かすためのいろいろ
「EXILEはクラウド!」
ではなく、appengine ja night #6 Beer Talk : ATNDで発表した内容です。
Slim3をScalaで動かすためのブランクプロジェクトと、ScalaのController/Serviceを生成するSlim3-gen-scalaを作りました。
yuroyoro/slim3-scala-blank · GitHub
yuroyoro/slim3-gen-scala · GitHub
特徴
- ScalaでSlim3が動きます。
- ScalaのController/Serviceを生成できます。
- EntityはJavaで作成しますが、Scalaから問題なく使えます。
- テストはSpecsで書けます。( specs - a BDD library for Scala - Google Project Hosting )
やりかた
ブランクプロジェクトをダウンロー丼
とりあえず、JDKとScalaとGoogle appengine java SDKは入れておいてくださいね☆
- JDK6 Update 15以上(http://java.sun.com/javase/ja/6/download.html)
- Scala 2.7.7.final(http://www.scala-lang.org/downloads)
- Google appengine java SDK 1.3.1(http://code.google.com/intl/ja/appengine/downloads.html)
まずは、yuroyoro/slim3-scala-blank · GitHubからブランクプロジェクトを取得します。
git cloneで取得するか、"Download Souce"ボタンで圧縮ファイルを取得して転回してください。ディレクトリ名は変えてね?
設定を変えるよ
build.propertiesの中で、Google appengine java SDKとScala Homeのパスを環境に合わせて修正してください。
build.properties
# your appengine home gae.sdk.home=/Users/ozaki/sandbox/GAEJava/sdk/appengine-java-sdk-1.3.1/ # your scala home scala.home=/Users/ozaki/dev/Scala/scala-2.7.7.final/rt
build.xmlの先頭のプロジェクト名も変えておくとよいでしょう。
build.xml
<project name="slim3-blank" default="gen-controller" basedir=".">
war/WEB-INF/web.xmlのslim3.rootPackageの設定値を、作成するアプリケーションのパッケージ名に修正します。
war/WEB-INF/web.xml
<?xml version="1.0" encoding="utf-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5"> <context-param> <param-name>slim3.rootPackage</param-name> <param-value>your.application.pakcage</param-value> </context-param> <context-param> <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name> <param-value>application</param-value> ...
war/WEB-INF/appengine-web.xmlのアプリケーション名を設定します。
<?xml version="1.0" encoding="utf-8"?> <appengine-web-app xmlns="http://appengine.google.com/ns/1.0"> <application></application> <version>1</version> ...
いじょ。
自動生成ししてみる
現時点では、Ecipseでの開発環境に対応してません。ScalaのEclipse-pluginが残念なためです。ごめんなさい。
なので、コマンドラインからantコマンドを使います。
Controllerの生成
"ant gen-scala-controller"と入力すると、Controllerのパスの入力を促されるので「えいやっ」と入れます(気合い大事)。すると、ScalaのControllerとテストクラスとJSPが生成されます。
ozaki@yuroyoro-MacBook $ ant gen-scala-controller git[master][~/sandbox/.../yuroyoro/test] Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8 Buildfile: build.xml gen-scala-controller: [input] Input a controller path. /Foo/ [gen-scala-controller] Generated. ({slim3scala.controller.Foo.IndexController}.scala:0) [gen-scala-controller] Generated. ({slim3scala.controller.Foo.IndexControllerSpec}.scala:0) [gen-view] Generated. (/Users/ozaki/dev/Project/sandbox/scala/yuroyoro/test/war/Foo/index.jsp) BUILD SUCCESSFUL Total time: 11 seconds
生成されたController:
package slim3scala.controller.Foo import org.slim3.controller.Controller import org.slim3.controller.Navigation class IndexController extends Controller { override def run() = { forward("index.jsp") } }
生成されたテストクラス:
package slim3scala.controller.Foo import org.specs.Specification import org.specs.runner._ import org.slim3.tester.ControllerTester object IndexControllerSpec extends org.specs.Specification { val tester = new ControllerTester( classOf[IndexController] ) "IndexController" should { doBefore{ tester.setUp;tester.start("/Foo/")} "not null" >> { val controller = tester.getController[IndexController] controller must notBeNull } "not redirect" >> { tester.isRedirect must beFalse } "get destination path is /Foo/index.jsp" >> { tester.getDestinationPath must_==/ "/Foo/index.jsp" } doAfter{ tester.tearDown} } } class IndexControllerSpecTest extends JUnit4( IndexControllerSpec )
Serviceの生成
"ant gen-scala-service"と入力すると、Serviceクラスのクラス名の入力を促されるので「ふぬいっ」と入れます(勢い大事)。すると、ScalaのServiceクラスとテストクラスが生成されます。
ozaki@yuroyoro-MacBook $ ant gen-scala-service git[master][~/sandbox/.../yuroyoro/test] Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8 Buildfile: build.xml gen-scala-service: [input] Input a service name. (ex. FooService -> root.service.FooService, bar.FooService -> root.service.bar.FooService) HogeService [gen-scala-service] Generated. ({slim3scala.service.HogeService}.scala:0) [gen-scala-service] Generated. ({slim3scala.service.HogeServiceSpec}.scala:0) BUILD SUCCESSFUL Total time: 4 seconds
生成されたServiceクラス:
package slim3scala.service class HogeService { }
生成されたテストクラス:
ozaki@yuroyoro-MacBook $ cat test/slim3scala/service/HogeServiceSpec.scala git[master][~/sandbox/.../yuroyoro/test] package slim3scala.service import org.specs.Specification import org.specs.runner._ import org.slim3.tester.AppEngineTester object HogeServiceSpec extends org.specs.Specification { val tester = new AppEngineTester val service = new HogeService "HogeService" should { doBefore{ tester.setUp} "not null" >> { service must notBeNull } doAfter{ tester.tearDown} } } class HogeServiceSpecTest extends JUnit4( HogeServiceSpec )
あとは、中身をURRRYYYYY!!と書いていくだけです。
テストを実行する
"ant test"とコマンドを打ちます。コンパイルが行われ、テストが実行されます。
test: [java] Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8 [java] Specification "/Users/ozaki/dev/Project/sandbox/scala/yuroyoro/test/test/**/*Spec.scala" [java] Specification "IndexControllerSpec" [java] IndexController should [java] + not null [java] + not redirect [java] + get destination path is /Foo/index.jsp [java] [java] Total for specification "IndexControllerSpec": [java] Finished in 0 second, 432 ms [java] 3 examples, 3 expectations, 0 failure, 0 error [java] [java] Specification "HogeServiceSpec" [java] HogeService should [java] + not null [java] [java] Total for specification "HogeServiceSpec": [java] Finished in 0 second, 42 ms [java] 1 example, 1 expectation, 0 failure, 0 error [java] [java] Total for specification "/Users/ozaki/dev/Project/sandbox/scala/yuroyoro/test/test/**/*Spec.scala": [java] Finished in 0 second, 498 ms [java] 4 examples, 4 expectations, 0 failure, 0 error [java] BUILD SUCCESSFUL Total time: 14 seconds
テストはSpecsですので、"IndexController should not null."のようにテストケースが文章っぽくかけて細かく分割できます。ステキですね??
ローカルで動かす
EclipseのGAE pluginで起動できないので、"dev_appserver"コマンドでサーバを起動します。
ozaki@yuroyoro-MacBook $ dev_appserver.sh ./war/ git[master][~/sandbox/.../yuroyoro/test] Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8 Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8 2010-03-19 17:10:47.431 java[5406:903] Can't open input server /Library/InputManagers/Inquisitor 2010-03-19 17:10:47.482 java[5406:903] [Java CocoaComponent compatibility mode]: Enabled 2010-03-19 17:10:47.484 java[5406:903] [Java CocoaComponent compatibility mode]: Setting timeout for SWT to 0.100000 2010/03/19 8:10:49 com.google.apphosting.utils.jetty.JettyLogger info 情報: jetty-6.1.x 2010/03/19 8:10:50 com.google.appengine.tools.development.agent.impl.BlackList initBlackList 致命的: Unable to read a jre library while constructing the blacklist. Security restrictions may not be entirely emulated. /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/lib/plugin.jar Slim3 HOT reloading:true 2010/03/19 8:10:52 com.google.apphosting.utils.jetty.JettyLogger info 情報: Started SelectChannelConnector@127.0.0.1:8080 The server is running at http://localhost:8080/
"ant compilie/test"でコンパイルすれば、HotDeployも出来ます。