reactive-webを試してみました

Liftを使ったRIAフレームワーク reactive-web を試してみました。RIAフレームワークと言っているわりには、今のところGUI部品がそろっているわけではなく、ブラウザとサーバサイドで簡単にイベントをやりとりするためのフレームワークのようだ。とりわけJavaScriptの隠蔽っぷりがお見事だと思いました。

Github: nafg / reactive
Googleグループ Lift: reactive-web

動作確認は簡単で、

> git clone http://github.com/nafg/reactive.git
> cd reactive
reactive > sbt update
reactive > sbt "project demo" jetty

localhost:8080にアクセスする。



何が起きてるのかさっぱりわからないけれど、とりあえず、ブラウザ上のキーイベントがすぐにサーバサイドに伝わったり、サーバーサイドのイベントがブラウザに伝わったりする様子がわかる。
このリポジトリの構成は、

reactive
(reactive-core)
Functional Reactive Programming (FRP) ライブラリ
reactive-webLiftweb向けのCometActorとSnippetフレームワーク(各DOM部品など)
reactive-web-demoLiftwebのサンプルアプリ

reactive-web-demo はソースが短くて簡単なので、マネしながらページを追加していってみる。

Boot.scalaで、"reactive.web.Reactions.initComet"とCometActorを起動していることに注意。

※全コードはgistに貼りました

サーバサイドタイマーがクロックアップするたびにブラウザに現在時刻を表示する。

■テンプレート

<lift:surround with="default" at="content">

  <div class="lift:reactive" /><!-- 必須:JavaScript等に展開される -->

  <!-- CSS Selector Snippet (Lift2.2 or later) -->
  <div class="lift:ClockCSSSnippet">
    <span id="clock" />
  </div>
</lift:surround>

■スニペット

class ClockCSSSnippet extends ReactiveSnippet {
 val clockES = new Timer(interval = 1000,
            cancel = ()=> !isPageAlive)
 val clockSig = clockES.hold(0L)
 val clockSpan =
   Span( clockSig.map( t => Text((new Date).toString )) )

  def render = "#clock" #> clockSpan
}

Lift2.1以前のSnippetの作法なら、差分は以下のようになる。

<!-- Old Snippet -->
<lift:clockOldSnippet >
  <ns:clock />
</lift:clockOldSnippet >

class ClockOldSnippet extends ReactiveSnippet{
    :
  def render(xhtml:NodeSeq) :NodeSeq =
   bind( "ns", xhtml, "clock" -> clockSpan )
}

ブラウザからの入力をサーバサイドに伝播して、ブラウザにエコーする


■テンプレート
<lift:surround with="default" at="content">
  <div class="lift:reactive" />

  <div class="lift:EchoSnippet">
    <input id="field" /><br />
    エコー: "<span id="echo"/>"<br />
  </div>

</lift:surround>

■スニペット

class EchoSnippet extends ReactiveSnippet {
  val field = TextInput()
  field.value updateOn field.keyUp

  val fieldValue = field.value.value map { v =>
    println( "field value on client:"+v )
    Text(v)
  }
  println( fieldValue ) //MappedSignal

  val echo = Span( fieldValue )

  def render =
    "#field" #> field &
    "#echo" #> echo
}

これだけのコードで??と、けっこう驚きました。JavaScriptがうまく隠蔽されていて、JSを使ってるという意識すらないかも。
これでいろんなHTMLElementやGUIのバリエーションが増えたら面白いかもしれないですね。

Functional Reactive Programming

このフレームワークのベースになっているFunctional Reactive Programmingという言葉を初めて知ったので、今後勉強しておきたい。

参考文献:
http://en.wikipedia.org/wiki/Reactive_programming
http://en.wikipedia.org/wiki/Functional_reactive_programming
maoeのブログ:やさしいFunctional reactive programming(概要編)
maoeのブログ:やさしいFunctional reactive programming(Event編)
maoeのブログ:やさしいFunctional reactive programming(Behavior編)

とても自分にはまとめられませんが、、、
「シグナルに反応するもの」というのが、reactive-webの例ではSpan( signal )などということなのだろうか。。

reactive-core を使っていろいろ試せそうです。

reactive> cd reactive-core
reactive-core> sbt

とりあえずテストを動作確認

> test
[info] == test-finish ==
[info] Passed: : Total 28, Failed 0, Errors 0, Passed 28, Skipped 0
[info]
[info] All tests PASSED.
[info] == test-finish ==
[success] Successful.

テストコードを見ながら確認。
元のSignalを変更すると、それに反応して関連するSignalも変更されることがわかる。

> console
scala> import reactive._

scala> val v = Var(1)
scala> val signal = v.map[Int,Signal[Int]]( _ * 3 )
scala> val signal2 = signal.map[Int,Signal[Int]]( _ * 100 )
scala> v.now // => 1
scala> signal.now // => 3
scala> signal2.now // => 300
scala> v()=123
scala> signal.now // => 369
scala> signal2.now // => 36900

コメント

コメントしてください
お名前:
入力しなければ「匿名さん」。20字以内。

メール:
入力しても表示しません

URL:
入力すればリンクが貼れます


コメント: