図1●大まかなブログの仕組み<BR>ユーザーから閲覧要求があったとき,ブログツールはHTMLテンプレートに記事データを合成し,必要に応じてCSS(カスケーディング・スタイルシート)で記述されたデザイン情報を作成する。これらがまとめてWebブラウザに送信される。
図1●大まかなブログの仕組み<BR>ユーザーから閲覧要求があったとき,ブログツールはHTMLテンプレートに記事データを合成し,必要に応じてCSS(カスケーディング・スタイルシート)で記述されたデザイン情報を作成する。これらがまとめてWebブラウザに送信される。
[画像のクリックで拡大表示]
図2●CSS(カスケーディング・スタイルシート)の働き&lt;BR&gt;表示要素そのもの(h1タグなど)や表示要素に付けられたクラス情報に一意に対応するように,表示方法を記述する。CSSの解釈はWebブラウザに任される。
図2●CSS(カスケーディング・スタイルシート)の働き<BR>表示要素そのもの(h1タグなど)や表示要素に付けられたクラス情報に一意に対応するように,表示方法を記述する。CSSの解釈はWebブラウザに任される。
[画像のクリックで拡大表示]
リスト1●最初に作ったEntryクラス&lt;BR&gt;クラスの属性に対するsetter/getterを自力で定義している。@で始まる変数はインスタンス変数になる。またオブジェクト生成時に「initialize」メソッドが呼び出される。C++やJavaなどにおけるコンストラクタとほぼ同じ役割を担う。
リスト1●最初に作ったEntryクラス<BR>クラスの属性に対するsetter/getterを自力で定義している。@で始まる変数はインスタンス変数になる。またオブジェクト生成時に「initialize」メソッドが呼び出される。C++やJavaなどにおけるコンストラクタとほぼ同じ役割を担う。
[画像のクリックで拡大表示]
リスト2●テンプレートを保持するクラス&lt;BR&gt;テンプレートの内容をリクエストに応じて渡す部分と,ファイルからテンプレートを読み出す部分から成る。initializeメソッドで適当な情報を入れているが,あまり意味がなかった。
リスト2●テンプレートを保持するクラス<BR>テンプレートの内容をリクエストに応じて渡す部分と,ファイルからテンプレートを読み出す部分から成る。initializeメソッドで適当な情報を入れているが,あまり意味がなかった。
[画像のクリックで拡大表示]
リスト3●個別記事表示用のテンプレート&lt;BR&gt;記事データの内容を反映させる部分を「<$」と「$>」で囲んだタグで表現している。各表示要素に付けるクラス名はライブドアBlogから拝借した。
リスト3●個別記事表示用のテンプレート<BR>記事データの内容を反映させる部分を「<$」と「$>」で囲んだタグで表現している。各表示要素に付けるクラス名はライブドアBlogから拝借した。
[画像のクリックで拡大表示]
リスト4●個別記事を表示するサーブレット&lt;BR&gt;WebrickではWebブラウザにリクエストを返すクラスを「Servlet」として実装する。JavaのServletに似た形で動く。例えばGETメソッドによる呼び出しであれば「do_GET」というメソッドが呼び出される。ここで返答用のHTMLファイルを生成する。併せてCSSファイルを返すServletも定義している。
リスト4●個別記事を表示するサーブレット<BR>WebrickではWebブラウザにリクエストを返すクラスを「Servlet」として実装する。JavaのServletに似た形で動く。例えばGETメソッドによる呼び出しであれば「do_GET」というメソッドが呼び出される。ここで返答用のHTMLファイルを生成する。併せてCSSファイルを返すServletも定義している。
[画像のクリックで拡大表示]
画面1●記事の内容を表示&lt;BR&gt;CSSファイルを返していないので,シンプルなHTMLの解釈のようだ。&lt;BR&gt;&lt;BR&gt;画面2●CSSファイルを反映した画面&lt;BR&gt;一応ブログらしい画面表示となった。画面のデザインはライブドアBlogにある「blueframe」を使った。
画面1●記事の内容を表示<BR>CSSファイルを返していないので,シンプルなHTMLの解釈のようだ。<BR><BR>画面2●CSSファイルを反映した画面<BR>一応ブログらしい画面表示となった。画面のデザインはライブドアBlogにある「blueframe」を使った。
[画像のクリックで拡大表示]
リスト5●Webrickに施した修正&lt;BR&gt;Base64モジュールの使い方が間違っていた。
リスト5●Webrickに施した修正<BR>Base64モジュールの使い方が間違っていた。
[画像のクリックで拡大表示]
リスト6●Entryクラスの再定義&lt;BR&gt;記事の保存と取り出しを盛り込んだ。またRubyらしくアトリビュートを使って各要素を定義している。オブジェクトの永続化の機構であるPStoreを使ってデータを保存している。
リスト6●Entryクラスの再定義<BR>記事の保存と取り出しを盛り込んだ。またRubyらしくアトリビュートを使って各要素を定義している。オブジェクトの永続化の機構であるPStoreを使ってデータを保存している。
[画像のクリックで拡大表示]
リスト7●記事投稿用テンプレート&lt;BR&gt;記事投稿画面もテンプレートを使った。処理の仕組みを共通化できるからだが,この時点ではそれは生かされていない。またテンプレートを使うことによって,画面そのものの情報がプログラムの中に混入しないというメリットもある。このデザインもライブドアBlogを参考にした。
リスト7●記事投稿用テンプレート<BR>記事投稿画面もテンプレートを使った。処理の仕組みを共通化できるからだが,この時点ではそれは生かされていない。またテンプレートを使うことによって,画面そのものの情報がプログラムの中に混入しないというメリットもある。このデザインもライブドアBlogを参考にした。
[画像のクリックで拡大表示]
<!- 本文 ->

 ブログ(Weblog)は現在,最も注目度の高いインターネットのアプリケーションである。だがそれがどのような仕組みで動いているかについて,把握しているユーザーは少ないだろう。その仕組みについて,実際に似た動作をするソフトウェアを「作る」ことによって理解を深めていくというのが今回のテーマである。第1回は,記事の投稿とその記事を一つ表示できるところまでの試行錯誤を紹介する。

 人間ははるか昔からさまざまな道具を作り,それを使うことによって能力を拡大してきた。「もの」を作って,自らの生活の幅を広げることは人間の根元的な欲求の一部である。この欲求を多く持つ人は一般に「理科系」などと呼ばれる。物作りは,理学や工学における実験的精神の第一歩なのである。日経バイトは,これからいろいろな「もの」を作ることに取り組んでいく予定だ。

 その第1弾として採り上げるのが,ブログ(Weblog)である。ブログを1カ月に1度以上更新している利用者は,総務省の調べによると2005年3月末の時点で既に約95万人だという。単にブログサイトを開設しているだけであれば約335万人。大半はニフティやライブドア,So-net,ヤフーなど多くのプロバイダが提供しているASP型のサービスを利用している。したがってほとんどのユーザーは,ブログがどのような仕組みになっているかは知らないし,知らなくても使える。だが,ブログに盛り込めるさまざまなカスタマイズの持つ意味について,仕組みを知ればさらに理解が深まるはずだ。Webアプリケーションとして,規模が手ごろであるというのもブログを採り上げた理由の一つである。

