ここでは、下の画面のようにパラメータで指定された日付が何曜日かを表示するCGIプログラムを書いてみましょう。
まず、指定された日の曜日を求める関数を作りましょう。Gaucheユーザーリファレンスの「10.10 srfi-19 - 時間のデータ型と手続き」に日付を扱う関数があります。
これを調べてみると、date-week-dayという関数が曜日を数値(0が日曜、1が月曜……)で返してくれるようです。goshコマンドまたはEmacsのSchemeモードで確認してみましょう。ライブラリを使うにはuseマクロでライブラリを読み込みます。
% gosh-rl gosh> (use srfi-19) #<undef> gosh> (current-date) #<date 2008/12/07 19:20:39.922021000 (32400)> gosh> (date-week-day (current-date)) 0
確かに2008年12月7日は日曜なので、これが求めている関数のようです。
さて、指定された日の日付データ(<date>オブジェクト)はどうやって作るのでしょうか。これはmake-date関数を使うことにします。また、曜日名のベクター(配列)を用意し、date-week-dayの値で曜日名を取得することにしましょう。曜日名を求める関数day-nameは以下のようになります。
(use srfi-19) (define JST-TZ (* 9 60 60)) (define day-names-array #("日" "月" "火" "水" "木" "金" "土")) (define (day-name y m d) (vector-ref day-names-array (date-week-day (make-date 0 0 0 0 d m y JST-TZ))))
defineは変数や関数を定義するスペシャルフォームです。JST-TZは日本時間のGMTからの時差の秒数です。定数のベクターは'#(...)と書きます。ベクターのi番目の要素を取り出すにはvector-ref関数を使います。day-name関数もgoshコマンドやEmacsで試しながら作っていきます。
CGIを作るために便利な関数が「11.54 www.cgi - CGIユーティリティ」にあります。今回は、パラメータを受け取るcgi-parse-parameters関数と、その中から1つのパラメータを取り出すcgi-get-parameter関数を使うことにしましょう。これも少し実験してみましょう。
gosh> (use www.cgi) #<undef> gosh> (define p (cgi-parse-parameters :query-string "y=2008&m=12&d=10")) p gosh> (cgi-get-parameter "y" p) "2008" gosh> (cgi-get-parameter "m" p) "12"
一見よさそうですが、年月日の値は数値でないと計算できません、そこでcgi-get-parameterの:convertオプションで文字から数値に変換する関数を渡してみます。
文字から数値への変換は、「6.2 数値」にあるstring->number関数です。やや老婆心となりますが、->は変換するという演算子などではなく単なる関数名の一部です。
gosh> (use www.cgi) #<undef> gosh> (define p (cgi-parse-parameters :query-string "y=2008&m=12&d=10")) p gosh> (cgi-get-parameter "y" p :convert string->number) 2008 gosh> (cgi-get-parameter "m" p :convert string->number) 12
ちゃんと数値でパラメータが取得できました。Gaucheにはこのようにキーワード指定の引数が使えます。
あとは出力するHTMLを組み立てるだけです。文字列と変数や式の値を連結するのに、「6.10.4 文字列の補間」という便利な機能があります、PerlやRubyをご存じな方はピンと来たかもしれませんね。文字列に式の値を埋め込める機能です。(print #`"abc,(+ 1 2)def")は、abc3defと出力します。
これらを組み合わせると以下のようなプログラムになります。
#!/usr/local/bin/gosh (use www.cgi) (use srfi-19) (define JST-TZ (* 9 60 60)) (define day-names-array '#("日" "月" "火" "水" "木" "金" "土")) (define (day-name y m d) (ref day-names-array (date-week-day (make-date 0 0 0 0 d m y JST-TZ)))) (define (main args) (let* ((params (cgi-parse-parameters)) (y (cgi-get-parameter "y" params :convert string->number)) (m (cgi-get-parameter "m" params :convert string->number)) (d (cgi-get-parameter "d" params :convert string->number))) (print "Content-Type: text/html; charset=utf-8\n") (print "<html><head><title>曜日</title></head><body>") (print #`",y 年 ,m 月 ,d 日は ,(day-name y m d)曜日です") (print "</body></html>") ))
ここで使われている、let*スペシャルフォームはローカル変数を定義し、続く本体を実行します。このプログラムではparams、y、m、dという変数を定義して、それぞれに次に書かれた式の値を束縛(代入)し、print関数の並ぶ本体を実行します。
また、UNIX系のOSであればapacheを起動しCGIを動かすことはそれほど難しくないと思います。@ITにapacheの記事がありますので参考にしてください。
今回は、GaucheのインストールとGaucheで実際にプログラムを作る過程で、どのように必要な関数を見つけ、確認しながらプログラムを作成していくのかを説明しました。goshコマンドやEmacs上のREPLで実際にプログラムの動作を確認しながらプログラムを作っていくLisp流の開発スタイルを実感していただけたでしょうか。
Copyright © ITmedia, Inc. All Rights Reserved.