Ruby CGI Adjuster

(2004.03.27新規作成。2004.12.31更新。)

概要

Rubyは、バージョン1.6から1.8にバージョンアップしたときに、CGIライブラリが変更され、非互換な部分が生じています。Ruby 1.6用に書かれたCGIスクリプトを両方で動かすことができません。

この話は、拙著『基礎から学ぶWebデータベースプログラミング』でも解説しています(p.192-193)。

Ruby CGI Adjusterは、次のことを行うための、小さなスクリプトです。

ライセンス

Ruby's ライセンスとします。LICENSE

使い方

Ruby 1.6用のCGIスクリプトで、次のようになっているところ;

  require "cgi"
または
  require "cgi/session"
を、次のように修正します。
$COMPAT_VERSION = "1.6"
require "cgisup.rb"

Ruby 1.8用のスクリプトでは、$COMPAT_VERSION に代入せずに、次のようにしてください。

require "cgisup.rb"

変更・追加するメソッド

クラスCGI

[key]
コントロール値またはIOを得る。

Ruby 1.6モード($COMPAT_VERSION == "1.6")では、@params[key] と同じ。

Ruby 1.8モードでは、次のように動作する。

  • マルチパートではないときは、名前がkeyである最初のコントロールのコントロール値(文字列)を返す。keyコントロールがないときは、""を返す。
  • マルチパートのときは、IO、StringIOまたはTempfileオブジェクトを返す。
file_control(key)
keyコントロール(ファイルコントロール)のコントロール値を格納するIOオブジェクトを返す。keyコントロールがないときは、nilを返す。
マルチパートではないときは、例外RuntimeErrorを投げる。
get(key, default = "")
ファイルコントロール以外の値を取り出すのに使う。keyコントロールの最初のコントロール値(文字列)またはdefaultで指定される値を返す。マルチパートであるかどうかによらない。いずれでも、値を取得できる。

次のようにして使う。

require "cgisup.rb"

cgi = CGI.new
text = cgi.get("text")
file = cgi.file_control("file")
size = file.size
body = file.read

クラスCGI::Session

CGI::Session.exist?(request, option)
セッションが存在するかどうかを調べる。requestにはCGIオブジェクトを、optionにはCGI::Sessionオブジェクトを生成するときに与えるハッシュを与える。
CGI::Session.get(request, option)
セッションが存在する場合のみ、Sessionオブジェクトを得る。
CGI::Session.sweep(option)
セッション情報を保存するファイルを削除する。option["holdtime"](整数で、単位は秒)だけ経過したセッション情報を削除する。
update_access_time()
セッション情報の最終アクセス時刻を更新する。CGI::Session.sweep()で参照される。

関数

menu_control(name, options, default = nil)
メニューコントロールHTMLを生成する。

ダウンロード

日付
2005.01.08
内容
  • datesup.rbが必要だったのを修正した。datesup.rbは私の手許で使っているファイル。
ファイル
cgisup-20050108.rb
日付
2004.12.31
内容
  • Ruby 1.8.2-releaseに対応した。
ファイル
cgisup-20041231.rb
日付
2004.03.27
内容
  • 初公開。
ファイル
cgisup-20040327.rb

内部の挙動について

通常、CGIクラスの[]メソッドでフォームのコントロール値を取り出します。CGI#[]の戻り値は、Rubyのバージョン、formタグのenctype属性値によって、それぞれ次のようになります。

enctype属性値Ruby 1.6の場合Ruby 1.8の場合
application/x-www-form-urlencoded (省略値) コントロール値(文字列)の配列、またはnil コントロール値を格納したCGI::QueryExtension::Valueインスタンス、または""
multipart/form-data コントロール値を読むためのTempfileインスタンスの配列、またはnil コントロール値を読むためのStringIOまたはTempfileインスタンス

問題は、次の2点。

  1. Ruby 1.6用のスクリプトがRuby 1.8で動作しない。
  2. Ruby 1.6と1.8の両方で動くスクリプトが書けない。

どうしてこういう惚(とぼ)けた失敗をやらかすのか理解できません。ライブラリでは通常、既存のプログラムが動かなくなるような事態を避けるために、すでにあるメソッドの動作は変えず、新しいメソッドを作るものです。基礎的なものであるほど変更は慎重に行わなければなりません。

それはともかく、この問題を解決するために、次の方針で臨むことにします。

  1. 既存のスクリプト用に互換メソッドを用意する。
  2. バージョンに依存しない動作のメソッドを新たに用意する。

Rubyはすでにあるクラスの定義を書き換えられるのが助かります。Ruby 1.6用のスクリプトの場合は、1.6と同じ動作になるようにCGI#[]を定義しなおします。Ruby 1.8.1でもRuby 1.8.0と非互換な変更が入っている(ふざけているの?)ので、それも潰しておきます。