Ruby 1.9.3-p0化にともなうトラブル

変に早起きしてしまったためか急にぽっかり時間があいてしまった。そこで、ずるずる先延ばしにしていたtypoのバージョンアップを行うことにした。

コードそのものはCapistranoでdeployできるようにしてある。でも、久しぶりのことなので念のためdeploy:update_codeなど試しておく。typo自体のテストも通してみる。いくつかfailしているが、ざっと見た上で、リリースされていることでもあるから問題ないのだろうということにした。順調。だったから。ここで、ふとRuby 1.9.3化もやってしまうかと考えたのだった。

Ruby Enterprise Edition 1.8.7-2011.03から1.9.3-p0へ。軽く考えていていたのだが、まあ実際のところ、全体的にはそう大変な作業ではなかったと思う。とはいえトラブルはあった。

最初のトラブルはRuby 1.9.3 & Passenger 3.0.9 で「Unexpected end-of-file detected」(ITS: Passenger Ruby)だった。まったく同じ状況になった。が、その分、同じ方法で回避できた。

ただ、こちらの環境はPassenger+Nginxであったため、Passengerの再インストールはNginxの再インストールにもつながり少々めんどうである。Passengerの修正を見てみたところ、ラッキーなことに、Ruby用の拡張ライブラリに対する変更だけであった。そこでこの変更を直接適用し、拡張ライブラリのみrebuildすることにした。(このことを忘れて後ではまるかもしれないが……。)

次のトラブルは文字エンコーディングに関するもの。ほとんど問題なかったのだが、管理画面のうちのサイドバーの設定の部分で例外が発生した。(サイドバーが消えさってしまったので、どうなっているか見ようとしたときに気付いた。)

ビューの中でエンコーディング非互換の例外が起きている。ビューの中にロジックがあるわけではなく、メソッド呼び出しがそのまま埋め込みになる部分だった。そのため何が起きているのか逆に把握し難い。ひとまずその場でforce_encodingして表示できるようにし、何がどのように混じっているのか見てみることにした。すると、typoのサイドバー用のレコードの一部がASCII-8BITになってしまっていること、文字化けが発生していることが分かった。

これらのレコードは1.8.7で運用していたときに保存されたものである。当然、記事データなども同じなのだが、そちらでは問題は発生していない。両者の違いはserializeされているかどうかにあり、つまりYAMLの挙動にもよるようだ。文字化けのほうは、YAML上の"\xE3\x81\x93"のような表現の解釈の違いによる。(この形式のYAMLデータがDBに保存されていた。)

YAMLの挙動を確認してみる。

Ruby 1.8.7
irb(main):001:0> YAML.load("--- \ntitle: \"\\xE3\\x81\\x93\"\n\n")
=> {"title"=>"\343\201\223"}
Ruby 1.9.3
irb(main):001:0> YAML.load("--- \ntitle: \"\\xE3\\x81\\x93\"\n\n")
=> {"title"=>"ã\u0081\u0093"}
Ruby 1.9.3 (YAML入力が!binary形式だった場合)
irb(main):001:0> YAML.load("--- \ntitle: !binary |\n  44GT\n\n")
=> {"title"=>"\xE3\x81\x93"}

問題が発生していることは確かなのだが、その場合でも、文字エンコーディングはUTF-8になる。これがASCII-8BITになってしまったのは、どこでどうしたからなのかよく分からない。はて。(!binary形式の場合、文字化けせず、ASCII-8BITになる。)

と、そうこうしているちに空き時間を使い切りそうになってしまい——結局、問題が起きたレコードがそれほど多くはなかったので、あらかじめとっておいたMySQLのダンプからコピー&ペーストにより上書き再設定を行った。

その後

もう少し調べてみようと思ったのだけど、二つの環境をいったりきたりが意外にめんどうで追求できていない。ただ、YAMLに関してはデータを移行できないケースがあることがわかった。

$ ruby1.8 -r yaml -ve 'YAML.dump("あいう", $stdout)'
ruby 1.8.7 (2010-08-16 patchlevel 302) [x86_64-linux]
--- !binary |
44GC44GE44GG

(Ruby 1.9.2)
$ ruby1.8 -r yaml -e 'YAML.dump("あいう", $stdout)' | ruby -r yaml -ve 'p YAML.load($stdin)'
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]
"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86"

(Ruby 1.9.3)
$ ruby1.8 -r yaml -e 'YAML.dump("あいう", $stdout)' | ruby -r yaml -ve 'p YAML.load($stdin)'
ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]
/home/akira/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/psych.rb:154:in `parse': (<unknown>): couldn't parse YAML at line 3 column 0 (Psych::SyntaxError)
    from /home/akira/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/psych.rb:154:in `parse_stream'
    from /home/akira/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/psych.rb:125:in `parse'
    from /home/akira/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/psych.rb:112:in `load'
    from -e:1:in `<main>'

マルチバイトというか!binaryだとまずいみたい。また、!binaryであっても配列やハッシュの中にあれば例外にはならない。