Flapjaxチュートリアル

ようこそ!

ようこそ Flapjax へ! このチュートリアルは、抽象的な概念を具体的なコードと結びつけるためのものです。 クライアントサイドのみのプログラミングの議論から始めて、 サードパーティのサーバーからデータを取得する方法を説明し、 最後にFlapjaxサーバーにデータを保存することを議論します。

このチュートリアルは、デモへのリンクを含んでいます。ただデモを実行するだけでなく、 そのソースを読むことをお勧めします。デモは、あなたが勉強しやすいように、 できるだけきれいでお見やすいコードになるように努力しました。 さらに、チュートリアルに含まれるサンプルを、自分自身で 実行してみることで、 チュートリアルを最大限に理解することができるでしょう。

最後にもう一度。ようこそ Flapjax へ。 お座席のシートベルトをお締めください!

「ビヘイビア(Behavior)」を導入する

Flapjaxでプログラムをはじめるのにもっとも簡単な方法は、 テンプレート構文を使うことです。テンプレート構文は、Flapjaxのコードを HTMLページに埋め込むものです。簡単なサンプルを次に挙げます。

<p>
The time is {! timer_b(100) !}.
</p>

このコード断片は、{!("curly-bang"と呼びます)と !}の間にFlapjaxの式が記述されています。 この式の文法は、JavaScriptに非常によく似ていますが、それは偶然ではありません。 FlapjaxはJavaScriptと文法を共有しています。だから、これが何を意味するのかは はっきりとは分からなくても、なんとなく推論することはできるでしょう。 timer_bは、おそらく現在のシステム時間を返す関数ではないか。 そうならば、このページはおそらくページがロードされたときのシステム時刻を 表示するのではないか。それではプログラムを実行して確認してみてください。

うまく表示されましたか? 現在のシステム時間がただ表示されていたのではなく、 その時間はすばやく増加していたはずです。関数timer_bは、ビヘイビア(Behavior)という、 時間の経過とともに変化する値を作り出しているのです。 ビヘイビアはFlapjaxの中心的な機構です。このチュートリアルの最初のパートでは、 このビヘイビアについてもう少し学びたいと思います。

サンプルに戻りましょう。timer_b(100)の式は、 100ミリ秒ごとに(つまり、1秒に10回)値を返すタイマービヘイビアを作成します。 しかし、返ってくる値はミリ秒の値で、余分な数字があるせいで、タイマーは 狂ったように表示を更新しているように見えます。そこで、表示を滑らかに するために、値を1000で割ることにしましょう。

<p>
The time in seconds is {! Math.floor(timer_b(100) / 1000) !}.
</p>

まず、実行してみてください。 表示されましたか? 表示される値は、穏やかに1秒に1回更新されています。

これがこのサンプルの面白いところです。割り算とfloor演算はタイマーが 新しい値になるたびに実行されました! プログラムに再計算するように指示 する必要はありませんでした。timer_bの値が変わったら、 自動的に変化に気付いて残りの計算が行われ、表示が更新されたのです。 言い換えれば、timer_b(100)の値が時間とともに変わった だけでなく、timer_b(100) / 1000の値と、 その結果、Math.floor(timer_b(100) / 1000)の値も 時間とともに代わったのです。 このことは、重要なルールを示しています。つまり、もし、式がビヘイビアであれば、 その値に依存するすべての式もまた、ビヘイビアになります。このような、 ビヘイビアの値の自動的な更新は、Flapjaxの中心となる機構です。

実際には、すべての式をHTML文書の中に書く必要はありません。 もっと複雑な式は、scriptタグの中に書いてもいいですし、 またそうすべきです。それらの式には、後で参照することができるように名前を つけます。次のサンプルを見てください。

<script type="text/flapjax">
var timerB = timer_b(100);
var secondsB = Math.floor(timerB / 1000);
var secsModTenB = Math.floor(secondsB % 10);
</script>

このスクリプトヘッダーを書くことで、FlapjaxコンパイラはこれがFlapjax言語 のスクリプトであることを認識します。コンパイラは、これをJavaScriptコード に変換します。そうすることで、標準的なブラウザで何のプラグインも使わずに 実行することができるようになります。ビヘイビアを使っている部分だけを除くと、 この定義は普通のJavaScriptのコードによく似ていることに注意してください。

このような定義を作ることで、それをページの中で使うことができるようになります。 たとえば、現在のシステム時刻が、秒単位で偶数か奇数かを確認することができます。

<p>
The current system time is {! ((secondsB % 2 === 0) ? "even" : "odd") !}.
</p>

あるいは、別のJavaScriptのscriptタグの中で、arrayToString関数を定義したとします。すると、Flapjaxの中でビヘイビアに対して その関数を適用することができます。

<p>
The list of time modulo 10 elements is
  {! arrayToString(oneToN(secsModTenB)) !}.
</p>

