それでも俺はLiftをやるってのか

Liftを使って、Hello的Webサイトを作成します。htmlとsnippetの関係についてと、scala.xmlについて。今のところのliftを触った感触・向き不向きなども。

Liftの話の前に、明日仙台でscala勉強会@東北が立ち上がります。興味ある方、google-groupも参加してみてはいかがでしょうか。


さて、LiftでWebアプリを作成するときのフレームワークをざっくり説明すると、こうなる。




HTMLでのデザイン・遷移を決めておいて、動的に変化する箇所をsnippetで入れ替える。という開発手順になると思います。

snippetとは、xhtmlを生成するメソッドのこと。Railsなどでいうヘルパーメソッドと同等のものです。一般的なMVCフレームワークのControl(あるいはAction)に相当するものは、とりあえず「無い」と考えておきます。

上図のアプリケーションを作成するには、/src/mainの配下に

■/scala/firstapp/snippet/Hello.scala

package firstapp.snippet

class Hello {
 def aTitle = <div>Welcome</div>
 def aLink = <a href="/show">Show</a>
 def aParagraph = <p>contents</p>
}

■/webapp/index.html

<html>
<body>
 <lift:Hello.aTitle/>
 <lift:Hello.aLink/>
</body>
</html>

■/webapp/show.html

<html>
<body>
 <lift:Hello.aTitle/>
 <lift:Hello.aParagraph/>
</body>
</html>

これらの部品をデプロイするために、ブートストラップにSiteMapを設定します。

■/scala/bootstrap/liftweb/Boot.scala

package bootstrap.liftweb

import net.liftweb.util._
import net.liftweb.http._
import net.liftweb.sitemap._
import net.liftweb.sitemap.Loc._

class Boot {

 def boot {

  LiftRules.addToPackages("firstapp")

  val entries =
    Menu(Loc("Home", "/", "Home")) ::
    Menu(Loc("Show Blog", "show", "Show Blog"))::
    Nil

  LiftRules.setSiteMap(SiteMap(entries:_*))

 }
}

以上を記述したら、mvn jetty:run でサーバを起動して、
http://localhost:8080/
http://localhost:8080/show
にアクセスして動作を確認します。

snippetをもうちょっといじってみる

scalaの特徴として、XMLをソースコード上に埋め込むと、それがそのままXMLオブジェクトになります。

 val xml:NodeSeq =
  <item>
   <name>Gum</name>
   <price>10</price>
  </item>

これを踏まえ、snippetの型を厳密にして、もうちょっと「メソッド」ライクにいろんな書き方してみると、

■/scala/firstapp/snippet/Hello.scala

package firstapp.snippet

import scala.xml._
import blogonlift.lib.Formatter._

class Hello {

 def aTitle( xhtml: Group ): NodeSeq = {
  // xmlを返す
  <h1>Welcome</h1>
  <h2>Welcome</h2>
  <h3>Welcome</h3>
 }

 def aLink( xhtml: Group ): NodeSeq = {
  val label = "Show" //文字列をXMLに埋め込んで返す
  val xml:NodeSeq = <a href="/show/1.html">{label}</a>
  return xml
 }

 def aParagraph( xhtml: Group ): NodeSeq = {
  val html:String = "<p>contents</p>" //文字列を
  PCDataXmlParser.apply(html).open_! // XMLにパースして返す
 }
}


Liftを使いこなすために

最初に気をつけるべき点は、

 snippetのパラメータと戻り値は、
 厳密なXMLでなければならない


ことではないでしょうか。厳密とは、scala.xmlパッケージがXMLオブジェクトとしてコンパイルできる形という意味。(※Validであれば良いのかというと、そうでもないクセのようなものがある気がしているが、まだはっきりしない)

たとえば、次のようなコードは、コンパイルエラーやランタイムエラーになります。

■悪いHTMLの例

<html>
<body>
 <lift:Hello.some>
  <div class="<lift:Hello.style/>"></div>
 </lift:Hello.some>
</body>
</html>

■悪いsnippetの例
def list = {
 <li>a
 <li>b
}
def title = {
 "mojiretsu" //XML以外を返しても処理できない
}

実際にこのブログサイトを製作してみての感想ですが、はっきり言って、この制約はツライです!条件によってstyleを変えるなどの凝ったHTMLにしたい場合は、liftは向かないフレームワークのように思います。

逆に向いているのは、データ指向なサイト。モデル-XML-HTMLが、ズバズバっと連動するので、気持ちよくコーディングできるような気がします。(ホントかどうかはまだ不明w)


コードを修正してデプロイするには

1つの端末で mvn jetty:run でしておいて、もう1つの端末で mvn compile します。
Jettyが新しいバイトコードをロードするタイミングは、pom.xmlで調整できます。

