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-web | Liftweb向けのCometActorとSnippetフレームワーク(各DOM部品など) |
| reactive-web-demo | Liftwebのサンプルアプリ |
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