もう一度、 実行してみてくださいarrayToString関数が、 JavaScriptでかかれているにもかかわらず、自動的にビヘイビアに対して適用され、 正しく実行されていることに注意してください。つまり、時間が秒単位で変わる ごとに、新しい配列が再計算されます。 このように、JavaScriptで書かれた関数がビヘイビアに対して適用されるプロセスを リフティング(Lifting)と呼びます。これは、関数を、JavaScript の値を操作するところから、Flapjaxビヘイビアを操作するところに、"持ち上げる(lift)" ところから名づけられました。 Flapjaxコンパイラは、リフティングを自動的に実行します。そのため、プログラマは それと直面しなければならないことは、たとえゼロでないとしても、めったに そのようなことにはなりません。しかし、もしFlapjaxを単にJavaScriptの ライブラリとして扱う場合は(Flapjaxはそのようなモードもサポートします)、 自分自身でリフティングを明示的に実行しなければなりません。

このビヘイビアの紹介で使ったサンプルを使うときは、法律的な次の2つの点に注意してください。 一つ目は、あなたのWebページでこのようなタイマーを無意味に表示するような 行動に飛びついてはいけません。そのようなことが、1990年代からJavaScriptの もっともよくない使い方と考えられていたことを思い出してください。 そのようなことは、あなたのサイトの評判を悪くするでしょう。 二つ目は、このチュートリアルのサンプルは、プログラムを走らせる際の ページ全体の一部の抜粋でしかないことです。欠けている部分には、あなたが 書かなければならないコードや、書いた方がよいコードが 含まれています。書かなければいけないコードは、正しいWebページを作って Flapjaxライブラリを読み込む部分です。書いた方がいいコードは、ブラウザが JavaScriptを無効にしている(あるいはサポートしていない)場合に、意味のある メッセージを表示する部分です。これらの詳細を理解するために、注釈つきの バージョンのデモを読むことをお勧めします。

ここまで読んだら、がんばってこの先を読みつづけてもいいですし、読むのをやめて 自分自身のFlapjaxのページを作ってもよいです。私たちとしては後者の方を お勧めします。プログラミング言語の楽しさは、それを使って実際にプログラムを 書くことができるところにあると思うからです。チュートリアルのサンプルが もっと難しくなると、提供しているサンプルを見るだけでなく、サンプルをいじって 変更がどのような影響を与えるかをみることができることは、(特に不満がたまってきた 場合には)手助けになるでしょう。

ビヘイビアによって内容を変化させる

マウスの位置について考えてみます。マウスがあればその値は存在し、その値は 変化しつづけています。マウスの現在の位置に依存したものを何か作るような プログラムを書くならば、マウスが動くたびにそれを更新したいと思います。 幸運なことに、Flapjaxの別のビルトインのビヘイビアにマウスの位置に関するものが あるため、これは簡単に実現できます。

マウスの現在の位置にテキストボックスを表示するサンプルを示します。 コードはちょっとごちゃごちゃしているように見えますが、一度確認すれば 実際には非常にシンプルだと分かります。

<div id="themouse" 
  style={! {color: '#FFFFFF', 
            backgroundColor: '#000000',
            position: 'absolute',
            left: mouseLeft_b(document),
            top: mouseTop_b(document),
            padding: '10px'} !}>
the mouse
</div>

これは、div要素を作って、そのスタイルを設定しています。 もっとも重要な属性は、left属性とtop属性で、マウスの位置が設定されます。Flapjaxはそれをビヘイビアとして提供しているので、 スタイルの設定値は自動的に更新され、テキストボックスはマウスの後をついてきます。 実際にマウスを動かして試してみてください

上のサンプルは、Flapjaxコンパイラに実装されている便利構文が使われています。 デリミターの中で、式は{ ... }の形で書かれています。 この文法は、JavaScriptのリテラルオブジェクトを生成します。 オブジェクトは、単に名前から値へのマッピングを集めたもので、HTMLのスタイル もまた、名前から値へのマッピングの単なる集合なのです。 Flapjaxの式が評価されてオブジェクトになるとき、デリミタは自動的にオブジェクトを CSSの属性値表記を使った文脈につなぎあわせます。この短縮記法は、 ビヘイビアを含むオブジェクトを定義したり、それを使ってページのエンティティの スタイル属性を操作したりするのに特別に便利です。(Flapjaxの式は評価した結果オブジェクトになることも可能です。上のサンプルは、式自体が文法的にオブジェクトであるような特殊例であることを、注記しておきます。)

では、このサンプルをもう少し複雑にしてみましょう。マウスに何かしらの尻尾が ついているとして、尻尾がマウスに追いつくのには少し時間がかかると考えてください。 つまり、尻尾の現在の位置は、マウスが少し前にあった場所になります。 言い換えれば、尻尾の位置は、マウスの位置の遅延(delayed)バージョンなのです。 これは、Flapjaxで簡単に表現できます。

<div id="tail" 
  style={! {color: '#FF0000', 
            backgroundColor: '#000000',
            position: 'absolute',
            left: delay_b(mouseLeft_b(document), DELAY) + $('themouse').offsetWidth,
            top: delay_b(mouseTop_b(document), DELAY),
            padding: '10px'} !}>
its tail!
</div>

中心となっている式は、次のところです。

delay_b(mouseLeft_b(document), DELAY) + $('themouse').offsetWidth

左の部分式は、マウスの左位置の値を、DELAYで 与えられた定数分だけ遅延させた新しいビヘイビアを生成します。 右の部分式は、現在のページのCSS IDがthemouseであるオブジェクトを参照して、その幅を計算します。これらの和が、 新しい横方向のマウスの位置になります。マウスの尻尾が追いかけてくる様子を見てください

今度はあなたが、もっと複雑なサンプルを書いてみてください。たとえば、 尻尾の別の部分を作って、マウスを追いかけるだけでなく、尻尾を振る動作を 加えてみてください。(ねずみは尻尾を振るのでしょうか? 実は知りません。 仕事中にちょっと調べた限りでは、結論は出ませんでした。)うまくいかなくても、 その取り組みから学ぶことがあるはずです。終わった後は、すべてのコードを 確認してください

私たちの顧問弁護士がしつこいので、もう一度言います。無意味にWebページに このような振る舞いをさせると迷惑です。だから、必要なときと、ユーザを 迷惑がらせたいとき以外は、このサンプルを使うのはやめてください。

内容をビヘイビアとして反映させる

これまで、ページの内容がビヘイビアにどのように依存して、ビヘイビアの値 の変化に合わせて更新されるかを見てきました。今度はちょっと違う角度に進んでみます。 ページの内容に依存したビヘイビアを作って、ページの内容が変わったら、 それにあわせてビヘイビアの値も変わるようにしましょう。(もし、ページの別の 部分がそのビヘイビアに依存していたら、その部分も更新されますし、 さらに別の部分がそこに依存していたら、さらに先まで伝播します。)

フォームを作ることを考えましょう。そこに内容がぴったり3文字の長さで なければならないフィールドが含まれるとします。フィールドの枠線の色で、 内容がその制限を満たしているかどうかがわかると素敵です。 注目すべき点は、制限が満たされているかということは(それは論理値で表されますが)、 現在のフォームのフィールドの内容に依存して変化し、また、その論理値に依存して フィールドの枠線の色が変化するという点です。これらのことをすべてビヘイビアとして 表現することで、Flapjaxは自動的にそれらの間の依存関係を調整します。

まず、これがフィールドを表示するHTMLページの断片です。

Enter a 3 character string: <input id="textField1"/>

ここでやりたいことは、フィールドの長さが正しいかどうかによって、inputフィールドのborder color属性を変更することです。 extractValue_b関数は、ページの要素の値をビヘイビアに 変換します。この便利な関数を使って、背景色を決める式は次のようになります。

(extractValue_b('textField1').length === 3 ? 'green' : 'red')

残りは、このビヘイビアを使ってborder color属性を設定することです。

Enter a 3 character string:
  <input id="textField1"
            style={! {borderColor: (extractValue_b('textField1').length === 3 ? 'green' : 'red')} !}/>

このようなインライン表現は、常に望ましいわけではありませんし、 常に可能なわけでもありません。

  • 望ましくないようになる場合の理由は、そのような表現は、表現とビヘイビアが 混ざり合って、ページが散らかってしまうことです。値のチェックをするコードは scriptタグの中に移動して、ページのHTMLの部分は スクリプトでいっぱいにならないようにする方が望ましいことがよくあります。 実際、Flapjaxはページ要素をビヘイビアに変換する機能があるため、HTMLを 変更することなく、スクリプトを名前つきのidに 遡及的に付け加えていくことは簡単です。 このような控えめな(unobtrusive) JavaScriptを採用する戦略を推奨する 人もいます。もしあなたがバズワードに飢えているなら、この戦略を アスペクト指向プログラミングの一種として考えることも可能です。 Flapjaxスクリプトは、ページにアドバイスを関連付けていて、 ページはFlapjaxの存在に気付いていない(oblivious)と言えます。 しかし、このチュートリアルでは、できるだけ平易な表現で説明をするように したいと思います。
  • 可能でなくなる場合の理由は、すべての制約がローカルでない場合です。上の サンプルでは、入力フィールドの制約はその長さだけでした。しかし、もっと 複雑なフォームでは、制約は階層的であったり相互依存的であることさえあります。 そのようなケースでは、スクリプトをscriptタグに 移すことが強く推奨されます。そのようにすることで、チェックコードの 中から共通部分を抽出した関数を定義することも可能になるかもしれません。 (たとえば、適切な比較関数を使って文字列の長さをチェックするなどです)
それでは、これらの概念を実演する長いサンプル見てください。

もしあなたがJavaScriptでプログラミングした経験があるなら、Flapjaxを使った プログラム(Flapjaxの文法でも、生のJavaScriptの文法でもどちらでも)と、 同じことをコールバックだけを使って作ったプログラムを比べてみると、 勉強になるでしょう。

