sorted out

wasavi のディレクトリ構造を整理した。

wasavi のディレクトリは、ローカルでは Subversion で管理し、さらに公開用に git も使っている。つまり、同一ディレクトリに .svn と .git が共存している。Subversion には、ここのサーバへの ftp のパスワードとか、chrome 用の wasavi.pem といった、ムフフ(謎)なファイルも格納しているが、git に対しては ignore させている。

で、github で見ればわかるとおり、今まではいわゆる trunk 直下に wasavi.js とか諸々を置いていた。これは基本的に chrome の extension を前提とした構造である。opera と firefox 向けにはそれぞれ専用のディレクトリを作り、trunk 直下へのファイルへのシンボリックリンクを置いていた。なぜ chrome 第一主義になっているかというと、別に chrome サイコー! というわけでは全然なくて、chrome は extension のファイルについて ntfs ネイティブなシンボリックリンクを解決してくれないからだ(最近のはどうか知らないが、試していない)。

これはなかなかゆがんだ構造だったので、trunk 直下には chrome/opera/firefox のディレクトリを置くようにし、ソース群は chrome/ へ移動した。すなわち、やはり基本的には chrome extension が前提の構造だ。opera/firefox については、シンボリックの参照先が trunk 直下から chrome/なんちゃらへ変わっただけだ。

それはそれでそれだけの話なのだけど、面倒なのは build.xml と、ビルドの際に必要なこまごまとしたシェルスクリプトで、通して見直さなければならないのであった。

めんどいなー!

 * * *

ぼちぼち Firefox 版の full review がなされる頃合になってきているが、どうもぐぐって見ると、amo 上でユーザーレビューが複数ないとそもそも full review してもらえないとか。現在 wasavi に対するユーザーレビューは 0 である。だめじゃん。まあそもそも full review に一発で通る気ではぜんぜんいないが、どうもまだ時期尚早だったようだ。うーんしばらくは preliminary reviewed の状態で更新したほうがいいのか?

evaluate a expression

以前 manifest v2 な chrome extension では、eval や new Function() が禁止されると書いたが、なぜか new Function() は動いていた。しかし今日通しでテストしてみたらいよいよ動かなくなった。chrome のバージョンは 21.0.1180.89m だ。

wasavi では eval は除去してあるが、未だメッセージ中の特定の単語を付随する数字に従って変化させる処理と :s の置換文字列を生成する処理で new Function() を使っている。いずれも小規模な一種の言語といってよいものであり、コンパイルと実行処理が必要になるわけだが、実際にコンパイラと実行マシンを書くわけではなく javascript の機能でまかなっていた。

これらが今回動かなくなったので、書き換える。

まず前者。適当なメッセージ内の単語が数値に付随するとき、その数値によって単語が変化するパターンを得る。たとえば英語の場合、数値が 1 のときとそれ以外の場合に分けられる。そのためパターンは 2 種類必要になる。

従来、メッセージカタログ内に “n==1?’one’:”” というような javascript の式を置いていた。これを実行時に new Function() で関数に変換・保持し、実行時にメッセージを要求されたときに適宜使用する。今回、new Function() が使えなくなったので、自前で式を解析して評価する仕組みにしないといけない。

といっても javascript の式を解析する処理を書くわけにも行かないので、もっと単純な式にする。

変換識別子列 := 変換識別子
変換識別子 , 変換識別子列
変換識別子 := 変換関数名 ( 変換パターン接尾子 )
変換関数名 := [a-zA-Z_][a-zA-Z0-9_]*
変換パターン接尾子 := [a-zA-Z_][a-zA-Z0-9_]*

というような単純な式を動的に評価し、変換識別子の配列を持っておき、実行するようにした。メッセージカタログに置く式は “is_one(one)” といった形になる。is_one という変換関数の実態は wasavi.js に定義しなければならないので、従来の方法だと新たに言語に対応する際もメッセージカタログの新設で済んだのが、wasavi.js の対応も必要になることになる。

次に後者。これは例えば :s/foo\(bar\+\)/FOO\u\1/g みたいな ex コマンドが与えられたとき、置換文字列から “return ‘foo’ + arg[1].substring(0, 1).toUpperCase() + arg[1].substring(1);” みたいな javascript の式を生成し(arg は正規表現にマッチした結果の配列)、関数を作り出す処理。これも動かなくなるので、やはり適当な中間形式にコンパイルし実行させるようにしなければならない。こちらは、コンパイラと実行マシンを書く手間のほかに実行効率が気になる。なにしろ置換が発生するたびに呼ばれるのだ。しかしそう言ってもいられないので修正した。

 * * *

