レベル: 初級 Bruce Tate (bruce.tate@j2life.com), President, RapidRed
2006年 7月 25日 Java™ コミュニティーは、これまでほぼ 10 年間 JSP (JavaServer Pages)技術を使用してきました。しかし、その限界が見え始めています。長年の因習のおかげで、Javaプログラマーは現在 Web ページ内で Java コードを使うことができず、単純なコンポーネントを拡張するだけでも面倒な作業になってしまいます。JSPプログラミングを超えた Java Web 開発を実現するためのフレームワークは生まれつつありますが、それらは動的言語の能力の前には力不足です。この記事では、Rubyを使って Web ページを開発する方法を説明し、また Seaside による過激な方法にも触れて行きます。
Java による Web 開発の初期の頃、Sun と Microsoft は、動的 Web ページ構築のためのデファクト・スタンダードの主導権を取るべく争いました。Sunはサーブレット API を導入しました。サーブレットを使うことによって、Java言語の持つ全機能を活用して素早く Web ページを立ち上げることができます。サーブレットがコンパイルできること、またフリーのサーブレット・コンテナー実装(Apache Tomcat) が利用できることから、サーブレットは非常に一般的なものとなりました。一方Microsoft はこれに対抗して、ASP (Active Server Pages) と呼ばれる API を導入しました。これは使いやすい技術でした。すぐに使いこなすことができ、背後にデータベースを持つWeb ページや他の動的コンテンツを持つ Web ページなど、より高度な Web ページを作ることができるものでした。
 |