Intermezzo: 表計算を進化させる

私たちはいろいろな観客にの要求を満たさなければならないため、時々脱線して、 もっと概念的な問題を説明します。どこで脱線した話をしているかがすぐに 分かるように、(このセクションのように)intermezzoというラベルをつけた 別のセクションを作ります。あなたが必要なのはFlapjaxのプログラミングの 核心部分だけなら、これらの脱線部分を無視してもかまいません。しかし、 他のプログラミングのトピックとどのように関係しているかを理解したければ、 これらの脱線が役に立つでしょう。もちろん、最初に読むときにはintermezzoを 読み飛ばして、後で戻ってきて読んでもまったくかまいません。

表計算はいいアイデアです。行と列に配置された数字を一日中ガチャガチャと 処理するのが楽しいと言っているのではなくて、セルの間に依存関係を表現して 自動的にそれらの依存関係を伝播する"重いリフティング"を実行するところを 言っています。ある意味では、表計算は、宣言的プログラミング言語の究極の 形態でありながら、宗教的なカルトとは無関係なものであるということができます。

ビヘイビアは、本質的には、表計算モデルの自然な拡張であるといえます。 これは2つの点を一般化したものであると考えられます。

  1. 単に数字とわずかで貧弱なデータ型しか扱えなかったところを、 どんなデータ型でもプログラムできるようにしました。
  2. すべてをグリッドで表現したり、スケールしない命名規約を使ったりする必要が なくなりました。代わりに、式Bが式Aの部分式であれば(これは、Bがメソッドの 引数で、Aがメソッド呼び出しであったり、Aが呼び出すメソッド自体にBが含まれる 場合も含みます)、AがBの値に依存すると判断します。 式に名前を付ける必要があれば、JavaScriptの名前付けの力を利用することができます。 これは、変数名だけでなく、配列のインデックスやオブジェクトのフィールドや その他のさまざまなものを含みます。やりたいことにマッチするものをどれでも 選ぶことができます。
つまり、ビヘイビアは今でも、依存性を表現して、値の変更を伝播する仕組みを 与える、表計算の鋳型の中にあるのです。ほとんどの表計算のように、Flapjaxは 無駄な計算を避ける最適化を行っています。しかしほとんどの表計算とは違い、 Flapjaxは相互参照を含むきわめて複雑な依存関係を取り扱う仕組みを持っています。 (相互参照は、視覚的なユーザーインターフェースのプログラミングを行う上で たびたび発生します)

すると、ひとつの見方として、Flapjaxは深い理由なく対立していた2つの重要な プログラミングスタイルの間を調停しようとしていると考えることができます。 それは、宣言的プログラミングと命令的プログラミングです。命令的プログラミング は、時に、必要以上に帳簿を管理するような面倒な作業をプログラマに押し付ける ところがありました。プログラマがそれに失敗すると、プログラムは不整合性に 起因するエラーを発生させることになります。一方、伝統的な宣言的プログラミングは プログラマに拘束服を着させて、現実の世界のデータやシステムに存在する 命令的な影響を無視することを強制させることがありました。 これら両方とは違い、Flapjaxは完全に命令的な更新処理を受け入れます。ビヘイビアは 完全に命令的な更新処理の存在の上に構築されたものだからです。しかし、プログラマは システムを宣言的に記述することができます。値の変更を伝播させる面倒な作業は、 宣言的な仕様を記述するだけでプログラミング言語に押し付けることができるのです。 簡単に言えば、Flapjaxは、命令的なデータに対する宣言的な仕様記述 を行うことがやりやすい言語なのです。

離散的なストリーム

時間、マウスの位置、フィールドの内容。これらすべては連続的な (どの瞬間にも値が存在する)値でした。そのようなものに対してするべきことは、 観察の間に値が変化するので、その値に依存するすべての式は、システムを整合的な 状態に保つためにそれぞれの値を更新しなければならないということだけです。 Flapjaxはその値の更新を自動化します。これがビヘイビアの本質的なことです。

では、次の現象を考えてみてください。マウスのクリックやキーボードの打鍵や ネットワークパケットの到着などです。これらは離散的です。時間の中で、 値はいくつあってもかまいません。無限にあるかもしれません。しかし、値は 観察したときには到着していないかもしれません。実際、値は二度と到着しないかも 知れません(たとえば、ケーブルの接続が切れてしまった場合など)。これは 本質的に外部デバイスの典型的な通信パターンです。

それらは離散的なので、そして、必ずしも"現在の"値が存在するとは限らないので、 このような現象に対しては、ビヘイビアは十分な表現力を持っていません。 ポーリングのような手段を用いるのは、システムを無期限に停止させてしまう 可能性があるのでやりたくありません。代わりに、この離散的なストリームに 新しい値が到着したら、残りのシステムの計算を促して、依存性を更新し、 システムを整合的に保つようにします。Flapjaxでは、このようなストリームを イベントストリームと呼びます。