第1ステップ
材料を揃え,適当に始める

 ソフトウェアを作る場合,最初にすることは使う道具の選定だろう。基本的に実験的な作成を考えているので,いろいろなツールを使わずに済ませることを第一義とした。また実験という観点から,ソースコードを分かりやすく書けそうな気がするというのも重要だ。今回は個人的な好みもあり,Rubyを使うことにした。PerlやPHPでブログを構築した事例は山ほどあって,今さら感が強いというのも理由の一つである*1。またRubyには「Webrick」と呼ぶ,Webサーバ ー・アプリケーションを構築するためのライブラリが標準で付属している。このため別途Webサーバーを用意しなくても済む。実験的な規模なのでデータベースも使わないことにした。

 当初この決定を下したとき,そもそもWebrickだけで作りきれるのか,データベースがなくても本当に大丈夫なのかなどの不安はあった。しかしそれはやってみなければ分からない。とりあえず走り始めることにした。なおあらかじめ断っておくが,筆者はプロのプログラマではない。必要なソフトがあって,それがネットなどで見あたらなければ自分でプログラムを書くのをいとわないサンデー・プログラマではある。Rubyには以前から関心を持っていたが,Rubyでプログラムを書いた経験は数行程度しかない。

デザインは他人任せで

 まず最初に考えたのは,個々の記事を表示する場面である。ここで必要な要素は大きく三つである。記事の内容を保持するものと,その内容を表示する処理,それにブログらしさを出すためにデザイン・テンプレートを保持するものである(図1[拡大表示])。

 ブログの多くがさまざまなデザインを適用できるようになっているのは,CSS(カスケーディング・スタイルシート)を使っているからだ。CSSはHTML文書中の個々の表示要素や,その要素に付けたクラス名(divタグなどを使う)に対して,どのように表示するかを指定するものである(図2[拡大表示])。筆者はデザインセンスに自信がないので,既に存在するテンプレートを利用できる仕組みを考えた。つまり,公開されているブログのサービスで使っているデザインを利用できるよう,HTML側のテンプレートに割り当てるクラス名をどこかのサービスに合わせることにしたのである。対象としたのはライブドアBlog。深い理由はないが,無料で公開されているテンプレートがライブドアBlog対応だったのを見つけたことと,ライブドアBlogがHTML側のテンプレートも公開していたので,これも参考にさせてもらった*2

