tDiary2.2 for Ruby1.9.0
昨年末から tDiary2.2 を Ruby1.9.0 で動かそうとしている。
なんとか形になったので、思い切ってこの日記を Ruby1.9.0 で動かすように切り替えた。 フッタの「Powered by Ruby version 1.9.0」に注目。 一応動いているけど、正直、何が起こっても不思議じゃない。 何かあればツッコミしてもらえると嬉しいなぁ。 ちなみに、ちゃんと Ruby1.8 とも共用できるようになっているはず。
方向性は以下の通り。
- 一つのコードで Ruby1.8 と Ruby1.9 に両対応する
- 非互換の部分は極力 compatible.rb でカバーする
- Ruby1.9 は --encoding=Binary で動作させる
自分が使っているプラグインは一通り動いたけど、それ以外のは分かんない。
インストール方法
- tdiary-full-2.2.0.tar.gz を取得する
- tdiary-core-2.2.0.patch と tdiary-plugin-2.2.0.patch を当てる
- compatible.rb を misc/lib に入れる
- 起動オプションに --encoding=Binary を付ける
- cache ディレクトリの *.parser を削除 (PStore は基本的に互換性ないはず)
これらのファイルを CodeRepos に置きたいんだけど、どこに置けばいいかなぁ。
以下、変更点の説明。
compatible.rb
Ruby1.9 で無くなったメソッドを復活させる。
unless "".respond_to?('to_a') class String def to_a [ self ] end end end unless "".respond_to?('each') class String alias each each_line end end class String def method_missing(name, *args, &block) each_line.__send__(name, *args, &block) end end
次に Ruby1.8 で存在しないメソッドを追加。こっちは Ruby 1.8 で動かすために必要。
unless "".respond_to?('force_encoding') class String def force_encoding(encoding) self end end end unless "".respond_to?('bytesize') class String alias bytesize size end end unless "".respond_to?('ord') class String def ord self[0] end end end
最後に tDiary に特化した変更。
# Ruby1.9でNKF::nkfを呼ぶと文字列のencodingが変わってしまう。 # そのため、encodingがBinaryの環境で動かすと # "character encodings differ" エラーとなる。 begin require 'nkf' module NKF alias :_nkf :nkf def nkf(option, src) r = _nkf(option, src) r.force_encoding('Binary') end module_function :nkf, :_nkf end rescue end # 日本語を含むツッコミを入れると diary.last_modified が String になる (原因不明) # (PStore 保存前は Time だが, 保存後に String となる) # 暫定的に String だったら Time へ変換する module TDiary class WikiDiary def last_modified if @last_modified.class == String @last_modified = Time.at(0) end @last_modified end end end
index.rb
$defout を $stdout に変更。 $defout は Ruby1.6 との後方互換性のためで、1.8でも非推奨。
Index: index.rb =================================================================== --- index.rb (revision 97) +++ index.rb (working copy) @@ -5,7 +5,7 @@ # Copyright (C) 2001-2006, TADA Tadashi <sho@spc.gr.jp> # You can redistribute it and/or modify it under GPL2. # -BEGIN { $defout.binmode } +BEGIN { $stdout.binmode } $KCODE = 'n' begin
update.rb
index.rb と同じ。
Index: update.rb =================================================================== --- update.rb (revision 97) +++ update.rb (working copy) @@ -5,7 +5,7 @@ # Copyright (C) 2001-2003, TADA Tadashi <sho@spc.gr.jp> # You can redistribute it and/or modify it under GPL2. # -BEGIN { $defout.binmode } +BEGIN { $stdout.binmode } $KCODE = 'n' if pos == 'detail' then
tdiary.rb
ちょこっと変更あり。
- compatible.rb をロード
- instance_variables.each が文字列でなくシンボルを返すように変更になったので to_s で文字列に変換
- eval で宣言したローカル変数が外側で読めないので、 eval 実行時にインスタンス変数への格納まで実施
Index: tdiary.rb =================================================================== --- tdiary.rb (revision 97) +++ tdiary.rb (working copy) @@ -11,6 +11,7 @@ $:.insert( 1, File::dirname( __FILE__ ) + '/misc/lib' ) +require 'compatible' require 'uri' begin @@ -466,6 +467,7 @@ load instance_variables.each do |v| + v = v.to_s v.sub!( /@/, '' ) instance_eval( <<-SRC def #{v} @@ -631,11 +633,10 @@ cgi_conf.untaint unless @secure def_vars = "" variables.each do |var| def_vars << "#{var} = nil\n" end - eval( def_vars ) + extend_vars = 'variables.each do |var| eval "@#{var} = #{var} if #{var} != nil" end' Safe::safe( @secure ? 4 : 1 ) do - eval( cgi_conf, binding, "(TDiary::Config#cgi_conf)", 1 ) + eval( def_vars + cgi_conf + extend_vars, binding, "(TDiary::Config#cgi_conf)", 1 ) end - variables.each do |var| eval "@#{var} = #{var} if #{var} != nil" end rescue IOError, Errno::ENOENT end end
misc/lib/hikidoc.rb
String#[] は文字コードではなく文字を返すようになったので、 ord メソッドを呼ぶように変更。 Ruby1.8 環境の場合は compatible.rb で対応している。
Index: misc/lib/hikidoc.rb =================================================================== --- misc/lib/hikidoc.rb (revision 109) +++ misc/lib/hikidoc.rb (working copy) @@ -476,7 +476,7 @@ def escape_meta_char( text ) text.gsub( META_CHAR_RE ) do |s| - '&#x%x;' % s[1] + '&#x%x;' % s[1].ord end end
plugin/ja/05referer.rb
前に書いたとおり、エスケープの数の問題。
Index: plugin/ja/05referer.rb =================================================================== --- plugin/ja/05referer.rb (revision 97) +++ plugin/ja/05referer.rb (working copy) @@ -31,7 +31,7 @@ <p>→<a href="#{h @update}?referer=volatile" target="referer">既存設定はこちら</a></p> <p><textarea name="only_volatile" cols="70" rows="10">#{h @conf.only_volatile2.join( "\n" )}</textarea></p> <h3 class="subtitle">#{label_referer_table}</h3> - #{"<p>リンク元リストのURLを、特定の文字列に変換する対応表を指定できます。1件につき、URLと表示文字列を空白で区切って指定します。正規表現が使えるので、URL中に現れた「(〜)」は、置換文字列中で「\\1」のような「\数字」で利用できます。</p>" unless @conf.mobile_agent?} + #{"<p>リンク元リストのURLを、特定の文字列に変換する対応表を指定できます。1件につき、URLと表示文字列を空白で区切って指定します。正規表現が使えるので、URL中に現れた「(〜)」は、置換文字列中で「\\\\1」のような「\\数字」で利用できます。</p>" unless @conf.mobile_agent?} き、URLと表示文字列を空白で区切って指定します。正規表現が使えるので、URL中に現れた「(〜)」は、置換文字列中で「\\1」のような「\数字」で利用できます。</p>" unless @con <p><textarea name="referer_table" cols="70" rows="10">#{h @conf.referer_table2.collect{|a|a.join( " " )}.join( "\n" )}</textarea></p> HTML
amazon.rb
たぶん、rexmlライブラリでエラー - 橋本幸樹のいまさら日記と同じ問題。 とりあえず force_encoding で逃げる。
Index: misc/plugin/amazon.rb =================================================================== --- misc/plugin/amazon.rb (revision 113) +++ misc/plugin/amazon.rb (working copy) @@ -205,6 +205,7 @@ xml = amazon_call_ecs( asin, id_type ) File::open( "#{cache}/#{asin}.xml", 'wb' ) {|f| f.write( xml )} end + xml.force_encoding('UTF-8') doc = REXML::Document::new( xml ).root item = doc.elements.to_a( '*/Item' )[0] if pos == 'detail' then
あとは contrib の category_to_tag.rb も一部変えてる。
追記
移行のときにテストツッコミがRSSに入ったり、RSSがテスト環境にリダイレクトされたりといくつかミスっちゃった。
追記2
自分でやっといてなんだけど、よほどの覚悟がないと Ruby1.9 で動かすのはお勧めしない。 まだまだ 1.9 の非互換な変更が入るかもしれないしね。
追記3
やっぱりまだ不具合がありそう。
- ツッコミが入った日の日記にツッコミフォームが表示されない → hide_comment_form プラグインを無効にすれば表示される
- ツッコミフォームが表示されてもツッコミが反映されない (原因不明)
- ツッコミを入れたら ruby の CPU 使用率が 70% 前後になり、処理が終わらない (強制停止したら makerss でストップ)
たださんからの嬉しいツッコミにお返事できないよ…。なのでここに書く。
ありがとうございます! 熱すぎるかも…と思っていたのですが、UTF8部ランチとマージされる頃にはちょうどいい位に冷めていそうですね。
追記4
ツッコミフォームが表示されない原因が分かった。 今の Ruby1.9 環境だと、ツッコミを入れたときに cache/*.parser に保存されるキャッシュの last_modified が Time でなくて String になってしまうという問題がある。 PStore に保存するときは Time なのに、取り出すときは(読めない) String になる。 原因が分からなかったので、 last_modified が String のときは Time.at(0) にしていたんだけど、この影響で古い日記と判断されてツッコミフォームが消えていた(SPAM対策で古い日記にツッコミできないようにしている)。