イベントストリームを使ったプログラミングは、ビヘイビアを使ったプログラミング とは少し異なります。ビヘイビアは普通のJavaScriptのオブジェクトのような見た目で、 値の変更が自動的に取り扱われるだけのものでした。しかし、イベントストリームは 新しい種類の値で、新しいプリミティブを使ってプログラミングする必要があります。

まずは、非常に簡単なサンプルからはじめましょう。入力ボックスが与えられて、 その入力ボックスの中の文字列の長さを出力するプログラムを書きます。 これをビヘイビアを使って書くこともできますが、キーボードの打鍵をイベントとして 考えることも概念的にすっきりしています。イベントが起きたときだけ、 文字列の長さを更新するのです。まず、テキストボックスを作りましょう。

Text buffer: <input type="text" id="toLength"></input>

プログラムは、extractValue_e関数を使って、 テキストボックスに関連するすべてのイベントを反映するイベントストリームを 作成します。(実際には、このストリームは打鍵だけでなく、タブの入力や その他のイベントも含みます。extractValue_e関数 は、イベントの種類を限定するための追加の引数をとることができます。) このイベントストリームを、長さを示す文字列のストリームに変換します。

<p>
Length: {! extractValue_e('toLength').transform(
             function (s) {return s.length; }) !}
<p>

transformメソッドは、入力のイベントストリームから 値を受け取って、与えられた関数を適用し、その結果をイベントストリームとして 出力することを繰り返すものです。このケースでは、toLength要素の文字列をイベントストリームとして受け取り、文字列の長さを ストリームとして出力しています。

2つ目のサンプルは、テキストボックスを用意して、ボックスの内容を原稿として 保存します。これには、保存先のサーバーが必要です。いまはクライアントサイド のプログラミングだけを説明しています(もう少ししたらサーバーの話をします) ので、今のうちはクライアントサイドの機能についてどのようにプログラムを書くか という点に焦点を絞ります。Webページは適すとぼっくを持っていて、原稿を 保存するtためのボタンがあり、いつ原稿を"保存した"かを示す場所があります。

Last Saved: <span id='savedTime'></span>

<form>
<textarea id='theText'></textarea> <br>
<input type='button' id='saveButton' value='Save Now'></input>
</form>

ユーザーがボタンをクリックするごとに、表示する時間を更新します(そして、 将来のバージョンでは、テキストボックスの内容をサーバーに保存します)。 まず、ページの中の別々のDOMオブジェクトを参照する変数を作ります。(接尾辞 'D'は、これがDOMオブジェクトへの参照であることを思い出す助けになります)

<script type="text/flapjax">
var textD = $('theText');
var saveD = $('saveButton');
var savedTimeD = $('savedTime');
...
</script>

さて、ボタンクリックのイベントストリームを抽出して、クリックがあるごとに 保存した時間を更新するようにします。

var saveClickE = extractEvent_e(saveD, 'click');
var savedTimeE = saveClickE.transform(getTime);
insertValueE(savedTimeE, savedTimeD, 'textContent');

ここで、getTime関数は、JavaScriptの関数です。

<script type="text/javascript">
var getTime = function (_) {
  var date = new Date();
  return date.toLocaleString();}
</script>

どのように動くか見てください。 あまり満足できない感じがするのではないでしょうか。ユーザーがボタンを クリックするときに原稿を登録するだけで、ユーザーが作業に没頭して、 ボタンをクリックすることを忘れたら、原稿を失ってしまいます。 代わりに、タイマーを使って、定期的に原稿を保存するようにしましょう。

var autoSaveE = timer_e(100);
var savedTimeE = autoSaveE.transform(getTime);
insertValueE(savedTimeE, savedTimeD, 'textContent');

これはだいぶよくなりましたが、まだ不十分です。自動保存はタイマーが発火した 時だけしか起こりません。本当にやりたいことは、ユーザーがクリックした 時とタイマーが発火したときの両方で保存を行いたいのです。つまり、 タイマーのイベントストリームとユーザーのクリックのイベントストリームが 与えられたら、それをマージして、統合したトリガーを作って原稿を保存するように したいのです。これが、Flapjaxのmerge_e関数が まさに行うことです。

var saveClickE = extractEvent_e(saveD, 'click');
var autoSaveE = timer_e(10000);
var saveE = merge_e(saveClickE, autoSaveE);
var savedTimeE = saveE.transform(getTime);
insertValueE(savedTimeE, savedTimeD, 'textContent');

コード全文を見て、 どうなっているのかを確認してください。

Intermezzo: ビヘイビアとイベントストリームを比較する

イベントストリームとビヘイビアは、世界に対する補完的な見方を与えるものです。 その違いは、大げさに語られがちですが、適当な初期値を与えることで、 イベントストリームはそれをビヘイビアに変換することができます。 ビヘイビアは常にストリームから受け取った最新のイベントの値を持つようにし、 最初のイベントが届くまでは、最初に与えられた初期値を持つようにすればよいのです。 同様に、すべてのビヘイビアはイベントストリームに変換することができます。 ビヘイビアの値が変化したときに、新しい値をイベントとして送るようにします。 この変換は、Flapjaxが提供するプリミティブであるhold関数とchanges関数をそれぞれ使うことで、 簡単に実現できます。(これらはこの2つを変換する唯一の方法というわけではなく、 もっとも自然な方法であるだけです)

