まずローカルで試してからアップロードしたのだがローカルの Apacheが Ruby-1.9.0を呼ぶので、FrontPageの表示からログインまでを可能にするために加えた変更点のリストをメモしておく。
- instance_variables.each do |v| + instance_variables.each do |v| v = v.to_s;
vにシンボルが渡されて、次の行で v.sub!したときにエラーになっていた。
if page && !page.empty? - redirect(@cgi, @conf.base_url + @plugin.hiki_url( page ), session_cookie( session.session_id )) + redirect(@cgi, @conf.base_url + @plugin.hiki_url( page ), [session_cookie( session.session_id )]) else - redirect(@cgi, @conf.index_url, session_cookie( session.session_id )) + redirect(@cgi, @conf.index_url, [session_cookie( session.session_id )])
Cookieが session_id=SESSIONIDの形でなく SESSIONIDと key名なしの状態でブラウザにセットされるからログインに失敗していた。
Hiki::Command#cmd_logoutでは同じ引数を [session_cookie(session_id, -1)] としていたので同じように配列にした。
- Digest::MD5::new( s || '' ).hexdigest + Digest::MD5::hexdigest( s || '' )
リファレンスマニュアルには Digest::MD5.new([str]) とあるが引数の数が 0でないと叱られる。
when Array - "[\n"+obj.collect{|x| dump_text(x)+",\n"}.to_s+"]" + "[\n"+obj.collect{|x| dump_text(x)}.join(",\n")+"\n]" when Hash - "{\n"+obj.sort_by{|e| e[0].inspect}.collect{|k,v| "#{dump_text(k)} => #{dump_text(v)},\n"}.to_s+"}" + "{\n"+obj.sort_by{|e| e[0].inspect}.collect{|k,v| "#{dump_text(k)} => #{dump_text(v)}"}.join(",\n")+"\n}"
dumpに失敗していた。
原因となった Array#to_sのバージョンによる出力の違い↓。
Ruby-1.8.5p12> [1,2,3].to_s #=> "123" Ruby-1.9.0 20061205> [1,2,3].to_s #=> "[1, 2, 3]"
リファレンスマニュアルには
to_s self.join($,) と同じです。
と書いてあるから to_sで(ある種の) joinを代用していても仕方ない。
と思ったがどちらにしろ Array#to_sの出力は $, に依存するので、後で(loadするときに) evalすることを考えれば今回の to_sの使用は不適切か。
上のエントリで FrontPageの表示とログインまでやったが、差分の表示もおかしかったので Array#to_s らしき部分を join('') に書き換えまくったら直った模様。
'string'.join は存在しなかったので、書き換えてエラーにならないということは考えたとおり Array#to_sだったか、そのコードが実行されてなくて発覚してないが実は間違いだった(実行されたらNoMethodErrorになる)かのどちらか ^_^; こういう実行してみないとわからないところは javascriptと同じでレアなコードパスのデバッグを難しくするね。
以下、リスト。
+if(defined? ' '.ord) # Ruby-1.9 def escape_meta_char( text ) text.gsub( META_CHAR_RE ) do |s| + '&#x%x;' % s[1].ord + end + end +else + def escape_meta_char( text ) + text.gsub( META_CHAR_RE ) do |s| '&#x%x;' % s[1] end end +end
いきなり Array#to_sと関係ないが String#[index] が Integerに代えて一文字の Stringを返すようになった対策。
if digest - return View.new( diff, src.encoding, src.eol ).to_html_digest(overriding_tags, false).to_s.gsub( %r|<br />|, '' ).gsub( %r|\n</ins>|, "</ins>\n" ) + return View.new( diff, src.encoding, src.eol ).to_html_digest(overriding_tags, false).join(\).gsub( %r|<br />|, ).gsub( %r|\n</ins>|, "</ins>\n" ) else - return View.new( diff, src.encoding, src.eol ).to_html(overriding_tags, false).to_s.gsub( %r|<br />|, '' ).gsub( %r|\n</ins>|, "</ins>\n" ) + return View.new( diff, src.encoding, src.eol ).to_html(overriding_tags, false).join(\).gsub( %r|<br />|, ).gsub( %r|\n</ins>|, "</ins>\n" ) end
if digest - return View.new( diff, src.encoding, src.eol ).to_wdiff_digest({}, false).join.gsub( %r|\n\+\}|, "+}\n" ) + return View.new( diff, src.encoding, src.eol ).to_wdiff_digest({}, false).join(nil).gsub( %r|\n\+\}|, "+}\n" ) else - return View.new( diff, src.encoding, src.eol ).to_wdiff({}, false).join.gsub( %r|\n\+\}|, "+}\n" ) + return View.new( diff, src.encoding, src.eol ).to_wdiff({}, false).join(nil).gsub( %r|\n\+\}|, "+}\n" ) end
join('')か join(nil)か統一しろよ、とセルフツッコミ。
- before_change = Document.new(line[1].to_s, + before_change = Document.new(line[1].join(''), doc1.encoding, doc1.eol) - after_change = Document.new(line[2].to_s, + after_change = Document.new(line[2].join(''), doc2.encoding, doc2.eol)
if block_given? - source = yield block[1].to_s - target = yield block[2].to_s + source = yield block[1].to_a.join '' + target = yield block[2].to_a.join '' else - source = block[1].to_s - target = block[2].to_s + source = block[1].to_a.join '' + target = block[2].to_a.join '' end
block[i]は nilの可能性があるので to_a.join
if block_given? - source = yield entry[1].to_s - target = yield entry[2].to_s + source = yield entry[1].to_a.join '' + target = yield entry[2].to_a.join '' else - source = entry[1].to_s - target = entry[2].to_s + source = entry[1].to_a.join '' + target = entry[2].to_a.join '' end if i == 0 context_pre = "" # no pre context for the first entry else - context_pre = @difference[i-1][1].to_s.scan(context_pre_pat).to_s + context_pre = @difference[i-1][1].to_a.join('').scan(context_pre_pat).to_s end if (i + 1) == @difference.size context_post = "" # no post context for the last entry else - context_post = @difference[i+1][1].to_s.scan(context_post_pat).to_s + context_post = @difference[i+1][1].to_a.join('').scan(context_post_pat).to_s end
def source_lines() if @source_lines == nil - @source_lines = @difference.collect{|entry| entry[1]}.join.scan_lines(@eol) + @source_lines = @difference.collect{|entry| entry[1]}.join(nil).scan_lines(@eol)
def target_lines() if @target_lines == nil - @target_lines = @difference.collect{|entry| entry[2]}.join.scan_lines(@eol) + @target_lines = @difference.collect{|entry| entry[2]}.join(nil).scan_lines(@eol)
Hikiの設置が一段落したようなのでページの編集に取りかかる。が、こちらもすんなりとはいかない。プラグイン記法でできることが著しく制限されているのだ。
tDiaryは日記の著者を信用している(自分の日記を壊そうとする者はいないので。著者!=管理者となるレンタルサービスでは話が違って、セキュアモードでシステムを守る必要があるが)のに対し、Hikiはページ編集者を全く信用することができない。誰でも書き込めるのが Wikiだから。
そんなわけでセキュリティエラーが続発中。プラグイン記法で許されるのは単一のプラグイン呼び出しだけ。任意の文字列を埋め込むことも、プラグイン呼び出しを連ねることも、Rubyであれやこれやをすることもできない。全てをプラグインの中に閉じこめてしまい、Hikiページではそれを呼び出すしかないわけだ。(プラグインは Hikiの設置者が責任を持っているので信用されている)
{{CGI::escapeHTML @hoge.inspect}}
どころか
{{CGI::escapeHTML '<abc>'}}
ですら通らないんだから。いやはや全く。
SecurityError (Insecure: can't intern tainted string)
これは Ruby 1.9.0に固有のエラーじゃまいか。だったら Hikiの方をちょこっと変更してもいいんじゃないか?
{{hoge a b 5}} #=> hoge('a', 'b', 5) {{hoge 'a' b(5)}} #=> hoge('a', 'b', 5) {{hoge ,a(, b)(5)}} #=> hoge('a', 'b', 5) {{hoge, a, b, 5}} #=> PluginException('not plugin method: hoge,') {{hoge; hage}} #=> PluginException
文法の緩さとか、一つのメソッドしか呼べないとか、嫌すぎる。
そりゃあ Rubyで
require digest/md5
という風にライブラリ名をクォーテーションで括らずに書けたら楽だなとかは考えるし、Symbolが Stringのサブクラスになったときは
require :sqlite3
が通るのを一番に確認したけど、
defined? printf alias printg printf
を見て、
というのと同種の嫌悪を感じる。