三つのデータを組み合わせる

 さて図1を見ると,とりあえず定義しなければならないクラスは,個別の記事を表現するクラスとテンプレートを保持するクラスだ。ブラウザに対して応答する部分はWebrickに従って実装することになる。

 最初に定義したのは記事を表現するクラスである(リスト1[拡大表示])。とりあえずRubyでは@を先頭に付けるとインスタンス変数になることと,initializeというメソッドが生成時に実行されるということが分かったので,ここで初期化して仮のデータを入れるようにしている*3

 次にテンプレートを保持する「TemplateHolder」を定義した(リスト2[拡大表示])。センスの悪さを暴露するが,当初個々のテンプレートごとにクラスを定義しようとしていた。クラスとオブジェクトの整理がアタマの中でついていなかったことがよくわかる。しかし,同じ操作を定義しようとしている自分に気づいた。クラスとして「テンプレートを保持するもの」を定義し,それぞれのインスタンスで個々のテンプレートを保持するよう切り分ければよいじゃないか。

 ここではとりあえず,オブジェクトを生成したら適当なテンプレートを読み込んでしまうことにした。後々修正することになるが,C++やC#のようにオブジェクト生成時の引数によって振る舞いが変わるよう,オーバーロードできると思っていたためだ。仮に間違えて引数を渡さないコードを書いても,何らかのテンプレートが入っている方が正しく初期化されて安全だろう。また,このTemplateHolderのオブジェクトをいちいち使う場面で生成するのではなく,プログラムのスコープとしては全域で保持するべきかとも考えていた。ただグローバル変数になるので,それも善しあしだなと思い,決めあぐねていた。

 HTML部分のテンプレートは,ライブドアBlogから拝借したHTMLファイルから,とりあえず今回関係のないところを切り落とした(リスト3[拡大表示])。具体的には「<$ArticleTitle$>」のようにタグに似た形で記述してある部分に,個々の記事の内容を埋め込む。これで実際の表示を実現しているのである。

Webrick=Servletエンジン

 そして最後に,これらを呼び出してWebブラウザのリクエストに応える部分を記述した(リスト4[拡大表示])。Webrickの記述方法に従っている。Webrickでは「Servlet」というクラスを定義して,そこでWebブラウザに対する回答を組み立てる。Servletと言えば,一番に思い出すのがJavaのServletだろう。基本的な仕組みはこれと同じだ。正直,「さてまずどうやってWebサーバーにするか」を迷っていたあたりでは,この簡単さに感激した。JavaのServlet自体は簡単なものだが作ったことがあるので,考え方自体も分かりやすかった。

 具体的には,Webrickで定義している「AbstractServlet」クラスの子クラスとして処理本体を定義する。Webのメカニズムでは,サーバーに対するブラウザからの要求は「GET」と「POST」の2種類がある。このそれぞれに対して何を返すかを,あらかじめ決められた名前のメソッドに定義する。Webrickの場合,GET要求に対応する処理を「do_ GET」,POST要求に対応する処理を「do_POST」に記述する。

 Webブラウザから伝達されるさまざまな情報は,メソッドの第1引数(通常はreqとする)に格納されている。この取得方法については後述する。またブラウザに戻す情報は,第2引数(同じくresとすることが多い)に指定する。resオブジェクトのbodyに,表示するHTMLの本体(正確に言えば,HTTPで返信するデータ本体)を記述する。必要に応じて送るデータの種別を指定する場合は,

res['Contetnt-Type']="text/html"

などと指定することになる。ここまでで一応,エントリ・オブジェクトの内容を表示する画面ができる(画面1[拡大表示])。