ビヘイビアかイベントストリームのどちらかのほうがより自然に考えられるものも ありますが、どちらを使ってもよくて、文脈によって選ぶような場合もあります。 経験的には、ビヘイビアは内部的な状態を表現して、 2つの値の間の依存関係の計算があまり長くならないような場合に 適しているように思われます。 それに対し、状態が何らかの外部的な媒体に存在する場合、計算経路が予測できない 公算があるため、イベントストリームを使うのが適切と思われます。 同様に、計算が非常に長くかかって、タイムアウト処理を実装する方がよい ような場合には、イベントストリームとタイムアウトビヘイビアをマージする ほうがよいです。ちょうど原稿保存のサンプルで見たような感じです。

ドット記法

前に、次のようなプログラムを説明しました。

(extractValue_b('textField1').length === 3 ? 'green' : 'red')

この断片は実際には小さな手品が含まれています。.lengthを使っているところに注意してください。extractValue_b関数の結果を、普通のオブジェクトのように取り扱って、lengthフィールドにアクセスしています。これはFlapjaxでまったく文法的に正しいだけでなく、 期待したように動作します。extractValue_b('textField1').lengthの式全体の値は、各時点時点での指し示す要素の長さとして定義されます。 つまり、その値は要素の内容が更新されるたびに更新されます。

これはビヘイビアだけでなくイベントストリームに対しても同様です。 間違いなく、イベントストリームの場合はもっと便利になります。というのは、 これによってtransform関数を書く必要がなくなることが あるからです。テキストバッファーを表示して、そこに書かれた文字列の長さを 出力する簡単なプログラムを考えます。まず、ページを作成します。

<p>Text buffer: <input type="text" id="toCount"></input></p>
<p id="result">Start Typing!</p>

それではFlapjaxのコードを書きましょう。最初のコードは普通に書きます。

var valE = extractValue_e('toCount', 'value');

valueはどのイベントを抽出するかを支持しています。 これで、値の変更に関してのみ通知されるようになります。それでは、 ビヘイビアにしたのと同じように、"ドット記法"をイベントに対して使ってみましょう。

insertDomE('length: ' + valE.length, 'result');	

これもまた、期待したとおりに、自動的にtransform関数を適用します。それではデモを見てください

静的初期化処理

デモプロ不ラムを見て気付いたかもしれませんが、|||(super-orと読みます)という記法を時々使っています。これは、{!!}のデリミタと関連しています。 super-orの左に現れるものはすべてFlapjaxのコードです。しかし、このプログラムを 呼び出すまでに何かのイベントが必要なため、super-orの右の値がHTMLの最初の値 となります。これを静的初期化子と呼びます。

静的初期化子は、特に、プログラマがいつ最初のイベントが発生するかが予測できない ようなイベントストリームを使うときに重要ですが、ビヘイビアを使う場合に 使うのも上手い場合があります。ページのコードが実行されるまでにちょっとの 間があることがあります。しかしもっと考えられることは、数秒たっても ビヘイビアの値に静的初期化子が現れる場合は、何か問題があることを示している ことがあります。つまり、JavaScriptが無効になっていたり、ライブラリが ロードされていなかったり、プログラムがエラーを起こしていたりすることです。

明らかに、静的初期化子はテンプレート構文と関係ないところにも存在する 言語的な概念です。すべてのイベントストリームは、startsWithメソッドをサポートしていて、プログラマが静的初期値を与えることができるように なっています。

Intermezzo: コールバックはどこにいったのでしょう?

あなたがJavaScriptやGUIツールキットを使った経験があって、このチュートリアルの サンプルに注意を払っていたら、重要なものが存在していないことに気付いた に違いありません。つまり、コールバックです! コールバックはほとんどの伝統的な 対話的なプログラムやイベントドリブンのプログラムでの土台となっていましたが、 Flapjaxのスタイルではまったく現れないようです。なぜでしょう?

ほとんどのプログラムは、入力(場合によっては無限ストリームである)を消費して、 対応する出力を生成する、つまり出力が入力に依存するところをブラックボックス として考えられると便利です。しかし、コールバックは、システムの中の アプリケーション依存な部分から呼び出されるので、自然な依存関係 の順序とは逆になってしまいます。 この問題は、静的型宣言のある言語で見る方がより分かりやすいです。 コールバックはアプリケーション非依存なフレームワークから呼び出されるため、 何も値を返すことはできません。(できたとしても、汎用的なステータスコードだけです。) 結果として、コールバックは他のアプリケーション独自のメソッドと組み合わせる ことができないものになります。そのようなことで、命令的な更新処理やその他の 命令的な作用を使うことが、たとえそれが概念的に必要ないものであっても、 強制させられます。

