狠狠撸

狠狠撸Share a Scribd company logo
tDiaryなどの
レガシーウェブアプリを
Ruby1.9で動かす方法
藤岡岳之(xibbar)/(有)ラビックス
日本Rubyの会/Rails勉強会@東北
Open Source
Conference
24 Jan. 2009
まずご容赦
今日発表する4人の中で唯一著作を持ってい
ないことに気がついた
大したヤツではありませんm(_ _)m
つーか、3人(組)とも著作を持っているなんてす
げーよ
おそらく、よくわからんマニアックな内容を
グダグダと話すに違いない
tDiaryがまじめに対応しそうなので、セッ
ションのタイトルがピンチ
自己紹介
福島市在住
秋田県出身
福島大学教育学部出身
有限会社ラビックス
社内では何でも屋
もう7年もやってます
Ruby on Railsでソフト作っています
生粋の東北人です
ちょっと本業の宣伝
中規模向けの携帯連絡網システム
販売代理店を募集中
収益の一部をRuby財団に寄付します(そんな組織ないけど)
Rubyの活動
Matz Rubyのコミッタ
cgi.rbの担当のためだけのコミッタです(現状は)
M17N関係のバグ報告はそれなりにしているつもり
Rails勉強会@東北
日本Rubyの会関係に出没
今日は福島か
ら来ました
牛タンの
ために
Ruby会
議のため
に
というわけでアジェンダ
第1章?いかに1.9のcgi.rbが腐っていたか
第2章?改良した結果、cgi.rbはこうなった
第3章?1.9.1のM17Nはこうなった
第4章?レガシーアプリはこうやって動かせ
第1章
第1章?いかに1.9のcgi.rbが腐っていたか
第2章?改良した結果、cgi.rbはこうなった
第3章?1.9.1のM17Nはこうなった
第4章?レガシーアプリはこうやって動かせ
きっかけはReject会議
yuguiさんのセッション
1.9を使ってみてください
RejectKaigiでの
yuguiさんの布教活動
バグレポートと人柱を
必要としている
そろそろ使ってみよう
かな
Redmineもあるし
バグの報告?機能拡張の提案ができる
チケットに自動的になる
MLに自動的に流れる
誰かが担当者に振り、作業することになる
cgi.rbだと、担当者が私になります
1.8のcgi.rb
みんな使っている
Ruby on Railsでも使っている
一応ちゃんと動く
cgi.rbって何ぞや?
CGIアプリの開発を支援するライブラリ
これがないと、Content-Typeなんとかと自力で出力
する羽目になる
これがないと、「id=123&id=456&id=&str=
%40h+%3D%7E+%2F%5E%24%2F」こんなのを
オレオレunescapeする羽目になる
その他、機能いろいろあるけど省略
みんなdisっている
kwatch
cgi.rb がイケてない 12 の理由(るびま)
Matz
ruby-listとかruby-devにて
mput
ruby-devあたりで
kakutani
札幌Ruby会議にて
咳さん
自分のブログで
1.8のcgi.rbはここがダメ
テストがない
マルチパートの時のデータの受け取り方が酷
すぎる
@cgi[ name ].readみたいなやつ
遅い
これらは改良したいなぁ
1.9のcgi.rb
誰も使っていない
積極的メンテナがいない
2006年には捨てたいと言われている
まだcgi.rbを使いたい
既存のアプリがある
cgi.rbのお手軽さもよく知っている
世の中の流れはRackに行っているけ
ど、Rackにはないお手軽さもあるよ
Rack => Web Server Gateway Interface
cgi.rbでhello world
コンソールで実行すると
素直でいい子だ
この挙動がcgiの基本だと思う
そして、
1.9で使っ
てみる
まず、hello world
お、出るじゃん?
次、日本語
単純に日本語にして、実行してみる
いつものエラー
いつものエラー。こんな時はコンソールだ。
コンソールでデバッグ
これって、M17Nのエラー
気を取り直して、ソースコードのエンコー
ディングを教えてやる
マジックコメントを追加
マジックコメントを追加
マジックコメントを追加し、ソースの
Encodingを教えてやる
例外は回避したけど、
肝心の牛タンが表示されていない!
正しくはこう
コンソールで見てみよう
コンソールでの出力結果
予想通り、1.9の方のContent-Lengthの値がお
かしい
fujioka@dhcp155: /cgi-bin% ruby hello_world3.rb </dev/null
Content-Type: text/html
Content-Length: 79
<HEAD><TITLE>Hello World</TITLE></HEAD><BODY>こんにちは、
牛タン</BODY>%
fujioka@dhcp155: /cgi-bin% ruby19 hello_world3.rb </dev/null
Content-Type: text/html
Content-Length: 61
<HEAD><TITLE>Hello World</TITLE></HEAD><BODY>こんにちは、
牛タン</BODY>%
ここまでの感想
この程度のことも修正されていないなんて、
本当に誰も使っていないんだな
cgi.rbは1.9.1のリリース前に削除されてし
まうのではないだろうか?
こんな動かないライブラリ、ない方がいいでしょ?
早速行動
IRCに報告
usaさんが?x
でも、まともに動かすには大幅なテコ入れが
必要だ
kwatchさんのcgialtを参考に入れ替えたい
こっそり、1.8のテストも入れたい
テコ入れのステップ
まず、cgi.rbにテストを導入
改造する前にテストを書け by naruseさん
でも、これは手間取った
1.8とテストは共通では無理
cgi.rb本体をファイル分割
その他、問題を修正する
改善できる機能を改善する
第1章
完
第2章
第1章?いかに1.9のcgi.rbが腐っていたか
第2章?改良した結果、cgi.rbはこうなった
第3章?1.9.1のM17Nはこうなった
第4章?レガシーアプリはこうやって動かせ
cgi.rbを読んだ感想
チャレンジなコードが多い気がする
Rubyはこんな変な機能があるから使っておけ!みた
いな(例えば、継承の方がいいのに、Delegateを
使ってみたり)
スピードのことは丸っきり考慮がない
当時は、スピードが要求される場合はRubyを使って
はいけなかったんだと思う
aaa + bbb => aaa << bbb の方が早い
大まかな変更点
テストが追加(使う人は関係ないかも)
CGI.newするときに受け取るエンコーディング
を指定する(デフォルトはUTF-8)
CGI.newにブロックを与えて、例外処理を行う
ことができる
マルチパートのデータの受け取りは、IO型では
なくなった
救済措置として、readメソッドをくっつけている
CGI#outでencodingの変換はしなくなった
スピードアップをがんばった
テストが追加
今後もメンテナンスされていく上で、最も重
要なポイント
kwatchさんのCGIAltのコードを大分参考にしている
CGIというのは標準入力からデータを受け取
り、標準出力に出力する
横取りする
横取り方法
標準入力の横取り
UTF8なCGIアプリ
挙動を実演(hello_world4.rb)
EUC-JPなCGIアプリ
挙動を実演(hello_world5.rb)
Internal Server Error
受け取るデータのencoding error
/Users/fujioka/local/lib/ruby19/1.9.1/cgi/core.rb:600:in `block (2 levels) in initialize_query':
Accept-Charset encoding error (CGI::InvalidEncoding)
from /Users/fujioka/local/lib/ruby19/1.9.1/cgi/core.rb:595:in `each'
from /Users/fujioka/local/lib/ruby19/1.9.1/cgi/core.rb:595:in `block in initialize_query'
from /Users/fujioka/local/lib/ruby19/1.9.1/cgi/core.rb:594:in `each'
from /Users/fujioka/local/lib/ruby19/1.9.1/cgi/core.rb:594:in `initialize_query'
from /Users/fujioka/local/lib/ruby19/1.9.1/cgi/core.rb:752:in `initialize'
from hello_world5.rb:4:in `new'
from hello_world5.rb:4:in `<main>'
encodingを指定する
受け取るencodingを指定する必要がある
オプションはHashで指定するようにした
hello_world6.rb
例外じゃいやだ
encodingの例外を入れておく器
encodingの例外を入れる処理を
ブロックで渡してしまう
encodingをチェックし、
変換できそうだったら変換
hello_world7.rb
面倒になった
気もするが、
UTF-8で
書いておけ
multipart form on 1.8
受け取ったデータはIO型であることに注目
この仕様はひどすぎると思う
hello_world8.rb
multipart form on 1.9
ある程度、互換性は保ちたい
でも、この酷い仕様はやめてStringにする
そーだ、String型にselfを返す
readを特異メソッドで
くっつけてしまおう
de?ne_method(:read){self}
受取データはString
Stringになったので、これだけでOK
hello_world9.rb
CGI#?lesでファイル一覧
CGI#?lesでHash形式でアップロードされ
たファイルを一式取得できる
hello_world10.rb
好き放題やっている
cgi.rbはコミッタの間で利用者が少ない
特に、タグ生成メソッドあたりは好き放題で
きる
ライバルはhamlだと思っている
RSSの配信なんかもcgi.rbでささっと出力
するのが楽だと思う
もっと早くしたい
もっとよくしたい(会社が暇な時期に)
第2章
完
第3章
第1章?いかに1.9のcgi.rbが腐っていたか
第2章?改良した結果、cgi.rbはこうなった
第3章?1.9.1のM17Nはこうなった
第4章?レガシーアプリはこうやって動かせ
文字数をカウントする
1.8の時代
"牛タン".split(//u).size
=> 3
1.9の時代
irb> "牛タン".size
=> 3
irb> "牛タン".bytesize
=> 9
Rubyは真の国際言語へ!
重要なこと
RubyのM17Nの大前提です
Stringのインスタンスが
Encoding情報を持つようになった
irb(main):001:0> "ほげ"
=> "ほげ"
irb(main):002:0> "ほげ".encoding
=> #<Encoding:UTF-8>
1.9のString型
String#encoding # 現在のEncoding
String#force_encoding(encoding) # エンコー
ディングを強制変更
String#encode(encoding) # 文字列をエンコード
String#valide_encoding? # エンコーディングが
あっているかチェック
String#ascii_only? # 7bit ASCIIのみかどうか
チェック
Encoding情報を持つようになった
Encodingクラス
Encoding.list # 有効なEncoding一覧
Encoding.?nd(encoding) # encodingが有
効かどうか調べる
Encoding.default_external # デフォルト外
部エンコーディング
Encoding.default_internal # デフォルト内
部エンコーディング(xibbarは説明できない)
デフォルトエンコーディングは代入できるのだが、あまり
しない方がいいと思う
Encodingの種類
US-ASCII # ABab123などの7bit ASCII文字列
ASCII-8BIT # バイナリだと思ってOK
UTF-8、EUC-JP、SJISなど(説明省略)
外部Encoding
Encoding.default_externalのこと
1.9ではファイルをオープンする時に
Encoding情報を与える
省略された場合は
Encoding.default_externalが採用される
irb> Encoding.default_external
=> #<Encoding:UTF-8>
irb> open('/tmp/hoge.rb','r:euc-jp').read.encoding
=> #<Encoding:EUC-JP>
irb> open('/tmp/hoge.rb','r').read.encoding
=> #<Encoding:UTF-8>
外部Encodingをキメる
コマンドラインで与える
shebang行で指定する
代入する(非推奨だと思う)
環境変数(LANGとか)
% ruby19 -Eeuc-jp sample.rb
#!/usr/bin/ruby19 -Eeuc-jp #<=shebang行
Encoding.default_external=
String#encode
文字列をencodeする
破壊的に変換するので注意
irb> "ほげ"
=> "ほげ"
irb> "ほげ".encoding
=> #<Encoding:UTF-8>
irb> "ほげ".encode("EUC-jp")
=> "??"???
String#force_encoding
Encoding情報を強制変換
破壊的に変換するので注意
バイト列自体は変化しない
間違ったEncoding情報の文字列を生成できる
irb> "ほげ".force_encoding("EUC-JP")
=> "xE3x81??x81x92"
irb> "ほげ".force_encoding("ASCII-8BIT")
=> "xE3x81xBBxE3x81x92"
irb> "ほげ".force_encoding("US-ASCII")
=> "xE3x81xBBxE3x81x92"
String#valid_encoding?
Encoding情報が正しいかをチェックする
irb> "牛タン".valid_encoding?
=> true
irb> "牛タン".force_encoding("EUC-
JP").valid_encoding?
=> false
合体 その1
同じEncoding同士は連結できる
基本的に違うEncodingは連結できない
ただし、7bit ASCIIしかない場合は連結できる
irb> "ほげ"+"ふが"
=> "ほげふが"
irb>"ほげ"+"ふが".force_encoding("US-ASCII")
Encoding::CompatibilityError: incompatible
character encodings: UTF-8 and US-ASCII
> "abc"+"ふが".force_encoding("ASCII-8BIT")
=> "abcxE3x81xB5xE3x81x8C"
合体 その2
7bit ASCIIしかないASCII-8BITは連結できる
Encoding情報は柔軟に判断される
下の挙動はバグだとさ(発見してしまった)
irb> ("abc".force_encoding("ASCII-8BIT")
+"def").encoding
=> #<Encoding:UTF-8>
irb> ("abc".force_encoding("US-ASCII")
+"def").encoding
=> #<Encoding:US-ASCII>
文字列dump
上2つはただのバイト列で、Scriptの
Encodingに依存する
Marshal.dumpはEncoding情報がつく
irb> "ほげfuga".dump
=> ""u{307b}u{3052}fuga""
irb> "ほげfuga".inspect
=> ""ほげfuga""
irb> Marshal.dump("ほげfuga")
=> "x04bI"x0FxE3x81xBB
xE3x81x92fugax06:rencoding"nUTF-8"
マジックコメント
ソースコードのエンコーディングを明示する
これがないとRubyはソースに埋め込んである文字列
のencodingがわからない
1.8の時はバイト列扱いだった
2種類ある
emacs方式(# -*- coding: utf-8 -*-)
vim方式(# vim:?leencoding=UTF-8)
まとめ
Stringは常にEncoding情報を持っている
ことを意識しよう
StringをファイルなりDBなりに保存すると
きは、データを保存したいのか、Encoding
ごと保存したいのかを考えよう
日本語を含む場合はマジコメ(マジックコメ
ント)を忘れずにつけよう
第3章
完
第3章
第1章?いかに1.9のcgi.rbが腐っていたか
第2章?改良した結果、cgi.rbはこうなった
第3章?1.9.1のM17Nはこうなった
第4章?レガシーアプリはこうやって動かせ
tDiaryなどの
レガシーウェブアプリを
Ruby1.9で動かす方法
藤岡岳之(xibbar)/(有)ラビックス
日本Rubyの会/Rails勉強会@東北
Open Source
Conference
24 Jan. 2009
tDiaryが
1.9に対応
しそうだ
あっさり
転身
tDiary Hikiなどの
レガシーウェブアプリを
Ruby1.9で動かす方法
Open Source
Conference
24 Jan. 2009
藤岡岳之(xibbar)/(有)ラビックス
日本Rubyの会/Rails勉強会@東北
Hikiとは?
Before Rails世代のwiki
Rubyだけで動く
とりあえず1.8で動かす
svn co むにゃむにゃし
hikiのためにとりあえずwebrick serverを用
意
hikiconf.rb.sampleをhikiconf.rbにコピー
dataフォルダとcgiファイル名だけ設定
1.8ではあっさり起動
1.8.6で起動している
1.9ではどうかというと
日本語が入ったソースはマジックコメント必要
というわけで追加
1行目にマジックコメントを追加する
--- hikiconf.rb.sample 2009-01-19 16:56:34.000000000 +0900
+++ hikiconf.rb 2009-01-22 13:39:06.000000000 +0900
@@ -1,3 +1,4 @@
+# -*- coding: euc-jp -*-
# $Id: hikiconf.rb.sample,v 1.20 2006-07-31 13:43:20 fdiary Exp $
# Copyright (C) 2002-2003 TAKEUCHI Hitoshi <hitoshi@namaraii.com>
次
同じ類いのエラー
ちょいちょいとマジコメをつける
エラーが出な
くなるまで
マジコメる
別のエラーが出た
EUC-JPとASCII-8BITは合体できません
外部encodingを変更
Encoding.default_externalのこと
IO型を開いたときに、読み込んだデータの
encodingのデフォルト値
ruby -Eeuc-jp sample.rbとオプションを渡す
#!/usr/bin/ruby -Eeuc-jp とshebangで指定
Encoding.default_external= で指定
これをつけると、open( hoge ).readが自
動的にEUC-JPになる
WEBRickの設定を変更
hikiserver.rbで外部encodingを指定
rubybin = "#{ENV['HOME']}/local/bin/ruby19"
rubybin = "#{ENV['HOME']}/local/bin/ruby19 -Eeuc-jp"
表示された
これだけで表示だけはされた
表示はできるようだ
1.8で作成し、1.9での表示まではOK
新規ページを作ってみる
新規ボタンを押すと、、、
予定通りエラー
EUC-JPなんだから、CGI.newするときに
受信するencodingを教えてあげる
CGI::newでinitializeしてた。grepかけても見つから
ない訳だ。。。
ページの作成
こんなエラーが出た
探ってみると、
hiki/db/tmarshal.rb の中を見ると
Array#to_sを使って
いる
Array#to_sが違う
map/collectした結果をto_sとかやらない
ように
Array#joinを使うこと
% ruby -e 'puts ["aaanbbb","cccnddd"].to_s'
aaa
bbbccc
ddd
% ruby19 -e 'puts ["aaanbbb","cccnddd"].to_s'
["aaanbbb", "cccnddd"]
PStoreの独自拡張
Hikiはpstoreを独自拡張して、オレオレ
transactionを作成している
PTstore#transactionを丸ごとコメントし
て無効にしてやったら動いた
unde?ned method `commit_new' for #<PTStore:
0x40bcbc>
Please back to FrontPage.
ひととおり動くように
wikiのページの閲覧、作成ができた
まとめ
マジコメ(マジックコメント)をつける
Encoding.default_externalを指定する
UTF-8以外の時は、CGI.newする時
に:accept_charsetを指定する
それ以外は地道につぶす
String#eachとか?
第4章
完
全体的なまとめ
cgi.rbも一応動くようにはなっている
M17Nでハマらないように

More Related Content

迟顿颈补谤测などのレガシーウェブアプリを搁耻产测1.9で动かす方法