IE9でBackboneアプリが動かない
ChromeやFFで問題なく動作していたBackboneアプリがIE9では動かない。。
デバッグツールを立ち上げるとこんなエラーが出ていました。
SCRIPT1028: 識別子、文字列または数がありません。
var ItemView = Backbone.View.extend({ render: function(){ $(this.el).html(this.template(this.model.toJSON())); return this; }, //こんなかたちでカンマが残っているとエラーになります。 });
IE9でも互換モードになっているとChromeやFirefoxのように動かないので、ヘッダーを入れておく必要があります。
http://stackoverflow.com/questions/4811801/force-ie9-to-emulate-ie8-possible
Source:
http://d.hatena.ne.jp/rockstar2007/20081102/1225590395
Jasmine+sinon.jsでjQuery.ajaxが呼ばれているかテストする
sinon.spyを使うと$.ajaxが呼ばれているかをテストできます。
このときはBackboneのCollectionでfetchが正しいパラメータで呼び出されているかをテストしてみました。
describe("some ajax test", function(){ beforeEach(function(){ this.ajaxSpy = sinon.spy($, "ajax"); this.paramSpy = sinon.spy($, "param"); this.collection = new MyCollection(); }, afterEach(function() { $.ajax.restore(); $.param.restore(); }); it("should make some ajax request using these parameters", function(){ var start = "2012/6/1"; var theEnd = "2012/6/31"; this.collection.someAjaxCall(start, theEnd); expect(this.ajaxSpy).toHaveBeenCalledOnce(); expect(this.paramSpy).toHaveBeenCalledWith({start: "2012/6/1", theEnd: "2012/6/31"}); }); });
Jasmine+BackboneでViewのテストをするときにダミーのHTML要素を使う
jasmine-jqueryのsandboxを使うと、テストの間だけ使えるDIV要素を作ってくれます。
各テストの間でちゃんと掃除をしてくれるので、わざわざ削除する必要もありません。
beforeEach(function(){ setFixtures(sandbox()); });
sandbox()を使うとdiv要素にidとしてsandboxが付けられます。
idを変更したい場合はsandbox({id: "someId"})とするとIDを変更できます。
DIV以外の要素を指定したい場合はこんな感じでappendすると使えます。
setFixtures(sandbox()); $("#sandbox").append("<input type='text' id='search' />");
Jasmineで非同期のリクエスト終了後にテストを実行する
今日はJasmineを使ってBackbone.Viewのテストを書いていました。
サンプルに載っていた通り、非同期リクエストでViewのテンプレートを読み込んでいたのですが、テンプレートの読み込みが終了した時点でテストを実行しようとして、うまくいかずにハマりました。Jasmineを使った非同期リクエストのテストについて調べて「waitsFor」と「runs」を使うことで、思い通りに実行できました。
waitsFor(function, message, timeout)
https://github.com/pivotal/jasmine/wiki/Asynchronous-specs
waitsForを使うとtimeoutで指定した秒数(ミリ)が経過するまで、引数に渡したfunctionからtrueが返ってくるのを待ってくれます。
もしtrueが返ってくるまえにtimeoutに達した場合はmessageで指定したエラーメッセージが戻ってきます。
下の例では、テンプレートを非同期で読み込んで、読み込みが完了したらloadedがtrueになります。
waitsForで500ミリ秒間、loadedの値がtrueになるのを待ってから、次のrunsを実行しています。
beforeEachの時点でviewを用意しているので、itが実行されるときにはテンプレートの読み込みが終わって、viewの準備ができた状態になっています。
describe("nice test", function(){ beforeEach(function(){ var self = this; this.loaded = false; this.model = new Backbone.Model(); templateLoader.load(["nice-template"], function(){ self.loaded = true; }); waitsFor(function(){ return self.loaded; }, "template loading timed out", 500); runs(function(){ self.view = new MyView({model: self.model}); }); } it("should be testing the view", function(){ expect($(this.view.render().el).html()).contains("hoge"); }); });
Source:
http://pivotal.github.com/jasmine/
https://github.com/pivotal/jasmine/wiki/Asynchronous-specs
http://d.hatena.ne.jp/hagino_3000/20111009/jasmine
PlayFramework 別のモデルと関連があるモデルにGsonのtoJsonが使えないとき
Gsonを使うとモデルをそのままJSON形式に変換したい時に、こんな形で一発変換できます。
Gson g = new Gson(); Person p = Person.findById(myId); g.toJson(p); // {"name": "Taro Yamada", "birthday": "1920/06/30"}
ただ、Personが別のモデルとManyToOneとかOneToManyなど、何らかの関連があるときには「gson circular reference error」でJSON形式に変換できません。最初はモデルを一度Hashに変換してからJSON形式に変換していたのですが、なにか違うのかもしれないと思い、回避する方法を探してみたところ、Exposeアノテーションを使う方法と、ExclusionStrategyを実装する方法の2つ方法がありました。
@Exposeを使う方法
http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/annotations/Expose.html
モデルでJSON形式として含めたいプロパティだけにExposeアノテーションを付けます。
この場合はsecretだけtoJSONしても出てきません。
@Expose public String name; @Expose public String address; @OneToMany(mappedBy="person", cascade=CascadeType.ALL) public List<Hoge> secrets;
モデルの設定が終わったらGsonBuilderでexcludeFieldsWithoutExposeAnnotationを使ってGsonインスタンスを生成します。
Gson g = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
Person p = Person.findById(id);
renderJSON(g.toJson(p));
うまくいったと思ったのですが、idが出力されないので使えません。。
いろいろごにょごにょした結果、最終的にもうひとつの方法を使いました。
http://stackoverflow.com/questions/4802887/gson-how-to-exclude-specific-fields-from-serialization-without-annotations
ExclusionStrategyを実装します。
さきほどと同じく他のモデルと関連があるsecretsを対象から外します。
package models; import com.google.gson.ExclusionStrategy; import com.google.gson.FieldAttributes; public class PersonExclusionStrategy implements ExclusionStrategy { public boolean shouldSkipClass(Class<?> arg0) { return false; } public boolean shouldSkipField(FieldAttributes f) { return (f.getDeclaringClass() == Person.class && f.getName().equals("secrets")); } }
でGsonをインスタンス化するときにこのExclusionStrategyを使うように指定します。
Gson g = new GsonBuilder() .setExclusionStrategies(new PersonExclusionStrategy()) .create(); Person p = Contact.findById(id); renderJSON(g.toJson(p));
無事に変換できました。
その他ソース:
http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/GsonBuilder.html#excludeFieldsWithoutExposeAnnotation()
https://sites.google.com/site/gson/gson-user-guide
Ajaxリクエストをテスト
PlayのFunctionalTestでAjaxリクエストをテストしてみました。
ここではJSON形式でデータを渡すので、Gsonを使ってHashをJSON形式に直してからPOSTしています。
HashMap dataToSend = new HashMap(); dataToSend.put("key1", "value1"); dataToSend.put("key2", "value2"); Gson g = new Gson(); Response resp = POST("/niceAction","application/json",g.toJson(dataToSend).toString()); // check if desired value is returned assertContentEquals("expected response!", resp);
Eclipseでvim/textmateライクなテーマを使う
仕事ではJavaが多いのでEclipseを使います。
画面があまりにもシンプルで寂しいので、Eclipseのテーマをいじれないか探してみたところ、プラグインを使ってVimやTextmateっぽい感じにすることができました。wombatやmonokaiなども最初から用意されています。インストールも設定も非常に簡単でした。
Help -> Install New Softwareで次のサイトを登録
http://eclipse-color-theme.github.com/update
Eclipse Color Themeをインストール
General -> Appearance -> Color Themeから好きなテーマを選ぶだけ
Eclipse Color Theme Plugin
https://github.com/eclipse-color-theme/eclipse-color-theme
Stackoverflow
http://stackoverflow.com/questions/96981/color-themes-for-eclipse
http://stackoverflow.com/questions/96981/color-themes-for-eclipse/4815649#4815649