1)tDiaryなどのレガシーウェウアプリをRuby1.9で動かす方法

藤岡岳之さんの発表(発表スライドはこちら)

  • cgi.rbのコミッタの方
  • m17n関連のバグ報告を実施
  • Rails東北の勉強会を募集

1.いかに1.9のcgi.rbが腐っていたか

  • 昨年のRuby会議でYuguiさんの話されたRedmineの話がきっかけ
  • バグレポーと人柱募集で奮起

1.8のcgi.rbは基本的に誰でも使うし、RoRでも使っていて基本的に動く
(Merbは使ってないけど)
ただし、各方面で現状の内容はよろしくないといわれている

1.8のcgi.rbはこんな点がだめ

  • テストが無い
  • マルチパート時のデータ受け取り方が酷い
  • 遅い

1.9のcgi.rb

  • 誰も使っていないし、だれもメンテナンスしてない

まだcgi.rbを使いたい

  • 既存のアプリがある
  • cgi.rbのお手軽さもある
  • 世の中ではRackに流れているけど、cgi.rbにも良さがある

1.9でcgi.rbを使ってみる

  • html出力は出たが、日本語が混ざると出ない
  • M17Nでエラーが出ている(マジックコメントの追加)
  • 「牛タン」の文字が表示されない!
  • Content-Lendthが短く出力される!
  • この時点で誰も使っていない事を確認。1.9.1では削除される危機

行動した事

  • IRCに報告し、usaさんがfix
  • 本格的に使うにはてこ入れ必要だった

てこ入れ

  • cgi.rbにテストを導入
  • 1.8とテスト共通化は断念(マルチリンガルが問題)
  • cgi.rb本体をファイル分割
    • erb使う人はhtmlジェネレーターは不要だったりするから
  • その他の問題に対応

2.改良した結果cgi.rbはこうなった
cgi.rbを読んだ感想

  • 通常使われていない機能が沢山使われている(継承よりDelegateを使ってる)
  • スピードへの考慮が無い
    • "aaa"+"bbb"より "aaa"<<"bbb"の方が早いんだが全く使われていない

大まかな変更点

  • テストを追加
  • CGI.newするときに受け取るエンコーディングを指定出来るように
  • CGI.newにブロックを与えて例外処理を行える
  • マルチパートのデータ受け取りはIO型では無くした
  • CGI#outでencodingの変換はやめた
  • 高速化対応

テストを追加

  • kwatchのCGIAltのコードを参考にテストコードを追加した
    • (標準コードを横取りしてる点が素敵)

文字コード対応

  • マジックコメントだけでなくCGI.newするときに受け付ける文字コードも指定する
  • プログラム内で文字コードを書き換える工夫も少し面倒だがかけるようにはなった

multipart form on 1.8

  • 現状はマルチパートになるとIO型になっているので改良したい
  • ただし互換性が1.9版で完全になくなるのは困るのでは?
  • 戻り値をstringにするけれど互換性用に.readを追加してある!
  • CGI#filesでアップロードされたファイルが一覧で取れる(Hash形式で入っている)

3.1.9.1のM17Nはこうなった
文字数のカウント変わった(国際化言語対応に!)

  • 1.8 "牛タン".split(//u).size =>3
  • 1.9 "牛タン".size =>3 "牛タン".bytesize =>9

1.9のString型
Encoding情報を持つようになった為に変わった部分

  • String#encoding
  • String#force_encoding(encoding)
    • 破壊的にEncoding情報を変換する。バイト情報は変更しないので注意
  • Strind#encode(encoding)
  • String#default_external
    • 文字コードを指定しないでファイルを読み書きした場合等
  • String#valid_encoding?
      • バイト情報とEncoding情報が一致しているか検査

 
Encodingクラスが新設

  • Encoding.list = 有効なENcodingリスト
  • Encodingの種類
    • US-ASCIi
    • ASCIi-8bit
    • UTF8,EUC-JP,SJIS


文字列dump

  • String.dumpだとEncoding情報が保存されない
  • Marshl.dumpmだとEncoding情報付きで出力されるので二つの違いに注意

マジックコメント

  • これがないとRubyはソースに埋め込んである文字列のEncodingが分からない
  • 指定の方式は「emacs方式」と「vi」方式の2つがある

まとめ

  • Stringは常にEncoding情報を持っている事を意識
  • StringをファイルやDBに保存する時はデータを保存したいのかEncodingごと保存したいのかを意識することが重要
  • 日本語を使う時にはマジックコメントをつけるようにすること

4.レガシーアプリはこうやって動かせ
tDiaryは本家が1.9に対応するのでHikiを1.9対応することに転身

  • euc-jpで書かれているのでそれに対応するマジックコメントを追加
  • これをひたすら続ける(マジコメる!)
  • そのうちEUC-JPとASCII-8BITの合体ができないってなエラーがでる
    • String#default_externalを定義してやると動く
    • WebRickで動かしていたのでWebRickにdefault_externalを追加
  • データ受け取りの文字コードが指定されていないので新規ページができなかった
    • CGI.newが無かったので気がつかなかった
  • 独自マーシャルが実装されていてそこでもエラーが
    • Array.to_sの挙動が1.8と1.9で変わっているために発生
    • Array.joinに変更
  • pstoreを拡張して独自transactionを使っていてそこでエラー
    • 独自部分をコメント化して、オリジナルを使うと動作

5.まとめ

  • マジコメをつける
  • Encoding.default_externalを指定する
  • UTF-8以外を使うときはCGI.newする時に:accsept_charsetを指定する
  • それ以外の仕様違いは地道につぶしてゆく
  • cgi.rbは1.9系で一応動くようになった
  • M17Nでハマらないように注意しましょう

6.質問
 Q.マルチパートのデータを上限無くメモリに確保するのはまずいのではないか?
 A.上限値を制限出来るようにしたので無限にメモリに確保するようにはなっていないです

 もう1個質問がありましたけど、メモ漏れ(ToT)