PlayFrameworkでローカルにあるJarを使いたい
こんな形でjarをローカルフォルダに突っ込んで、使用することができます。
こうしておくとJenkinsでも、ビルド前にdependencies --syncすることで、ちゃんと指定したjarを使ってくれます。
jarのファイル名は、artifactのところにあるように「モジュール名-バージョン.jar」の形に直しておく必要があります。
require: - play - play -> cobertura 2.4 - provided -> dom4j 1.6.1 - provided -> xmlbeans 2.3.0 - provided -> poi 3.8 - provided -> poi_ooxml 3.8 - provided -> poi_ooxml_schemas 3.8 - provided -> stax_api 1.0.1 repositories: - provided: type: local descriptor: "${application.path}/../[module]/conf/dependencies.yml" artifact: "${application.path}/jar/[module]-[revision].jar" contains: - provided -> *
Source: https://groups.google.com/group/play-framework/browse_thread/thread/b54e4e25ae49161b
jQuery + Backbone + JasmineでBDD その1
jQuery + Backbone + JasmineでBDDを試してみます。元ネタはこちらのすばらしいブログです。
最初に断っておきますが、私はJasmine初体験でBDD、TDDの知識も本で読みかじった程度です。
ついでに言うと、jQueryもちょろっと触ったことがあるくらいです。
なぜこんな無謀な記事を書いているかといいますと、Jasmineを使ってBDDに関する知識を獲得しつつ、BackboneでMVCフレームワークに触れながら、JavaScriptのオブジェクト指向を勉強している間に、jQueryでDOMの操作やセレクターの使い方を覚えられたらサイコーだと思ったからです。わからないことだらけで、いろいろなドキュメントを参照しながら進みます。「それは違う!」とか「こうしたほうがいいんじゃない?」などあれば、ぜひツッコんでいただければと思います。
今回サンプルとして作るのは電話帳アプリです。目標はSpineのサンプルにあるような感じです。
まず最初の一歩は必要なファイルをローカルにダウンロードします。
Jasmine
https://github.com/pivotal/jasmine/downloads
Underscore.js
http://underscorejs.org/
Backbone.js
http://documentcloud.github.com/backbone/
JQuery
GoogleのCDN
https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
Jasmine standaloneのZipを解凍したら、Underscore.jsとBackbone.jsはlibディレクトリに入れます。
どうやらsrcフォルダにソースを入れて、specフォルダにはSpecを入れる模様です。
準備ができたら次の行をSpecRunner.htmlに追加します。
※読み込む順番を修正しました。最初にjQueryを読み込むようにしないと後でおかしなことになります。
<head> ... <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> <script type="text/javascript" src="lib/underscore.js"></script> <script type="text/javascript" src="lib/backbone.js"></script>
ChromeでSpecRunner.htmlを開いてみるとデフォルトのSpec実行結果が表示されています。
ツールからJavaScriptコンソールもついでに開いておきます。
もともとあったspec/*Spec.js、src/*.jsをSpecRunner.htmlのHeadタグから削除して、ContactSpec.js、Contact.jsを作成します。
SpecRunnerのHeadタグ内にそれぞれ追加してRefreshしてみます。まっしろの画面でなにも表示されません。。
とりあえずサンプルのPlay.jsとPlaySpec.jsを参考にしながらSpecを追加してみました。
describeのところで何に関してのテスト(振る舞い?)なのか、二番目の引数にfunction(テストの中身)を渡してます。
contactはこのテストの中で使うモデルで、beforeEachメソッドの中にある内容は、これから追加するSpec(テスト)が実行される直前に、毎回実行されるようです。specが走る前の準備をするためのメソッドということでしょうか?
ContactSpec.js
describe("Contact", function(){ //Specの中で使うContact var contact; //各Spec実行前に毎回実行される beforeEach(function(){ contact = new Contact({}); }); });
Chromeで画面を更新するとデバッガにUncaught TypeError: Cannot call method 'suiteComplete' of undefinedエラーが表示されました。
どうやらspecがないのでJasmineに怒られている模様です。ContactSpec.jsにSpecを追加してみます。
expectの中には自分が評価したい値を入れて、toEqualにexpect(期待)する結果を入れます。
「expect(contact).toEqual(null)」だと「contactがnullであることをチェックしてね」ということになります。
ここではその逆をやりたいので、Googleで探してみたところ「not」を使うと反対のことをexpectするように指定できるとあったので、やってみました。
it("is my first spec!", function(){ expect(contact).not.toEqual(null); });
今度はSpecのエラーになってくれました。
Contactがないよ、ということです。
Failing 1 spec
1 spec | 1 failing
Contact is my first spec!.
ReferenceError: Contact is not defined
Contactのコードを追加していないので、Backbone.ModelとしてContact.jsにモデルを定義してみます。
Contact.js
var Contact = Backbone.Model.extend();
Passing 1 Spec
Contact
is my first spec!
初めてPassしました。これがBDD、TDDのRed,Green,Refactorサイクルというやつの入り口でしょうか。
次になにをするのかよくわからないので、getFullNameで氏名が返ってくるようなメソッドを追加してみます。
Backboneのモデルではmodel.set({name: value})がSetterでmodel.get("name")がgetterになっています。
beforeEachでsetを使ってModelにfirstName、lastNameをセットします。
続いて新しいSpecを追加します。
beforeEachでfirstNameとlastNameがセットされているので、getFullNameを呼べば氏名が取得できるはずです。
beforeEach(function(){ contact = new Contact(); contact.set({firstName: "Taro", lastName: "Yamada"}); }); //...略 it("should generate fullname from first name and lastname", function(){ expect(contact.getFullName()).toEqual("Yamada Taro"); });
もちろんモデルになにも書いてないのでRedになりました。
Failing 1 spec
2 specs | 1 failing
Contact should generate fullname from first name and lastname.
TypeError: Object [object Object] has no method 'getFullName'
getFullNameメソッドをモデルに追加してみます。
Contact.js
var Contact = Backbone.Model.extend({ getFullName: function() { return null; } });
なんとなくエラーがマシになりました。
Failing 1 spec
2 specs | 1 failing
Contact should generate fullname from first name and lastname.
Expected null to equal 'Yamada Taro'.
Backbone.Modelのgetを使って取得したfirstName、lastNameを繋げて返します。
getFullName: function() { return this.get("lastName")+" "+this.get("firstName"); }
全部Greenになりました!
さて、ここからどうしようか…
Passing 2 specs
Contact
is my first spec!
should generate fullname from first name and lastname
PlayFrameworkのtemplate その2
Include
テンプレートの中で別のテンプレートを呼び出すにはincludeを使います。
includeされたテンプレートでは、親テンプレートで使用可能な値を使うことができます。
includeする親側での呼び出しは下のような形です。
#{include 'Books/bookDetail.html'}
呼び出されるほうのテンプレート。
親で有効な値を使う場合は普通に${model.property}みたいに使えます。
<label>${book.author}</label>
Tag
テンプレートに対してパラメータを渡す場合にはTagを使います。
Tagというとわかりにくいですが、単にテンプレートと同じものだけども、こちらはパラメータを渡せます。
IncludeされたテンプレートからTagを呼び出すこともできます。
まず/views/tags/フォルダの下にTag化したいテンプレートを入れます。
Tag用のテンプレートの中では、親から受け取ったパラメータの頭にはアンダースコアが付きます。
この例では親テンプレートが「propertyName」を渡しているので、Tagテンプレートでは「_propertyName」として受けとります。
/*/views/tags/tagBookDetail.html*/ <input type="text" name="${_propertyName}" value="${_propertyValue}" />
/*親テンプレート*/ #{tagBookDetail propertyName:"author", propertyValue:"Goethe" /}
パラメータはカンマ区切りで渡します。
PlayFrameworkのtemplate
今日はPlayのテンプレートで3つ発見があったので、そのときのことをメモします。
ソースが手元にないので覚えてる部分から書いていきます。
・別のテンプレートをページの一部に読み込む(Railsのpartialみたいな)
・ループの中でインデックスを取得する
・フォームから複数のオブジェクトをListとしてコントローラーで受け取る
別のテンプレートを読み込むには、親になるテンプレートでincludeを使います。
今回やったのはこんな感じです。
1.EditAll画面でBookオブジェクトのListを受け取る。
2.BookのListをループさせて、includeしたBookオブジェクトの詳細を表示するbook.htmlで表示
/*editAll.html*/ #{form @Book.saveAll() , id:'saveAllForm'} #{list items:books, as:'book'} #{include 'book.html' /} #{/list} <input type="submit" value="Save All" /> #{/form}
/*book.html*/ <input type="text" name="books[${book_index}].name" value="${book.name}" /> <input type="text" name="books[${book_index}].price" value="${book.price}" />
includeだと親のテンプレートで使える変数はすべてそのまま使えます。
book.htmlはループの中でincludeされているので「オブジェクト名_index」でインデックスを取得できます。
他にも、Listの最後のアイテムかどうか、最初のアイテムかどうかを判断するbook_isLastとbook_isFirstが使えます。
SubmitされたあとはController上のActionで、引数にListで指定するだけで使えます。
public static void saveAll(List<Book> books){ ... }
Source:
http://www.playframework.org/documentation/1.2.3/tags#list
http://stackoverflow.com/questions/7659310/play-framework-how-can-i-pass-collection-to-action-create
PlayFrameworkでTDDのマネをしてみた
自分用の小さな開発案件にPlayを使ってTDDを真似てみようと思いました。
とりあえずModelのテストからと書き始めたところ…
//Model @Entity public class Company extends Model{ } //Test public class CompanyTest{ @Test public void testSomething(){ Company c = new Company(); assertNotNull(c); } }
これだけでも@TestアノテーションがあればJUnitでテストを実行することはできます。
ただ、これだとfindAllなどのJPA(Java Persistence API)の機能を使うと下記のエラーが発生します。
UsupportedOperationException occured : Please annotate your JPA model with @javax.persistence.Entity annotation
エラーメッセージだけを読むと@Entityを使えとしか書いていないので、「ちゃんと@Entityってあるじゃん!?」と少しはまりました。原因はJPAの機能を利用する側(テスト用のクラス)がPlayFrameworkに対応していないとダメなので、きちんとplay.test.UnitTestをextendsしておく必要がありました。最初からドキュメントを読んでおけばこんなことにはならないです。。
import play.test.*; public class CompanyTest extends UnitTest{ //... }
Fixtureからデータを読み込むには、testパッケージの配下にあるdata.ymlにYAML形式でデータを追加してからFixtures.loadModulesで読み込む必要があります。
# Test data Company(google): name: Google Company(zen): name: Zenexity
@Before public void setUp(){ Fixtures.deleteAll(); Fixtures.loadModels("data.yml"); }
http://ja.wikipedia.org/wiki/Java_Persistence_API
http://www.playframework.org/documentation/1.2.3/test
YUM, RPMのメモ
Redhat系のOSの場合、yum, rpmでパッケージの管理をすることになります。
削除や追加もたまに発生するのですが、毎回コマンドを忘れてしまい、その度に調べることになるのでメモします。
YUM
すでにインストールされているパッケージを調べるにはlist installedを使う。
ただこれだとインストール済みパッケージがすべて表示されるので、grepと組み合わせて、自分が探しているパッケージのみを表示する
# yum list installed | grep java java-1.6.0-openjdk.i386 1:1.6.0.0-1.25.1.10.6.el5_8 installed sun-javadb-client.i386 10.6.2-1.1 installed sun-javadb-common.i386 10.6.2-1.1 installed sun-javadb-core.i386 10.6.2-1.1 installed sun-javadb-demo.i386 10.6.2-1.1 installed sun-javadb-docs.i386 10.6.2-1.1 installed sun-javadb-javadoc.i386 10.6.2-1.1 installed
yumでインストールしたパッケージを削除する場合はremove
# yum remove PACKAGE
RPM
インストールの場合は-ivhオプション
rpm -ivh path_to.rpm
アップグレードの場合は-Uvhオプション
rpm -Uvh path_to.rpm
同じくrpmでインストール済みのパッケージを表示するには-qaオプションとgrepを組み合わせて使う
# rpm -qa | grep java sun-javadb-common-10.6.2-1.1 sun-javadb-docs-10.6.2-1.1 sun-javadb-core-10.6.2-1.1 sun-javadb-demo-10.6.2-1.1 sun-javadb-javadoc-10.6.2-1.1 sun-javadb-client-10.6.2-1.1 java-1.6.0-openjdk-1.6.0.0-1.25.1.10.6.el5_8
さらにパッケージの詳細を確認する場合はqiオプション
# rpm -qi sun-javadb-client-10.6.2-1.1 Name : sun-javadb-client Relocations: /opt/sun Version : 10.6.2 Vendor: Sun Microsystems, Inc. Release : 1.1 Build Date: Wed 03 Nov 2010 04:19:39 PM JST Install Date: Mon 21 May 2012 05:47:38 PM JST Build Host: jdb-lin-i586 Group : Applications/Databases Source RPM: sun-javadb-client-10.6.2-1.1.src.rpm Size : 528518 License: Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. Signature : (none) URL : http://www.sun.com Summary : Java DB client Description : Client for Java DB
削除する場合には-eオプションを使う
# rpm -e PACKAGE
Source:
http://linux.kororo.jp/cont/intro/yum.php
http://www.atmarkit.co.jp/flinux/rensai/linuxtips/050inforpm.html
http://www.atmarkit.co.jp/flinux/rensai/linuxtips/049instrpm.html
JenkinsでVerifyError
新しく仲間に加わったJenkins氏がPlayのプロジェクトのテスト実行時にエラーを吐いていた。
APIをみても「some sort of internal inconsistency or security problem」といまいちはっきりしないのですが。
Execution exception VerifyError occured : Expecting a stack map frame in method ...
application.confでJAVAのバージョンを指定することで解決できた。
java.source=1.6
http://docs.oracle.com/javase/7/docs/api/java/lang/VerifyError.html
http://stackoverflow.com/questions/6704169/verifyerror-expecting-a-stack-map-frame-in-method-controllers-securesecurity-a
http://java.dzone.com/articles/javalangverifyerror-expecting