このシリーズについて
この、境界を越えるシリーズでは、著者である Bruce Tate が、「今日の Java プログラマーは、他の手法や言語を学ぶことから多くを得ることができる」という概念を押し進めます。プログラミングの世界の様相は、あらゆる開発プロジェクトにとってJava が最善の選択肢であることが明確だった頃から変わってきています。他のフレームワークもJava フレームワークと同じ構築形態をとりつつあり、また他の言語での概念を学ぶことによって、それをJava プログラミングに生かすこともできます。皆さんが書く Python (あるいはRuby や Smalltalk、その他何であれ) コードによって、皆さんの Java コーディングに対する取り組みも変わる可能性があるのです。
このシリーズでは、Java 開発とは大幅に異なりながら、同時に Java 開発にも直接応用できるプログラミング概念や手法について紹介します。場合によると、そうした技術を利用するためには、それら統合する必要があるかも知れません。また場合によると、そうした概念は直接利用できるものかもしれません。他の言語やフレームワークが、開発者やフレームワーク、Javaコミュニティーでの基本的な手法にまで与えうる影響に比べると、個々のツールはそれほど重要ではありません。
|
|
そこに今度は JSP 技術が登場しました。JSP は、(名前からも分かる通り) ASPと直接競合するように設計されています。JSP ではタグを使って Web ページを構築でき、そのページの中にJava コードを直接落とし込むことができます。そして JSP コンテナーは、そのJSP ファイルをサーブレット形式にコンパイルします。次にサーブレット・エンジンは、他の普通のサーブレットを実行する場合と同じように、そのページを実行します。JSPも ASP も、テンプレート・ベースの手法を実装しています。テンプレートによる手法を利用することによって、単純なWeb ページを、ユーザーのブラウザー上に見えるものと全く同じように構築することができます。そうしておいてから、単純なプレースホルダー要素をテンプレート・エンジンが処理する際に、そうした要素を値やコンポーネント、あるいはそのページの一部となる構造で置き換えるのです。Javaプラットフォームには汎用のテンプレート・エンジンが数多くありますが、JSPが次第に市場シェアを支配的にしてきたのは、一部には ASP 開発からの転向者がたくさんいることによります。
しかし、Java 言語や ASP よりもずっとうまく Web 開発が行える言語は、他にもいくつかあるのです。動的言語による競合的な手法を見ていくことで、Javaプラットフォームで利用できるものをより的確に判断できるようになります。この記事では、Rubyによるコード生成の動作について説明します。そして、Seaside によるさらに過激なコンポーネント・ベースの手法について、掘り下げて見ていきます。
Ruby テンプレート
Ruby テンプレートは、この言語の持つ単純な機能を利用しており、Web ページ開発を行う上での、単純ながら効果的な手法と言うことができます。また階層毎に強力になっていく階層化の概念をいくつか理解すれば、Rubyテンプレートをすぐに理解することができます。
Ruby テンプレートの最も基本的な部分は String です。Ruby のストリングはファーストクラス・オブジェクトです。Rubyでストリングを作成する場合には、そのストリングを単一引用符または二重引用符で囲みます。リスト1 は、Ruby インタープリターに打ち込んでストリングを作成するための、3 種類のコマンド例を示しています。
リスト 1. Ruby ストリングを作成する
irb(main):001:0> "This is a string.".class
=> String
irb(main):002:0> 'This is also a string.'.class
=> String
irb(main):003:0> String.new('This is yet another string.').class
=> String
|
ストリング中のデータを単一引用符で囲んでおくと、Ruby はそのデータを処理しません。ストリングを二重引用符で囲むと、Rubyはコードを通して置換を行うことができます。リスト 2 は、改行文字の使い方の例を示しています。単一引用符を使った場合には、Rubyは改行文字をそのままにしておきます。二重引用符を使うと、Ruby は改行文字を解釈します。
リスト 2. 単一引用符と二重引用符
irb(main):004:0> puts 'Use \n to specify a new line in Ruby.'
Use \n to specify a new line in Ruby.
=> nil
irb(main):005:0> puts "A \\n causes a line break \n like this."
A \n will cause a line break
like this.
=> nil
|
Ruby は 2 番目の puts 命令 (puts は put string を表します) によって、2つの置換を処理します。単一の \ とその後に続く文字は、キーボード上にはない特殊な文字(例えば改行、\n) を表します。特別な意味を持つ文字、(例えばバックスラッシュそのものなど)の前にある \ は、Java 言語での場合と同じように、その文字をエスケープします。つまりリスト2 は、\\ と \n の両方の置換を処理しています。
もっと興味深い置換コマンドは、#{any_expression} です。このコマンドを含むString の前後を二重引用符で囲むと、Ruby は、 #{any_expression} を any_expressionの値で置き換えたストリングを返します。その一例をリスト 3 に示します。
リスト 3. 単純な変数の置換
irb(main):006:0> name = "Elvis"
=> "Elvis"
irb(main):007:0> puts "Your name is #{name}"
Your name is Elvis
=> nil
|
基本的なテンプレートに必要なものの大部分は、これで理解できたことになります。最後にトリックを1 つ紹介して、単純なテンプレート処理を終わることにします。単一引用符を持つストリング中で#{} 置換を使うと、バインディングを遅らせることができるのです。そのテンプレートを二重引用符で囲み、eval()メソッドを呼ぶことによって、あとで好きな時にテンプレートを変数にバインドすることができます(リスト 4) 。
リスト 4. バインディングを遅らせる
irb(main):008:0> template = 'Your name is #{name}'
=> "Your name is \#{name}"
irb(main):009:0> name = gets
Elvis
=> "Elvis\n"
irb(main):011:0> puts eval('"' + template + '"')
Your name is Elvis
=> nil
|
コードが name を初期化する前に template があることに注目してください。この単純なテンプレートによる方法を使うと、非常に単純なWeb ページは簡単に処理できるのですが、通常はもっと高度なことが必要です。単純なコード構造(例えば動的データを持つテーブルに対するループなど) を含めることができる機能は、ほとんどの動的Web ページのバックボーンとなります。
eRuby を使ってコードを埋め込む
Ruby コードを HTML ページに埋め込むための典型的な方法は、eRuby と呼ばれるフィルターを使う方法です(Rail で使われている方法も同様です) 。これには、ERb と呼ばれる Ruby ベースの実装や、もっと高速なeruby と呼ばれる C ベースの実装など、いくつかの実装があります (参考文献を参照) 。どれも Web サーバーのプラグインとして動作しますが、ローカル・ファイルを手軽に処理するにはERb が使われ、よりスピードが要求される場合 (実稼働の Web サーバーなど)には eruby が使われます。eRuby フィルターはテキスト・ファイルを処理しますが、下記の3 つの例外を除いて、すべてはそのままで何も変化しません。
- <% と %> の間にあるテキストは Ruby のコードです。 eRuby は、これをそのまま実行します。
- <%= と %> の間にあるテキストは Ruby の式です。eRuby はこれを実行し、式全体をこの式が返す値で置き換えます。
- % 1 つで始まるラインは、Ruby コードとして実行されます。
例えば、test.rhtml というファイルを表すリスト 5 を考えてみてください。(eRuby 用にマークアップされた HTML を含んだファイルには、習慣的に.rhtml拡張子が付けられます。) リスト 5 は、Ruby のコードと式の両方を使っています。doループの本体の中にあるテキストに注意してください。
リスト 5. 単純な rhtml ファイル
<% 4.times do |i|%>
<h1>This code is inside the loop.</h1>
<p>This line is pass number <%= i %> through the loop.</p>
<% end %>
|
このコードを実行するには、単純に ERb を使って実行します (リスト 6) 。
リスト 6. ERb を使ってファイルを処理する
> erb test.rhtml
<h1>This code is inside the loop.</h1>
<p>This line is pass number 0 through the loop.</p>
<h1>This code is inside the loop.</h1>
<p>This line is pass number 1 through the loop.</p>
<h1>This code is inside the loop.</h1>
<p>This line is pass number 2 through the loop.</p>
<h1>This code is inside the loop.</h1>
<p>This line is pass number 3 through the loop.</p>
|
テンプレートを呼び出す
Ruby は、LAMP ベースの Web 開発を行うための言語の 1 つです。LAMP は下記を表しています。
- Linux
- Apache
- MySQL
- オープンソースの P で始まる言語: Python、Perl、または PHP。(Ruby は名誉P 言語なのです。R の斜め棒を取り去れば P になることでも分かるでしょう。)
通常 LAMP では、単純なオペレーティング・システムのスクリプトとCGI (CommonGateway Interface) のようなフレームワークを使って、Web アプリケーションをサービスします。
eRuby は、通常の CGI ベースのプログラミング・レベルを実質的に高めるのです。皆さんが想像される通り、ERb(または C ベースの eruby に相当するもの) を直接 Apache HTTP サーバーにプラグインしてWeb ページを呼び出すことができます。そうすると、Java サーブレット相当のRuby 版ができます。しかし新しいフレームワークでは、多くの場合、ERb を Rubyライブラリーとして呼び出します。API 内から Ruby テンプレートを作成したい場合には、リスト5 を修正したものを使います (リスト 7)。
リスト7. Ruby アプリケーション内で ERb テンプレートを実行する
require 'erb'
template = ERB.new <<-EOF
<% 4.times do |i|%>
<h1>This code is inside the loop.</h1>
<p>This line is pass number <%= i %> through the loop.</p>
<% end %>
EOF
puts template.result
|
このようにテンプレートを実行することによって、Ruby プログラミング言語の能力を完全にテンプレートに反映させることができます。そうすれば、テンプレート中のコードとアプリケーションの残り部分のコードとを、シームレスにリファクタリングできます。例えば、ハッシュ・マップの内容に基づいて単純なテーブルを構築するヘルパーを作ることができます(リスト 8) 。
リスト 8. ヘルパーを抽出する
require 'erb'
def table_helper(map)
body = map.collect do |item|
"<tr><td>#{item[0]}</td>
<td>$#{item[1]}</td></tr>\n"
end
return("<table>\n#{body}</table>")
end
map = {
"Peaches" => "1.95",
"Apples" => ".95"
}
template = ERB.new <<-EOF
<p>Here's our price list</p>
<%= table_helper(map) %>
EOF
puts template.result
|
リスト 8 は、ハッシュ・マップを与えるとテーブルを作成するヘルパーを示しています。この例では次に、ハッシュ・マップとテンプレートを宣言し、両者を共に使っています。(通常、このテンプレートは別ファイルに含めるようにします。ここではリストを単純にするために、テンプレートをインラインとして含めました。)こうすることによって、Ruby プログラミング言語の持つ機能に基づいて、テンプレート・システムの機能を自然に拡張していることに注意してください。この例では、ERbスタイルの置換を、単純なストリング用に用意された Ruby の基本ストリング置換と組み合わせています。Rubyon Rails は、こうした置換スタイルを、次のようないくつかの強力な方法でうまく組み合わせています。
- Rails の partials によって小さなサブフォームが利用できるため、再利用を促進でき、また構成を整えることができます。
- Rails の layouts によって、ヘッダーやメニュー・バー、コピーライト情報などの共通要素を全ページに再利用することができます。
- Rails の helpers (リスト 8 で見たヘルパーと似ています) によって、ビューの一部分の単純化と再利用がしやすくなります。
実際、Rails の設計では、JavaScript を使って複雑な機能 (Ajax 要素やツリー・コントロール、ポップアップ・メニューなど)を実現するライブラリーを、ユーザーが提供しやすくなっています。Rails のコミュニティーでは、Railsそのものの持つ基本機能をはるかに超えるようなヘルパーを提供しています。
Seaside による方法
Seaside は Smalltalk で Web アプリケーション開発を行うためのフレームワークであり、伝統的なテンプレートを使わずにHTML を描画する方法の一例です。今日の Web デザイナーは、CSS (CascadingStyle Sheets、参考文献を参照) と呼ばれる方法によるスタイリングを非常に重視するようになっています。CSSを使うことによって、描画位置や色、背景、そしてフォントなど、スタイリングのあらゆる情報を、テンプレートと親和性の高い言語で作成することができます。Seasideは、スタイリングに関しては非常に CSS に似ていますが、基本的なコンポーネントの描画にテンプレートを全く使いません。
Seaside では、各コンポーネントが自分自身を描画する方法を知っています。コンポーネントは最も基本的なレベルとして、基本的なHTML タグと、そのコンポーネントを描画するために必要な動的コンテンツを出力します。例えばリスト9 は、単純な Seaside カウンターを作成するための renderContentOn メソッドを定義しています。
リスト 9. 単純な Seaside コンポーネント
renderContentOn: t1
t1 heading: count.
t1
anchorWithAction: [self increase]
text: '++'.
t1 space.
t1
anchorWithAction: [self decrease]
text: '--'
|
リスト 9 のコードでは、 t1 heading: count. が、インスタンス変数カウントの内容(単純なカウンターの値を含んでいます) を持つ見出しを描画します。次にこのコードは、Seasideの用語でアンカーと呼ばれるリンクを描画します (このリンクはテキスト、'++'を含んでおり、また increase メソッドを呼び出します) 。そしてこのコードは最後に、同様のリンクをdecrease メソッドに対して描画します。図1 は、リスト 9 のコードで描画されるカウンターを含んだWeb ページを示しています。
図 1. 単純な Seaside コンポーネント
もっと複雑なコンポーネントは、サブコンポーネントを使って自分自身を描画します。この手法のおかげで、ほとんど手をかけなくてもSeaside は驚くほど高度なコンポーネントを生成してくれるのです。例えば、あるテーブルが一群の行を描画し、そうした行が今度は一群のセルを描画する、といったことができます。リスト10 は、複雑なコンポーネントの一例を示しています。
リスト 10. もっと複雑な Seaside コンポーネント
renderContentOn: t1
counters
do: [:t2 | t1 render: t2]
separatedBy: [t1 horizontalRule]
|
リスト 10 のコードは、一連のカウンターを描画し、一連のコンテナーに対して繰り返しを行い、それぞれに対してrender メソッドを呼び、そして各カウンターを罫線で区切ります。その結果を図2 に示します。
図 2. 一連の Seasideカウンター
Seaside のモデルはテンプレートを使いませんが、個々のオブジェクトが自分自身を描画するという機能を利用することで、複雑な対話動作を備えた、驚くほど強力なWeb ページを構築することができます。Seaside では、スタイルシートに依存することで、デザイナーとプログラマーとを良好な関係に保つことができます。レイヤー化やレイアウト、バックトラック、そしてスタイリングなどは、Seasideではささいなことに過ぎないのです。
JSP を超える
Jason Hunter は、6 年前に書いた素晴らしい記事の中で、JSP の欠点をあげています(参考文献を参照) 。それらを私が言い換えると、次のようになります。
- JSP は必要以上に難しい。
- ループが難しい。
- エラー・メッセージが分かりにくい。
- プログラマーとデザイナーの間のバランスをとることが非常に難しい。
これまで長年の間、Java プログラマー達は、こうした制約に対応するためのプラクティスやフレームワークを考え出してきました。JSPプログラミング用のカスタム・タグ・システムである JSTL (JavaServer PagesStandard Tag Library) は、JSP ファイルから簡単にコードを取り出して共有ライブラリーに入れられないかを探っていますが、このタグ・システムは必要以上に複雑です。JavaWeb ページ開発者は、どうしても Java コードを直接 Web ページに挿入したくなるため、その誘惑に打ち勝とうとして、あらゆるコードを疫病のように避けようとしています。JSP技術の上に構築されたいくつかのフレームワークは、そうしたことが比較的単純にできることを目指しています。新しいフレームワークは、JavaWeb 開発の作業を改善しようとしてきました。例えば、JSF (JavaServer Faces)は Struts を作り直そうとしていますが、 (一部のエキスパートによる助言にもかかわらず)最初は JSP を必須としていました。
ここ数年の間に、JSP に依存しない革新的なフレームワークがいくつか生まれてきました。RIFEや Wicket、Spring Web MVC、Tapestry、その他いくつかのフレームワークは、テンプレート化という単純な(そして純粋な HTML の考え方にずっと近い) 考え方に基づくことで、どれもがはるかに単純にコンポーネントを統合する方法を提供すると主張しています(参考文献を参照) 。これらはどれも Web デザイナーが、JSP プログラミング用にカスタマイズされたツールを使うのではなく、ネイティブの設計ツールを使えるようになっています。これはJava 言語にとっては健全な方向と言えますが、それでもなお Ruby のような他の言語は、Java技術よりも Web 開発をずっとうまく扱うことができるのです。
Java の持つエンタープライズ機能の豊富さと動的言語の単純さを組み合わせる方法として、1つ可能性があるのは、埋め込みの仮想マシンを使う方法です。JRuby のリーダー、ThomasE. Enebo によると、開発者達はすでに、インラインの Ruby コードで Ruby スタイルのWeb ページを作れるようなサーブレットへの取り組みを始めているとのことです。この手法によって、両方の世界の利点が様々な面で活用できるようになるでしょう。
今回の記事で、他の言語が Web ページをどのように描画するか、多少理解できたのではないでしょうか。次回は、共通の問題に対して、関数型言語を使った別のアプローチの仕方について説明する予定です。
参考文献 学ぶために
製品や技術を入手するために
-
Ruby: Ruby プロジェクトの Web サイトから Ruby を入手してください。
-
Ruby on Rails: オープンソースの Web フレームワーク、Ruby on Railsをダウンロードしてください。
-
Seaside: 劇的に異なる Smalltalk Web フレームワーク、Seaside をダウンロードしてください。
著者について  | 
|  | Bruce Tateは父であり、マウンテンバイク乗りであり、カヤック乗りであり、そしてテキサス州オースチンに住んでいます。Joltを受賞した『Better, Faster, Lighter Java』を含め、ベストセラーとなった3冊の著書を執筆しています。最近、『Spring: A Developer's Notebook』を発刊しました。彼はIBMに13年間在籍した後、J2Life, LLC社を設立し、Java技術とRubyに基づく軽量開発戦略とアーキテクチャーを専門としたコンサルティングを行っています。 |
記事の評価
|