最新のビルドをここで公開すると同時に、Chrome と Opera のエクステンションリポジトリに更新を申請した。

stable or unstable, that is the question

wasavi を Chrome、Opera、Firefox と各エクステンションの公式リポジトリへ登録してある。しかし、それと同時に、ここのサーバでもエクステンションのパッケージを野良 build として置いてある。

この 2 つのパッケージの関係は、ありがちなことに、公式 build が安定版、野良 build が最新だが安定性は保証しない版ということになる。

さて野良 build は今まで週一で更新してきたのだが、最近はさぼり気味だ。なぜか。現在 Firefox 版の wasavi は full review 待ちという状態である。full review がなされたとして、そのまますんなり通るとは考えていない。いろいろと指摘をされるだろう。そうすると当然修正するわけだが、そのときに関係ない機能追加とかがあると向こうのレビュアーを混乱させるだけである。なので、大掛かりなコードの改変はしにくいのだ。

もちろん wasavi はローカルでは Subversion で管理しているので、Firefox 公開版と trunk は別に管理することもできるが……実際面倒だ。

all tests are migrated to java

いろいろ近況。

  • 500 項目すべてのテストを java へ移行した。クリップボードアクセスなどコマンドが非同期で実行されるものもテストできるようになった。
  • ex コマンド入力時のショートカットを拡充した:
    • ^A, HOME: 行先頭へ
    • ^E, END: 行末尾へ
    • ^B, LEFT: 1文字左へ
    • ^F, RIGHT: 1文字右へ
    • ^H: カーソルの左の1文字削除
    • ^N, DOWN: 履歴を1つ進める
    • ^P, UP: 履歴を1つ戻る
    • ^U: 全文字削除
    • ^V: コントロールコード入力のためのプリフィクス
    • ^W: カーソルの左の1単語削除
    • DELETE: カーソルの右の1文字削除

    chromeでは一部のショートカットをスクリプトで制御できない。それには ^N や ^W も含まれる。

  • Firefox の full review は Queue Position: 46 of 113。
  • wasavi 終了時に、マークを寄生先 textarea へ保存するようにした。
  • 寄生先 textarea のサイズ変更にある程度追従するようにした。

watch a test

ググればたくさん情報は得られるが、とりあえずメモ。

junit でテストを書く際、今何のテストをしているのか……などのログを吐きたいことがある。例えば wasavi のテストで、何らかのミスがあって、WebDriverWait がタイムアウトするとする。タイムアウト自体は catch 節で受け取るので、そこで単に System.out.println(“timed out!”); すれば ant が保存するログに含まれる。が、どのテストで発生したかまではわからない。

そこで、テストケースで

@Test public void foo () {
System.out.println(Thread.currentThread().getStackTrace()[1].getMethodName());
}

などと書けばログにテスト中のメソッド名が書かれるので判別する材料になる。しかしこれはすべてのテストケースに埋め込まなければならないので、とても煩雑だ。

さて junit4 には TestWatcher というものが用意されていて、テスト開始・終了、あるいは成功時・失敗時に任意の処理をはさむことができる。開始・終了というのは @Before と @After と被っているが、これらはあくまでテスト視点での開始・終了なのに対して、TestWatcher のそれはテストランナーから見た、「テストメソッド」の開始・終了であり、テストメソッドの素性などのメタな情報を利用することができる。


import org.junit.*;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;

public class WasaviTest {
protected String logText;

@Rule public TestRule watcher = new TestWatcher() {
protected void starting (Description d) {
System.out.println("Testcase: " + d.getMethodName());
}
protected void failed (Throwable e, Description d) {
System.out.println(d.getMethodName() + " FAILED\n" + logText);
}
};

@After
public void tearDown () {
logText = driver.findElement(By.id("test-log")).getAttribute("value");
}
}

こんな感じで自前のテストの基底クラスに仕込んでおけば、これを継承した個々のテストでは何も考えることなく勝手にテストケースの名前が出力される。

くわしくは javadoc を見れば全部書いてある。

buffering key input

キー入力周りを書き直した。

wasavi は document に対して keydown、keypress 両方をリスンする。keydown では機能キー(esc、tab、backspace、enter、pageup、pagedown、home、end、insert、delete、F1 ~ F12 の入力を見る。keypress では文字を表すキーを見る。

機能キーは ctrl および shift 併用の入力は、併用しない入力とは別個のキー入力として扱う(が、:map に定義する展開パターンではまだモディファイアキーに対応してない)。一方文字キーは、特定の キーと同時に ctrl が押されていたらコントロールコードの入力とみなすほかは、ctrl も shift も無視する……これは、特に shift 併用した際にキーボードレイアウトがらみで判断が難しいからだ。難しいというより、無理だと思う。あくまで入力された文字そのものだけをみてどのコマンドにディスパッチするかを決める。

また、スムーズスクロール中のキー入力を今までは単に捨てていたのを、キューにバッファするようにした。スクロールが完了した直後にキューをすべて掃き出す。これによりテストがちょっと楽になる。

 * * *

ところで amo を覗いてみたら、wasavi の full review は Queue Position: 45 of 106 だった。おーけっこう進んでるー!

requested full review

Firefox の Add on は preliminary review と full review があって、前者はセキュリティに関する点など最低限の部分的なレビューをした後、限定的に公開される。preliminary review に通ってから 10 日ほどの待機期間みたいなのがあって、それが過ぎると full review を申請できるようになる。

というわけで、full review を申請した。

それにしても 8 月 17 日に preliminary review 申請、29 日に通過、9 月 6 日に full review 受付……ってなかなかのんびりしたペースだなあ。そして、full review 待ちのキューには現在 132 個の Add on が溜まっている(wasavi の位置は 133 of 134)。full review ひとつに付き 10 日くらいかかる。

何人がかりで full review してるのかはわからないが、いつ順番来るのこれ?

reply for gradius, behind

去年の 8 月に javascript、canvas、audio などを活用した html5 版 gradius を某掲示板にそっと公開したところ、なんか知らないがあれよあれよと拡散した。1 年経過した今、html5 gradius でググると、ブログでもそれなりに話題になっていたようなので 1 年越しに適当に返答してみる。

キーコンフィグの説明がPC88/X1版っぽくてニヤリとしますね。

17 才とちょっとのヤングなので偶然の一致です。88/X1 版はおろか msx 版も X68000 版も知りませんったら知りません。

マシン性能のせいかちょっともっさりしていましたが、
確かにグラディウスがでした。
公開しているのも元のグラディウスがを作っていたコナミのようです。

残念ながら違います。

個々のキャラクター(スプライト)をなめらかに動かすことと、方向キーとショットという入力に対してリアルタイムにレスポンスするようにプログラミングするのは、けっこう大変なノウハウを必要とするわけですが

そんな大したノウハウは必要ないです。

(はてブのウェジェットが貼ってある+ソースのクレジットから察するに作者は日本人??)

うーんそもそも海外の人にグラディウスってあんまり知名度高くないんじゃないですかね……?

HTML5版のグラディウス。 JavaScriptは全くの素人なのだけど、コードはすごく洗練されてると思う。 マジックナンバーが多くて難読ではあるのだけど。

javascript のコードの質としてはふつーだと思います。

システム開発でもゲームプログラマーのような能力が求められてくる。人材が二極化していくのではなかろうか?

よく分かりませんが、プログラマの質についての危機感のようなものは伝わってきました。

>HTML5で完全再現されたグラディウスとはなんだったのか
今やってみたが、回転処理が滑らか過ぎてニセモノ。

そもそも完全再現してないし、目指してもないんですが……。

ビッグコア出てくるときに何かSEが入るけど 原版でもあったっけ?

オリジナルにはないです。もったいないのでつけました。

マリオやらグラディウスやらは著作権的にどーなのかと突っ込みたいが。

はっはっはー(笑ってごまかす)。

そういうことが可能なように作られてんだから別にHTML5が凄いとは思わない

これはその通りです。25 年前のハードウェアでやってたことをブラウザで再現できるようになったねやったね、とそれだけのことですね。

asynchronous madness

Selenium でテストすると keypress イベントが発生したりしなかったりする件。

原因は wasavi 側にあった。G とはつまり指定の行へカーソルを移動させる vi コマンドだ。このとき、スクロールが発生するのだが(実際のビューのスクロール量が 0 であっても)、[cci]:set smooth[/cci] の状態だと、スクロールは非同期に行われる。すっかり忘れていた。スクロールが完了するまで、keydown 時に preventDefault() される。つまり、keypress は発生しない。

そして、G に後続するテスト用コマンドはまさにスクロールが完了するまでの狭間のタイミングに送信されていたのであった。こりゃーちゃんとテストできるわけないよ。

というわけで、G を送信した後はコマンドの実行が完了するまで待つことにして解決。

で、とりあえず、jsunit 版の基本編集のテスト editing.js の 51 テストを移植したのだけど。javascript のコードを java に移すというのは、メロンパンの中をくりぬいてメロンを詰め込むようななんともいえない気持ちになりますな。