それでも、まだコールバックの価値はあります。第一に、データ駆動スタイルの プログラムを可能にするためです。出力処理が絶えず入力のデータをポーリング する代わりに、入力処理が新しいデータを用意して、新しい出力を生み出すまで、 システムを眠らせておくことができます。この利点を生かすために、Flapjaxは ポーリングではなくプッシングによって更新処理を評価します。

要約すると、コールバックは非常に便利なプログラミングの機構で、プログラミング の上で非常に有効な手段ですが、しばしば重要なプログラムの構造の詳細を あいまいにしてしまうことがあります。そのため、Flapjaxのプログラミングスタイル では、できるだけコールバックを使うことを避けるようにしています。 一度試してみることをお勧めします。 このスタイルは、あなたにプログラムの構造について考え直させることがあります。 しかし、命令的な操作を考えることを少なくして、その背後にあるデータモデル についてより注目するように絶えず仕向けるでしょう。データの間の関係について もっと熱心に考えることで、より宣言的な仕様記述を行い、整合性を保つための 労力をより言語処理系に任せるようになります。怠慢であれ、ラリー・ウォールと ランダル・L・シュワルツが"プログラマの3大美徳"の1つとして言った言葉の とおりです。

外部サーバーのデータにアクセスする

JavaScriptのセキュリティモデルは、リモートプロシージャーコール(RPC) のリクエストを自分自身のページが生成されたサイト以外のサイトに送ることを 許可しません。このため、他のサイトからデータを読み込むことが難しくなります。

この欠点を回避するためのさまざまな技術が、これまで提案されてきました。 よくある技術は、次に述べるような観察に基づいています。他の ホストにRPCリクエストを送信できなくても、JavaScriptのscriptタグの中身を読み込むことはできます。結果得られたJavaScript は、ページの他のコードと一緒に評価されることになります。このスクリプトは、 たとえば、ダウンロードしようとしているデータを定義しているだけのもので あってもよいのです。例として、del.icio.usの サイトでは、数に制限を設けて、ブックマークをその形式で提供しています。

この操作を実行するコードを書くのは、骨が折れます。まずスクリプトを作成し、 リモートサイトへの参照を挿入し、データがダウンロードされるのを待ち、 結果データを抽出しなければなりません。スクリプトがその中で結果を使われていない 変数に割り当てたら、値を取得した後に名前空間からその変数を削除したいと 考えるかもしれません。もしページがインタラクティブなら、これらすべてを 一連の流れで行う必要があるでしょう。そこで、Flapjaxはこの振る舞いを実装する プリミティブを提供します。このプリミティブはイベントストリームに対しても 適用できます(当たり前)。

具体的に、del.icio.usのサンプルを考えてみましょう。del.icio.usのユーザーの ユーザー名を含む特別なURLに接続して、JavaScriptコードをダウンロードします。 それを実行すると、Deliciousという変数にそのユーザー のブックマークの一部を割り当てます。この機構に対するFlapjaxのインターフェース は、evalForeignScriptVal_e関数です。これは リクエストのイベントストリームを消費します。userNameがdel.icio.usのユーザー名を入力するフィールドだとしましょう。

var userNameChangeE = extractValue_e('userName');

var deliciousUserLinksE = 
  evalForeignScriptVal_e(
    {'url': 'http://del.icio.us/feeds/json/' + userNameChangeE,
     'globalArg': 'Delicious'});

新しいユーザー名が入力されるたびに、イベントストリームに新しい値が供給され、 それが新しいリモートサイトコールが繰り返されます。そのたびに、Flapjax関数は、 名前つきのグローバル引数(この場合はDelicious) に割り当てられた値を抽出して返します。プログラムを 動かしてみてください

イベントストリームは、このFlapjaxの関数の自然な引数であることを観察してください。 イベントストリームとビヘイビアは交換可能ではあるのですが、外部のWebサイト に接続することは、連続的な処理であるというより離散的なものと考えるほうが 分かりやすいです。そのため、フィールドの値はビヘイビアとして考える方が自然で あっても、外部サイトに接続するのは値が変わったときだけにしたいと 思います。実際、evalForeignScriptVal関数に イベントストリームの代わりにビヘイビアを消費させた場合にどういう意味になるのか、 あるいは少なくともその処理の中でどのように振舞えばインターネットでの よい市民でいられるかということが、単にはっきりしていません。

インターネットには間断なくつながっているわけではないですが、それでも変更が あるたびに接続しています。そのため、すこしギクシャクしたな反応になったり、あまり 興味のないユーザー名のブックマークを取得してしまったりするかもしれません。 むしろ、ユーザーの操作がとまったときにだけ接続をする方がより自然です。 FlapjaxがfilterRepeats_e関数とcalm_e関数という2つの便利な関数をこのために提供することで、 十分に有用な構成になります。最初の関数はイベントストリームの中の重複を 取り除きます。後の関数は期間(duration)を示す追加の引数をとり、その期間の 間新しいイベントが発生しなかった場合に、最新のイベントを発生させます。 これらをいっしょに使ったサンプルを見てください。