<plugin>
 <groupId>org.mortbay.jetty</groupId>
 <artifactId>maven-jetty-plugin</artifactId>
 <configuration>
  <contextPath>/</contextPath>
  <scanIntervalSeconds>5</scanIntervalSeconds>
 </configuration>
</plugin>


このエントリ付近を掘り下げたい方は、サンプルhellodarwinを解読すると良いと思います。

次はもう少し複雑なsnippetとHTMLを編みこむ方法と、リクエストやセッションのスコープ話の予定。そもそもsnippetって、どのスコープで動くんだ?みたいなことを調べる。

モデルの実装はもうちょっと先になる気がしてきた。


同じカテゴリのエントリ
1.Lift再入門 / 8.javascriptからsubmitできない / 7.Ajax Form / 6.Radio、Checkboxについて / 5.行列型の編集FORM / 4.サーバーサイドバリデーションとサーバサイド関数 / 3.ログインFORM - S.param使ったら負け / 2.Snippetメソッドとして許される型 / sbt0.12.xで依存jar抽出タスク / scala2.10+lift2.5+NetBeans7.2 / Scalaで入門関数プログラミング / reactive-webを試してみました / Lift2.2M1のテンプレート機能 / Scala Compiler Plugin / View Bound/Context Bound / ScalaZa01参加してきました / Akka Frameworkチュートリアルの次 / Akka Frameworkチュートリアルその2 / Akka Frameworkチュートリアル / LiftでJCaptcha / Url Rewrite Filter / sbt-android-plugin / Android SDK for Scala / 祝Lift2.0リリース / Liftの携帯対応まとめ / Scala2.8への移行 / Lift 2.0-scala280-SNAPSHOT/sbt0.7.1 / Scalaお絵かき環境 - Kojo / Lift+Quartzでバッチ / Scala&Liftを採用した理由 / Liftでdate_select系ヘルパーを作る / LiftでAjax / LiftのSubmitかしこい / lift-mapperのpaginateを使う / snippetをspecする / Lift Mapperを拡張する / LiftのDBをMySQLに / Liftプロジェクト環境を整える / Scala本読み比べてみました / NetBeans6.7&scala / じつはScalaはライトな言語 / Scalaバザ~ル / lift1.0所感 / specsを読む / implicit def / ScalaならNetBeansがサイコー / scala勉強会@東北がスタート / それでも俺はLiftをやるってのか / Scala&Liftセットアップ / ブログリニューアル /
コメント
hmori
2008/08/28
>実際にこのブログサイトを製作してみての感想ですが、はっきり言って、この制約はツライです!

index.htmlのベースはXMLで記述して、描画部はXSLTを使うってのはどうでしょう?(XML+snippet+XSLT)
「条件によってstyleを変える」等はXSLTで吸収してしまうとか。
よくわからず無責任発言しています。
武田ソフト
2008/09/03
hmoriさん、アイディアありがとうございます。HTMLだけのためにXSLTを採用するのは、うーん、重厚すぎるかも。
yuroyoro
2008/09/18
SnipetのXMLですが、Rootタグを持たないXMLの場合は、
以下のように<xml:group>タグで囲むことで対応できますよ。
<xml:group>
<li>hoge</li>
<li>fuge</li>
</xml:group>

<xml:group>はScalaのXmlNodeに対するコンテナタグで、Snipetにレンダリングするときには
無視されるようです。
武田ソフト
2008/09/19
yoroyoroさん、ご教示ありがとうございます。
コメント打ってエラーになってしまったこと、お詫びします。まだまだ脆弱なんですよ><

#Snipetにレンダリングするときには無視されるようです。

なるほど!結構XMLの扱いには苦労するので(エラーになってしまったようにw)この情報はすごく助かります。ありがとうございました。
武田ソフト
2008/09/19
あと、コメントで「入力すればリンクが貼れます」と言ってますが、まだそこ作ってないです。作りますm(_ _)m
yasushia
2008/10/21
http://liftweb.net/index.php/JavaRebel
でscala限定のJavaRebelライセンスが公開されてます。
eclipseで自動コンパイルにしておくとまるでrailsですよ(いいすぎ)。

jettyのscanだとよくOOMで死んでしまいますので、これはすごい助かりました。
武田ソフト
2008/10/21
yasushiaさん、情報ありがとうございます、使ってみます!
確かにscanだと頻繁にOutOfMemoryなりますね。

ふと気がついたけど、Javaで開発してるときはOutOfMemoryは頻発するのでさほど気にならないんだよな、不思議と。開発中は出るモン、運用で出なければOK、みたいな・・

コメントしてください

closed.