var deliciousUserLinksE = 
  evalForeignScriptVal_e(
    {'url': 'http://del.icio.us/feeds/json/' +
            calm_e(filterRepeats_e(userNameChangeE), 450),
     'globalArg': 'Delicious'});

修正したプログラムを 動かしてみてください

これはまったくちょっとした遊びであって、強く警告することはできませんが、 任意のWebサイトからコードをダウンロードして、まさにあなたのブラウザの中で それを実行しているのです!(このことをあなたに伝えるのに、わざわざ弁護士を 介する必要はありません。ちょっと考えるだけで、私たちが弁護士になるのに 十分です。)あなたがリモートサイトを信頼できるだけの十分な理由を持つまでは、 本当に本当に絶対にこういうことを行ってはいけません。信頼できる場合でも、 生成されているコードを注意深く調査する必要があります。そして、定期的に 検査を行うようにしなければいけません。なぜなら、望ましくない変更が加えられる かも知れないからです。さらに、そのような注意を払っても、古典的な教育は バートランド・ラッセルの鶏を忘れないようにすることをあなたに教えています。

これはすべてではありません。Flapjaxは、Webサービスをプログラムで取り扱うもっと多くの 方法を提供しています。Yaggleを見てください。これは、クライアントサイドのマッシュアップで、 Yahoo!の地域サービスの電話帳とGoogle mapの機能を掛け合わせたものです。 このマッシュアップのキーは、FlapjaxのプリミティブのgetWebServiceObject_e関数で、サービスの呼び出しに加えて、XMLの応答 を解析してJSONの形式に変換するプロセスを単純化するものです。

サーバーサイド永続性

原稿サーバーに戻りましょう。明らかに、このサンプルは本物のサーバーに原稿を保存できて 後からそのデータいアクセスできるときにだけ、意味があります。 Flapjaxはデータを保存するサーバーを提供しています! このサーバーは、Flapjaxの 値を概念的に保存するため、その値にアクセスするすべてのクライアントに、変更を 自動的に伝播します。(もちろん実際には、Webでそのようなインターフェースを実装する のは難しいため、クライアントがサーバーをポーリングすることで実現しています。 Webの標準が進化するにつれて、Flapjaxはプログラマのあなたがコードを書き直さなくても、 新しい技術を使った方式を取り入れていきます。)

値を永続的にするためには、次の3つのことを決めなければなりません。 1つ目には、ファイル名のような感じに、サーバー上で値を保管する場所を 決めなければなりません。2つ目には、どのように値を初期化して、サーバーから 読み込みたいかを決めなければなりません。3つ目には、どのように変更を サーバーに書き込むかを決める必要があります。この区別は非常に柔軟で、 必要に応じてさまざまな範囲のポリシーを実装することができます。

具体的に見ていきます。原稿がtheTextと ラベルがつけられた要素に格納されていたことを思い出してください。 原稿を最後に編集した時の内容で初期化したいと思います。次を見てください。

<textarea id='theText'
          value={! readPersistentObject({path: ['draftFT'], 
                                          initial:''}) !}/>

もちろん、以前にあったデータを読まないということも選択できます。 initial属性は、単に、永続的なオブジェクトが 生成される前に、一番最初にどの値を使うかということを示しているに過ぎません。

加えて、サーバーに変更を書き戻さなければなりません。これは、最大限単純化されます。 どこに値を保存するかとどの値を保存するかを表明するだけです。この場合、saveEにイベントが発生するごとに、theTextの現在の値、つまりそのフィールドのsnapshotを保存します。

writePersistentObject(saveE.snapshot($B('theText')), 
                      {path: ['draftFT']});

最後に、サーバーを初期化して、適切なライブラリを読み込まなければなりません。 ちょっとサンプルを 見てください。2つのウィンドウやフレームの中でアプリケーションを 動かして、同じURLを開くことができることに注意してください。 タイムラグはありますが、片方の変更がもう片方に伝播するのを確認できます。

Intermezzo: これはModel-View-Controllerフレームワークですか?

ソフトウェア工学のテキストは、Model-View-Controller (MVC)という、 アプリケーションを構成する上で有用だけれども重量のある フレームワークをどのように使うべきかについて説明するのが好きです。 FlapjaxはMVCを提供しますが、すこし特徴があります。サーバーをモデル、 クライアントをビューの実装と考えてください。コントローラーは面倒なところです。 値を更新し、変更を伝達し、変更を伝播させるというようなことを行います。 Flapjaxはコントローラーをペナルティなしに実装するための糊です。 それは束縛と規律のないMVCです。

結論

これで、Flapjaxのチュートリアルを終わります。 よくぞここまでたどり着きました。おめでとう! これからこの言語のドキュメントを読んで、自分自身のプログラムを作るようになると、 もっといろいろなものに出会うはずです。もし素敵なプログラムを作ったら、 ぜひ私たちに教えてください!