/ 最近 .rdf 追記 設定 本棚

log[tDiary: 2009-08-16]



20090816() トゲ界隈で蔓延しているようだが一抹の抵抗を試みる課金をするのはサービスの提供者~を課すっていうじゃないあなたは支払い義務を課されてるんだよと書こうとしてあれ課する? 課(おお)す? なにそれ

最終更: 2009-08-28T23:41+0900

[tDiary] セクションごとに最終更新日時を(セクション単位の編集機能とからんでカオ)

表示方法はこう

# coding: utf-8
require 'date'
add_section_leave_proc{|date, index|
  diary = @diaries[date.strftime('%Y%m%d')]
  next unless diary # in case @mode == 'preview'
  section, sidx = nil, 0
  diary.each_section{|sec| sidx+=1
    if sidx == index
      section = sec
      break
    end
  }
  lm = section.last_modified rescue next
  next unless lm
  lm = DateTime.new(*(lm.utc.to_a.values_at(5,4,3,2,1,0))).new_offset(Rational(135,360)) # 日本時間
  lm.strftime %<<p class="lastmodified">最終更新: %Y-%m-%dT%H:%M%Z</p>> # 色分けテストとして、あえてタグと同じアングルブラケットで囲ってみた。
}

DateTimeのオフセトの単位がわからんかったブラウザのブックマークRubyリファレスマニュアル - 20051129だからなあるりまには載ってるかもとりあえfraction of a day(date.rb documented by William Webber)とのこと慣れない Rationalを使ったもんだから Rational(135,360)と書くべき所に Rational(135/360)と書いてしまいオフセ0の結果にしばし首をひねったRational()の呼び出しより引数の評価の方が先だからやむをえないことだけど分数を表現するのにはやっぱり / を使いたい(使ってしまった)FixnumBignumのシームスな移行のように Rationalへも融通無碍に切り替わって欲しい利用者には Numericだけを利用しているように思わせるということ必要なときに整数化(小数化)メソドを呼ぶし変数に整数(や分母を 1に約分できる分数)が入ってることを利用者が知っていればそのまま整数を前提としたメソドを呼んだりできるといい変わるのは整数型の演算結果が整数型であることを前提にした(旧来の言語の呪縛に過ぎない)切り捨て除算がなくなる以外にあるだろうそれも Pythonみたいに // を割り当てれば無駄な有理数化再整数化を避けられる実感に基づいて既に通った(んじゃなかったっけな?)議論を蒸し返してみました俺は整数と小数の垣根を取っ払った JavaScript最初は驚いたけど評価しているJavaScriptのシンプルさが好きだセミコロンインサーションもCより怠けることを許していながらRubyの改行をターミネータにするやり方よりフーマトが自由で最高にバラスがいい(はまるのは returnだけだ)require 'rational'; 10.to_r/2 とか不格好すぎるでしドウェアと型から離れて本質に戻りましょう算数で割り算と分数は同じものだったはずだ。<追記@2009-08-22>require 'mathn' がつまり FixnumBignumRational(と Complex)をより親密にするおまじないでした(いまさら何を)mathnって読めない(マスエヌ?)のと名前から中身が想像できないのとで意識せず無視してたけどRationalとセトで見かけることが多かった気がするそれはそうとRationalComplexの細々した議論に埋もれて全体の方向性が見えないRuby 2.0あたりでは require 'mathn' が不要になっているんだろうか……。</追記>

るりまにはスタドアロンサーバー版と chm版よりスタック HTML版を用意して欲しいなあchmだと閲覧が IEースになってしまって文字の大きさやスクロール量進む戻るが自由にならなくて使いにくいマニュアルサーバーを起動しておくのは嫌ですよview.cgiCGIしようとしたらリンクがルトからの絶対スなせいで Not FoundApacheは既に動いてるから名前ベースのバーチャルホトや待ち受けポトの追加でるりまに一つのホ(or)を与えることはできると思うけど……大仰なのでやらないbase_urlのオプションが用意されてるから view.cgiの設定を間違えてるだけの気もするけど……わからない

組み込みの TimeUTClocaltimeしか扱わないのがもったいない任意のオフセトに基づいた日時を出力したいだけだからDateTimeは牛刀な印象がある。<追記@2009-08-21>ーくかんがえよ(命令形)・・・・・・・・なんてことはないオフセト分だけ未来(過去)UTC時刻が即ちローカルタイムだよ当たり前すぎて俺が何を言いたいのかわからないでしょう先のスクリト片の最後は DateTimeを使わずにこう書けるということです。

  lm = section.last_modified rescue next
  next unless lm
  offset = 9 * 60 * 60 # 秒
  lm_local = (lm + offset).utc # UTCと見せかけて lmの地方時。
  %<<p class="lastmodified">最終更新: %d-%02d-%02dT%02d:%02d%s%+03d%02d</p>> %
    [lm_local.year, lm_local.month, lm_local.day, lm_local.hour, lm_local.min, offset/60/60, offset/60%60]
}

……てなことをmakerss.rbの中の TDiary::RDFSection#time_string

  g = @time.dup.gmtime
  l = Time::local( g.year, g.month, g.day, g.hour, g.min, g.sec )

gmtimeに基づく年月日時分秒からローカルタイムを作っている部分を見ていて(遅まきながら)気付いたgmtimelocaltimeも皮をむけば UNIX epochからの経過秒に過ぎないんだからどういう意味を持たせるかはこちらの自由だった。まあ比較はできなくなりますが……(lm.to_ilm_local.to_i はその意味(同じ瞬間の別表現であること)を考えると望ましくない結果)</追記>

脱線終了表示するまでの仕込みがこんな感じ

add_last_modified_to_every_section@defaultio.rb (2.4KiB)
日記の一日分のデータの一部としてその日のセクションの更新日時をまとめて記録しているWikiStyleのフーマトの一部として更新日時や著者名を埋め込む方法があればそちらの方が利用者の自由度は高い
新設したヘッダ(Sections-Last-Modified)と日記の本文とが連動しているので tDiary以外から *.td2をいじりにくくなっている
add_last_modified_to_every_section@wiki_style.rb (1.7KiB)
都合が良いように変更
add_last_modified_to_every_section@tdiary.rb (10.6KiB)
っちゃりもちろん*今の*自分にとってはそうではない
tdiary_style.rbを変更してないから TDiarySection#last_modifiedは未定義tDiaryスタイルでも日記を書いてみて見つかったエラーは rescueした

主に plugin/makerss.rbからの要請で更新日時を記録したいのでっとした修正では最終更新日時は更新されないとかいいながらこの日記には変更のあったセクションを見つける別の方法が入っている(20090705p01)ので makerss.rbが最終更新日時を利用するようにはしていない


最初にポトされた時刻も有用だろうか? 日記だから最初にポトされた日はほとんど確定してるし時刻まで知りたいとも思わないけど


WikiSectionlast_modifiedプロパをくっつけたけどWikiSection自体はこれを管理してなくて外部から操作されるだけだってのがいけてないっぱり to_src()initialize()DUMP & LOADを担う(last_modifiedauthorその他の情報をフーマトに含める)メソド群を整備してこちらの望む操作を WikiDiaryWikiSection自身にやってもらう(自分でやるから付帯情報のコピー漏れも発生しない道理)のがいい


 2009-08-22

「編集でセクションを追加したとき更新日時のコピー処理でのぬるぽを修正(if old_section and...を追加し)


20090806()

[tDiary] tdiary.rbplugin/navi_user.rbにパッチあて(plugin/recent_list.rbの分は使用してないのでスル) + セクションごとの最終更新日時に一票

 > Re: [tDiary-devel] all_filtersとかload_pluginsが呼ばれ過ぎで遅い件

速くなると聞いては捨ておけぬ

category_anchorでの nil.yearエラーは起こったのがカテゴリモドだったら既知だけど最新N日表示だから違うしTDiaryBase@dateは読み出し専用プロパだから(navi_user.rbのような荒技を使ったりしない)プラグインには変更できないし……(結局わかりませ)

 セクションごとの更新日時

plugin/makerss.rbが直前に変更のあったセクションの他に過去にちっとした修正のあったセクションを *.rdfのエトリに加えてしまうのを防げるので賛成一度考えた回避策はちっとした修正が *.rdfに反映されてしまうので影響が大きくて断念したし

 「編集」や「追記のときにどうやったら変更のあったセクションを見つけられるだろう(編集機能は一日単位だか)
  1. *.td2から読み込んだ AnyStyleDiaryPOSTされたソースに基づく AnyStyleDiaryを両方に並べて
  2. each_sectionしながらセクションを全文比較
  3. 一致すれば td2から読んだ古い方の最終更新日時を POSTされた新しい方の AnyStyleDiaryにもセ
  4. POSTされたソースに基づく方を *.td2に書き込む

という手順を考えた

セクションインデックスがずれるような変更だった場合は影響範囲が無駄に大きくなるけどセクションインデックスはセクションIDを兼ねているのでやむなし(URLって変わっちってますから)

新規作成や修正されたセクションに適用される最終更新日時を一回「編集」や「追記につき一つに限らないとupdate_procの中で変更のあったセクションを見つけるときにアバトな処理をするはめになりそう(心配しなくてもそうはならんでしょう)


20090721() ハルヒのエスエいつまで続くんだろうF1もテニスも野球もサッカーも似たようなことの繰り返しなんだし野球を 2時間見るより(<見たことないけど)断然面白く見られるけどね

[Amazon][tDiary][Ruby] 徒労劣化コピamazon.rb差し替えSecretKey埋め込みなのでパーミッションは rw-------

先人 > Amazon Product Advertising APIの認証の件 - zorioの日記

Ruby-1.8.7Ruby-1.8.6では String#force_encoding("ASCII-8BIT")ができずString#ordもない(ないのはエンコングの概念がないからとString#[]で代替できるからだと思われる)それらを使い分けるために 2種類のメソドを用意するくらいならunpackで配列経由でいいです。

require 'digest/sha2'
def hmac_sha256(key, message)
	hash = Digest::SHA256
	hash_block_size = 64 # bytes (= hash.new.block_length)
	key = hash.digest( key ) if hash_block_size < (key.bytesize rescue key.size)
	ikey = Array.new( hash_block_size, 0x36 )
	okey = Array.new( hash_block_size, 0x5c )
	key.unpack("C*").each_with_index{|key_byte, i|
		ikey[i] ^= key_byte
		okey[i] ^= key_byte
	}
	inner_hash = hash.new.update( ikey.pack("C*") )
	outer_hash = hash.new.update( okey.pack("C*") )
	digest = outer_hash.update( inner_hash.update( message ).digest ).digest
	return digest
end

短い秘密鍵は 0を補うって書いてあったその処理が見あたらないのになぜうまくいくのかと考えたら0を相手に排他的論理和をとったって何も変わらないのねん


class Digest::Base

update(str)
self << str
文字列を追加するself を返す。複数回updateを呼ぶことは文字列を連結してupdateを呼ぶことと等しいすなわち m.update(a); m.update(b)m.update(a + b) m << a << bm << a + b とそれぞれ等価である

Ruby-1.9で文字列の連結は怖いので m.update(a + b)m << a + bDigest::SHA256.digest(ipad + message) は避けたい


302 Foundはわかるリバースプロキシは何するもの?


 追記@2009-08-04: 他の部分も

require 'uri'
require 'base64'
def amazon_authenticated_query_string( host, params )
	re_rfc3986_unreserved = /[^A-Za-z0-9\-_.~]/
	query_string = params.to_a.sort_by{|x| x.first }.map{|key, value|
		URI.encode(key, re_rfc3986_unreserved) +'='+ URI.encode(value, re_rfc3986_unreserved)
	}.join("&")
	string_to_sign = <<-"STRING_TO_SIGN".gsub(/^\t\t/, '').chomp
		GET
		#{host.downcase}
		/onca/xml
		#{query_string}
	STRING_TO_SIGN
	amazon_secret_access_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
	signature = Base64.encode64( hmac_sha256( amazon_secret_access_key, string_to_sign ) ).chomp
	return "#{query_string}&Signature=#{URI.encode(signature, re_rfc3986_unreserved)}"
end

20090705() FEDERERでしたそれまでブレイクしてたのは RODDICKったのにファイナルセトでできなかった

[tDiary] makerss.rb: 更新したつもりのないエトリまでが上がってくる理由

ある日のエトリの一つを更新すると同じ日の他のエトリまでが更新されたとして上がってくる理由たぶんそれまでに他のエトリ「ちっとした修正を行っていたのだろうmakerss.rbを見てみたら

add_update_proc do
	makerss_update unless @cgi.params['makerss_update'][0] == 'false'
end

っとした修正では日記の更新時に何も行っていないこれを、index.rdfの更新はしないけど cache/makerss.cacheの更新はするというふうに変えられないだろう


目的は以前に加えたちっとした修正と今回の普通の更新で加えた変更とを区別するため


編集対象のセクションを特定できるならcache/makerss.cacheを常に更新することで以前のちっとした修正を検出しなくなるようにする必要はないしむしろ LDRのようにドの内容の一字一字を比較するリーダ?(ドアグリゲータ?)まで騙すことを考えるとcache/makerss.cacheの内容はちっとした修正以前の古いままにしておく方がいいみたい


ゃあなぜ既にセクション単位で編集を行ってるこの日記で直前の編集に関係していないセクションまでが上がってくるのか? makerss.rbの変更まで手を回す前にやる気が尽きたから

update_procに引数の追加が必要なんだけど改めて具体的に考えてみると単純にセクションナンバ1つを渡せばよいというものでもなさそうだセクション2を編集した結果セクション2がなくなってセクション32に繰り上がってる可能性があるセクション2が分裂してセクション23になってる可能性がある

LDRといい update_procの引数といい万全を期すと二進も三進もいかんなあ(LDRは使ってないから外せない問題ではないしupdate_proc{before=>2, after=>2..3} を渡すだけで済んでしまう気もするけ)


ああafterの範囲を確定するのが難しいんだ変更前に編集対象のセクションの前にいくつ後にいくつのセクションがあるかを数えておく手があるけど場合によったら直前のセクションと結合してしまうことがあるからなあ(セクション2を編集していたはずがセクション2を削除してセクション1に追記したことになってる可能性がある)この場合セクション1に変更があったことは無視してセクション2が削除されたことだけを考えていいならっぱり前後のセクション数を数えておく方法でよさそうだ


makerss.cacheは二つの目的を持ってるんじゃない変更のあったセクションを検出する目的と *.rdfのソースにする目的

そもそも*.rdfのソースは *.rdf自身で十分じゃないか?(深くわかってるわけじゃないけ) これに変更のあったセクションを特定できる引数が update_procに加わったら makerss.cacheを用済みにできない


できない一日単位の編集機能をなくせるわけじゃないから今と同等の変更検出機能は必要そうすると *.rdfのソースを makerss.cacheから *.rdfにスイッチする必要もなさそうに思えるけど……ないかも(っかりドに紛れ込んだテトコメトは index.rdfからアイムを削除するのでなくコメトを非表示にすればあとあと甦ってくることもなかったん)


 整理

makerss.cacheは二つの役割を持っている

  • 変更のあったセクションを検出する
  • .rdfのソースにする

変更のあったセクションの検出能力に難があったので改善を試みる一日単位の編集機能が存在し続けrdfのエトリの単位がセクションである限り変更のあったセクションの検出能力の向上は無駄にならない

makerss.cacheの日記内容をちっとした修正でも更新する

これでちっとした修正のあったセクションの誤検出はなくなるだがこの makerss.cacheをもとに *.rdfを作成するとエトリの内容がちっとした修正後のものになりLDRなど RSSーダーによる過剰検知の原因となる

*.rdfのソースを *.rdfにする

右から左に流すだけでは過剰検知の起こりようがないドを更新するときにどんな問題が発生するだろう……手順を考える

  1. makerss.cacheとの比較を基に追加変更のあったセクションを特定する
  2. .rdf内のエトリから削除された(現在のセクション数から考えられるより大きいセクションナンバーを持つ)セクションを取り除く
  3. 追加変更されたセクションを .rdfのエトリに変換する
  4. .rdf内に対応するエトリがあれば上書きなければ追加し.rdfの先頭に移動する
  5. トリ数の上限まで書き込

問題はドに含まれる日記やコメトを隠したりセクションを削除したりするとエトリ数が上限より少なくなるだけだろう最初は無理そうに思えたけどなんだったんだろう


makerss.cacheから読み込んだものと *.rdfから読み込んだものとは Rubyオブジトか文字列かという違いがあるんだなあでもそれが意味を持つのは MakeRssNoComments#itemで呼ばれる rdfsec.section.respond_to?( :body_to_html )だけみたいだからここを rdfsec.id.index("p") に置き換えれば *.rdfから読み込んだ xml文字列だけで makerss.cacheの代わりができそう


 整理(Plan B)

セクション単位の編集機能がありmakerss.rbupdate_procの引数から変更のあったセクションを知ることができれば今以上の変更のあったセクション検出能力は特段必要ではない

makerss.cacheはこれまで通りちっとした修正では更新されずLDRをちっとした修正以前の古い内容でだまし続けることが可能

日記の書き手はドの更新を伴うデリケトな編集作業ではセクション単位の編集を行うことで余計なセクションが上ってくることを避けられる

っちが断然楽そうだでも自分の環境で閉じてしまうから代替案なんだよね


トル(log)にふさわしい垂れ流しっぷりじゃあないですか?


 ををバグってる

はるか上の方でこう書いた

場合によったら直前のセクションと結合してしまうことがあるからなあ(セクション2を編集していたはずがセクション2を削除してセクション1に追記したことになってる可能性がある)

http://vvvvvv.sakura.ne.jp/ds14050/diary/20090705p01

何を見て書いていたかというと……

223
224
225
226
227
228
229
	unless body1.empty?
		current_section = @sections.pop
		if current_section then
			body1 = "#{current_section.body.sub( /\n+\Z/, '' )}\n\n#{body1}"
		end
		@sections << WikiSection::new( body1, author )
	end
http://tdiary.svn.sourceforge.net/viewvc/tdiary/trunk/core/tdiary/wiki_style.rb?revision=3381&view=markup

解説解説

223
224
225
226
227
228
appendされた Wikiソースがサブタイトルを持っていないもの( body1 )だったら、
最後のセクションを取り除き

最後のセクションの本文( current_section.body, サブタイトルを含まない )と body1を連結し、

新しいセクション( サブタイトルなし )として追加する。

WikiSection#bodyの代わりに WikiSection#to_srcを使わないとサブタトルが消えてしまう

226
			body1 = "#{current_section.to_src.sub( /\n+\Z/, '' )}\n\n#{body1}"

サブタトルのあるセクションにサブタトルのない本文を追加したときにサブタトルのないセクションができあがるのを防ぎます > fix_and_test_append_without_subtitle.diff


 Plan B 仮実行中

セクション単位の編集機能が追加されていることが前提そのせいでこの日記でしか使えないから気乗りしなかったんだけど第一案が手詰まりなのと一つの実験場として可能性を示すために

update_procupdated_sectionというパラメータを追加しmakerss.rbが過去のちっとした修正を誤検出するのを防ぎます > add_param_updated_section_to_update_proc.diff


20090306()

[Ruby][tDiary] > tDiary: ニコ動プラグインが動いてな? - ただのにっき(2009-03-05)

試してみたSecurityErrorが出たリンク先の ruby-1.9.1とは違いこちらは ruby-1.8.7-p72でのエラー内容

>irb
irb(main):001:0> require 'open-uri'
=> true
irb(main):002:0> $SAFE=1
=> 1
irb(main):003:0> open 'http://vvvvvv.sn25p.dip.jp/301.rb'
SecurityError: Insecure operation - []
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:577:in `[]'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:577:in `find_proxy'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:147:in `open_loop'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:164:in `call'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:164:in `open_loop'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:162:in `catch'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:162:in `open_loop'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:132:in `open_uri'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:518:in `open'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:30:in `open'
        from (irb):3
irb(main):004:0>

301.rbはこう

#!ruby
require 'cgi'
cgi = CGI.new;
print cgi.header({
	'Status' => '301 Moved Permanently',
	'Location' => 'http://vvvvvv.sn25p.dip.jp/index.html'
});

トネームを指定しない場合は大丈夫だった例えばこんな

#!ruby
require 'cgi'
cgi = CGI.new;
print cgi.header({
	'Status' => '301 Moved Permanently',
	'Location' => '/index.html'
});

どこまで by designなんだろう


20090226()

[tDiary] なにかおかしいーバーのRuby? 俺の書いたスクリト? 改行コド?

過去にこんなことを書いた

過去の日記「編集するとその日の全てのセクションが rdfに上ってくるのねtDiary-2.3系の目玉はセクション単位での編集機能だなあ

log[2007-12-31-p01] RSSを出力するように

セクション単位の編集機能を実装しおえてmakerss.rbの対応もやっとくかとソースを読んでみたらきっちり内容比較をしていただから当然変更されたセクションのみが RSSで上に上がってくる一文字も変更せずに日記を送信した場合RSSも更新されないーカルの tDiaryで確認したでもサーバ( http://vvvvvv.sakura.ne.jp/ds14050/diary/ )ではそうなっていない過去に書いたとおりどんな場合でもその日のすべてのセクションが上がってくる

そういえばこんなこともあった

日記を更新するとTDiary::Config#data_path/category/ 以下のカテゴリごとに作られるキッシュファイルがずいぶんたくさん更新される全部ではないが半分近い 21のファイルが更新されていた日記の内容はというと一つのカテゴリしか使っていない

log[2007-12-25-p01] PStore, category.rb: 日記に変更があるたびにカテゴリキッシュファイルが一斉に更新されるのをなんとかする

根が同じかどうかはわからないがなにかがおかしい


そういえばmakerss.rbの作成するキッシュファイルもカテゴリインデックスと同じ PStore形式だったにおうにおうぞ


必ずしも上がってくるというものでもないみたいーバーの makerss.rb概ね期待通りの動作をしているうにゅう

あまりに古い日記を編集していてmakerss.cacheから記事が掃き出されているために変更の有無を確認できないというのとも違うんだけど……と思うんだけど(もういい)


とりあえず内容を比較する前に stripしてみたこれで様子見(複数のエトリが同じ時刻に更新されたかのように記録されることがなくなければ O.K.)

if cache[id].section.body_to_html.strip != section.body_to_html.strip or
		cache[id].section.subtitle_to_html.strip != section.subtitle_to_html.strip then
	cache[id] = RDFSection::new( id, Time::now, section )
end

最終更: 2009-12-10T00:55+0900

[tDiary] この日記では一日一エトリールールを採用していません

ールを守るために未来日記を書く人もいるようですがこれはあくまで普通の日記だし書いた日付と内容は切り離せないので一日に複数のエトリを書いたりもします。だから、セクション単位での編集機能をもちろんブラウザで

 edit_section.diff

編集画面プレビー画面プレビー画面(競合あ)登録画面(競合あ)
edit_section_screenshot(edit).pngedit_section_screenshot(preview).pngedit_section_screenshot(preview,conflict).pngedit_section_screenshot(append,conflict).png

変更内容はこのような感じ

 section=n (n=1,2,...)パラメータ追加

例えば2009226日の第1セクションの編集フームへのリンクはこうなる

update.rb?edit=1;year=2009;month=2;day=26;section=1

 編集対象セクションの変更を検知

現在編集中のセクションが他の人によって書き換えられていたりセクションの挿入や削除によってセクションナンバーが変わっていたときはエラーメッセージを表示して(プレビー画面でも確認可能)変更をコミトしない(「戻るの後でも直前の編集内容が残っているかどうかは使用しているブラウザ次)

 著者情報を保存

従来の一日単位での編集では失われていた*著者情報がセクション単位の編集では保存される(編集対象のセクションは一番最後の変更者名にな)

ついでにある日の編集フームを利用して別の日に追記したとき――編集画面で日付を書きかえた後、この日付の日記を編集ボタンを押さずに、登録ボタンを押すことで可能――記録されていなかった*著者名も記録する

 Big5わかりません

というわけでskel/update.rhtml.zhskel/preview.rhtml.zhは手つかずなので従来の編集画面と機能になる

skel/update.rhtml.enskel/preview.rhtml.enは書きかえたけど動作未確認

 wikiスタイルでしか試していません

とはいえスタイル関連で利用するメソドは each_sectionappendreplaceだけなので動くはず(期待)

ただDiary#to_srcSection#to_srcを単純に連結したものであるという仮定をおいてしまっているのだが新旧wiki_stylerd_styleemptdiary_stylehatena_stylemarkdown_styleは大丈夫なもののetdiary_styleは少しだけ違っているのが若干気になる(といっても末尾の改行を一つにまとめてるだけなんだけ)

 [このセクションだけを編集]ボタンは[この日付の日記を編集]ボタンと同じもの

type="submit" name="edit"

上記が共通部分(ボタンのラベルも送信されるけど使われないので違ってて構わな)


 セクションの著者情報ってどこに保存されてるの?

新旧Wikiスタイルの場合*.td2にはないよね

tdiary_styleの場合書き出される(TdiarySection#to_srcに含まれる)けど読み込んだらカテゴリの一つになってしまいそう

etdiary_styleも書き出すけど読み込みは考えてなさそうEtdiarySection#initializeに明示的に authorを渡しても使われない

不毛だ


プラグインの表示したフームを送信すると次の画面が普通の一日分の編集画面になる<input type="hidden" name="date" value="yyyymmdd"> というようなフームを埋め込む責任が個々のプラグインに委ねられているのでどうしようもない

TODO: 元の画面に戻ることを保証することとプレビー画面に form_procを表示すること

プレビー画面への form_proc表示はもうやってるしform_procを利用したファイルのアップロドを別タブの編集画面でやれば変更内容が失われる心配もないってるから困らないけどわかりにくいのは確


 plugin/edit_section_link.rb

一日表示のときセクションごとに編集リンクを付ける

add_subtitle_proc {|date, section, subtitle|
	subtitle += %Q(<span class="adminmenu edit_section"><a href="#{h @conf.update}?edit=1;year=#{@date.year};month=#{@date.month};day=#{@date.day};section=#{section}" rel="nofollow">[edit]</a></span>);
} if @mode == 'day';

サブタトル(<h3>の中)に関係のないテキトを加えるよりサブタトルの直前に挿入されるこっちの方がいいかも

add_section_enter_proc {|date, section|
	%Q(<span class="adminmenu edit_section"><a href="#{h @conf.update}?edit=1;year=#{@date.year};month=#{@date.month};day=#{@date.day};section=#{section}" title="edit (author only)" rel="nofollow">✍</a></span>);
} if @mode == 'day';

*,(2) 未確認


20090223()

[Ruby][tDiary]ruby-1.9.1不思議で困ったことが起こった

問題のコ(再掲)はこれあるハッシュのキーについて繰り返しているのにッシュにそのキーが存在しない(すべてのキーが見つからないわけではないが見つからないキーはいつでも見つからな)

categorized.keys.each do |c|
	PStore.new(cache_file(c)).transaction do |db|
		categorized.fetch(c) #=> key not found (KeyError)
		db['category'] = {} unless db.root?('category')
		db['category'].update(categorized[c])
	end
end

fetchをブロックの最初に持って行くとそこではエラーにならない

categorized.keys.each do |c|
		categorized.fetch(c) #=> O.K.
	PStore.new(cache_file(c)).transaction do |db|
		db['category'] = {} unless db.root?('category')
		db['category'].update(categorized[c])
	end
end

cache_file(c)の呼び出しが原因その中でも includeしてある ERB::Utilu()メソドが核心

categorized.keys.each do |c|
		::ERB::Util.u(c)
		categorized.fetch(c) #=> key not found (KeyError)
	PStore.new(cache_file(c)).transaction do |db|
		db['category'] = {} unless db.root?('category')
		db['category'].update(categorized[c])
	end
end

引数にした文字列のエンコングが変わってしまっている

categorized.keys.each do |c|
		enc1 = c.encoding;
		::ERB::Util.u(c)
		enc2 = c.encoding
		categorized.fetch(c) { raise "#{enc1} #{enc2} #{::ERB.version}" } #=> UTF-8 ASCII-8BIT erb.rb [2.1.0 2009-01-11] (RuntimeError)
	PStore.new(cache_file(c)).transaction do |db|
		db['category'] = {} unless db.root?('category')
		db['category'].update(categorized[c])
	end
end

ERB::Util.url_encodeの定義を見ると引数の文字列を dupした後にエンコングを変更しているにも関わらず呼び出し元に影響を与えてしまっている

    def url_encode(s)
      s.to_s.dup.force_encoding("ASCII-8BIT").gsub(/[^a-zA-Z0-9_\-.]/n) {
        sprintf("%%%02X", $&.unpack("C")[0])
      }
    end
    alias u url_encode

そんなわけだから呼び出し側(category.rb)

u( c.dup )

なんてやっても効果はなく

u( ""+c )

あるいは

u( "#{c}" )

とやって初めて今回の現象を回避することができた

これは、文字列の複製を遅らせた結果期せずしておこった現象にみえる

バグのはずなんだけどirbで再現しようと思ってもできないんだこれ


 追記@2009-08-13: 見る人が見れば修正はあっという間でした

http://redmine.ruby-lang.org/issues/show/1929

(ここに見るべき場所を見つけることもできなかった人間がひと)

* 正しくは ruby-1.9.2dev(2009-02-03)


20090215() 本文中の URL自動リンクがセミコロンで切れていたので/shjs/lang/sh_ruby.js/shjs/lang/sh_javascript.jsを修正したそこで使っていた正規表現『詳説 正規表現 第3大抵の場合うまくいくと紹介されていたものでした(CGIパラメータを ; で区切るのはいまだに異端でした)

[Ruby][tDiary] ruby-1.9.1*不思議で困ったことが起こった

この断片で理解してもらえるだろう

categorized.keys.each do |c|
	PStore.new(cache_file(c)).transaction do |db|
		categorized.fetch(c) #=> key not found (KeyError)
		db['category'] = {} unless db.root?('category')
		db['category'].update(categorized[c])
	end
end

あるハッシュのキーについて繰り返しているのにッシュにはそのキーが存在しないというこの不思議

このときc

"\xE6\x9C\xAC\xE6\x97\xA5\xE3\x81\xAE\xE8\xB3\xBC\xE5\x85\xA5" ASCII-8BIT

ッシュのキーリトとそのエンコングは

"\xE6\x9C\xAC\xE6\x97\xA5\xE3\x81\xAE\xE8\xB3\xBC\xE5\x85\xA5" ASCII-8BIT
"本" UTF-8
"マンガ" UTF-8
"雑誌" UTF-8

存在しているだろうに……

 追記@2009-02-20: 同じ目に遭っている人がいた

さくらインターネト上で tDiaryruby1.9.1-p0 で動かす - まちゅダイアリ(2009-02-19)(14:57現在日別表示が不可能な状態最新表示は可)

* 正しくは ruby-1.9.2dev(2009-02-03)


20090212() ruby-1.8.7も最近 p0から p72にしましたそれ以上のはコンパイルできませんでしたおとなしくリリースを待ちます。

[tDiary] tDiary2.3.0.20080302から 2.3.1.20090129へアップデ

手動で migrate.rbを実行して UTF-8化してあったのに再度 90migrate.rbが走ってしまってータが壊れた慌てず ZIPァイルを解凍して元通り

grepと同じ程度に簡単にータファイルや tdiary.confのバージョンナンバーをすべて書き換える方法(sed?)が思いつかなかったのでtdiary/lang/ja.rbmigrate_to_utf8を無効化して済ませた

def migrate_to_utf8( str )
	return str
	to_native( str, 'EUC-JP' )
end

素通しとはいえ migrationは実行されるので数十から百ちかい数のファイルを開いて書き込んで閉じてといった負荷をレンタルサーバーにかけたーカルでは一分以上かかった

 2.3.1になってカテゴリが大文字小文字の区別なくソトされる*

のが嬉しい気になっていてっぽど自分でやってやろうかと思っていたので

 古い tdiary.confを引き継ぐと

@accesskey_enabledの設定が存在しない(=>nil => falseと判断される)ためにアクセスキーがなくなってしまって戸惑ったここはデフトを過去と互換にして欲しかった(設定名を @disable_accesskeyにするとか)いまさらだけど

 category.rbnilにアクセスして NoMethodErrorを出すと思ったら

NaviUserCGIが木偶だからだった原因は category.rbにはなくできの悪い CGIのモックを渡した navi_user.rbにある

 エラーを出した category.rbのコ
class Info
	include ERB::Util

	def initialize(cgi, years, conf, args = {})
		@cgi = cgi
		@years = years
		@conf = conf
		@category = args[:category] || @cgi.params['category']
		@year = args[:year] || @cgi.params['year'][0] #=> NoMethodError: undefined method `[]' for nil:NilClass
 NaviUserCGIの定義
class NaviUserCGI
	attr_reader :params, :referer, :user_agent
	def initialize(datestr)
		@params = {'date' => [datestr]} # <<<注目!
		@referer = nil
		@user_agent = nil
	end

	def request_method
		'GET'
	end
end

オリジナルの CGI#paramsは単一のデフト値( [].freeze )を持った Hashなんだよね……

navi_user.rbrecent_list.rbと同じように書き換えてやろう

* 一か所大文字も小文字も存在しない配列のソトを普通のソトに戻しました


20090209() すでに世の中一般人も RSSです……よ?

[tDiary]ーマ自作 > badboy2007.css

screenshot (theme: badboy2007)

自分好みの見た目に拘るようになるにつれ既存のテーマから得られる部分が減り打ち消す手間が目立ってきたそろそろ一から積み上げる方が楽だと感じたので

公開されるテーマは汎用性を求められるぶん個人的には冗長だったりかゆいところに手が届かなくて CSSを追加したりする必要があったりするが公開を前提としない自作なら十分かつ必要最小限なものになる(この現状を十分とは口が裂けても言えないけれ)

以下備忘録としてスタイルを決めた際のポイトを(すごく雑)

  • タイヤの下には地面
  • 「ツッコミを入れるリンクの目的は移動ではなくアクションなのでボタンっぽく
  • 「ツッコミを入れる前後の [角かっこ]skel/diary.rhtmlから削除(ナビゲーションリンクの &laquo;, &raquo;も削除しています。なんでラベルに含めないんだろ今なら CSScontentも広く使えるのに文字のハドコングは不便)
  • IE8RC1のデフトスタイルシトは<pre>の文字を小さくするので抵抗した
  • 引用文は自分の書いた文章ではないので異物感
  • 引用の中のPREはそれとわからないように(実験)
  • 色の決定には色名に対する好みが多分に入っている(好き > navy, crimson)

ッダとフッタに関してもポイトを(未来の自分が思い出せるよう)

  • 日記著者向けのリンク(追記など)目立たないように閲覧者向けのナビゲーションリンクと混ぜないように(ージ最下部でも良)
  • 目次はスクロールの必要なく一画面に収まるように(ージンとヘッダの内容と表示日数を削)
  • ップに前後方向のナビゲーションはいらない(目次の下とページ最下部に置いてみまし)
  • フラトなカレンダーを先頭に置くと Tabーによるフーカス移動が大変(カレンダーはページ最下部にとりあえず放り込みまし)

古い日記はレイアトが崩れてるかも過去の日記の凍結(ッダッタプラグインの出力を日記執筆時点のものに固定)という名の HTML書き出し機能が欲しい

実は squeeze.rbを少し変更してヘッダッタを含む HTMLを書き出しmod_rewriteを使ってその HTMLァイルが存在するときはそちらを参照するように .htaccessで設定したりしていた

RewriteEngine on
RewriteBase /ds14050/diary

# Rewrite rule1
#  shows static html, if exists.
RewriteCond /home/vvvvvv/www/cgi_file/ds14050/diary/snap/$1.html -f
RewriteCond %{REQUEST_METHOD} =GET [OR]
RewriteCond %{REQUEST_METHOD} =HEAD
RewriteCond %{HTTP:Cache-Control} !=no-cache [nocase]
RewriteRule ^([0-9]{8})\.html$ /cgi_file/ds14050/diary/snap/$1.html [L]

でも静的 HTMLをブラウザが直接参照するので tDiaryが起動せずリファラの記録が行われなくなるし多分ツッコミ(トラックバック)が入るだけで HTMLが新しく生成されてしまう翌日の日記へのナビゲーションリンクも基本的に出ないッコミの読み込みとリファラの記録を静的 HTMLに埋め込んだ JavaScriptで行うことで内容を最新に保ちつつ HTMLの生成を抑制できるが実際にやってみるほどのメリトを見いだせず。スクリトを実行しないブラウザ対応もパッと思いつかない(使える道具って<script><noscript>だけなのだろうコメト部を別 HTMLァイルとして保存して SSIで埋め込むとか……ーむ)


20090202() [Vista] リソース モニタのキーボドインターフェイ: P(CPU項目を展開)D(スク項目を展開)N(トワーク項目を展開)M(メモリ項目を展開)L(全て展開)Shift+P,D,N,M,L(それぞれの項目を展開折り畳み切り替)

[Ruby][tDiary] tDiary1.9系の Rubyでは 1.9.2から動くようになるの

やっぱり nobuさんがやってくれました。

requireの処理の中でーフレベルを一時的に 0 に下げる部分があってこの範囲を広げることでSecurityErrorが出ないようになっていた(3)

画像はtDiaryamazon.rbリポトリから持ってきただけの素の Ruby-1.9.2dev(2009-02-03)上で動いているところ

既に正式版がリリースされて*しまって*いる Ruby-1.9.1との違いを、先月の日記に書いた例で見ていくと

 $SAFE=1カレトリのスクリトを requireしたとき

irb192> RUBY_DESCRIPTION
=> "ruby 1.9.2dev (2009-02-03) [i386-mswin32_90]"
irb192> $SAFE=1
=> 1
irb192> require "a"
SecurityError: cannot load from insecure path - Y:/.../Desktop/a.rb
        from (irb):3:in `require'
        from (irb):3
        from C:/Program Files (x86)/ruby/bin/irb192.bat:20:in `<main>'
irb192> require "a.rb"
SecurityError: cannot load from insecure path - Y:/.../Desktop/a.rb
        from (irb):4:in `require'
        from (irb):4
        from C:/Program Files (x86)/ruby/bin/irb192.bat:20:in `<main>'
irb192>

2009-02-03版の ruby-1.9.2devでは$SAFE=1のときカレトリのスクリトを requireできないこれは $:($LOAD_PATH)に汚染されていない "." が含まれていようとrequire の引数の文字列が汚染されていなかろうとrequireできない見つけた抜け道は絶対パスで requireするか$:($LOAD_PATH)にカレトリを絶対パスで追加すること("."が含まれる場合はそれより前に追加する必要もある)

ruby-1.9.1の結果は Release Candidateのときと変わらず

irb191> RUBY_DESCRIPTION
=> "ruby 1.9.1p0 (2009-01-30 revision 21907) [i386-mswin32]"
irb191> $SAFE=1
=> 1
irb191> require "a"
SecurityError: Insecure operation - require
        from (irb):3:in `require'
        from (irb):3
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:20:in `<main>'
irb191> require "a.rb"
a.rb required.
=> true
irb191>

ruby-1.9.1では拡張子を付けてやるとカレトリのスクリトも requireできる拡張子を付けないときに requireできないのは ruby-1.9.2devも同じだが ruby-1.9.1には ruby-1.9.2devにない爆弾がある$SAFE=1のときの拡張子を付けない require添付ライブラリの requireであっても失敗したりする

irb191> $SAFE=1
=> 1
irb191> require "stringio"
SecurityError: Insecure operation - require
        from (irb):2:in `require'
        from (irb):2
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:20:in `<main>'
irb191> require "stringio.so"
=> true
irb191>

これが原因でtDiaryruby-1.9.1で動かすのは絶望的だと思っている*(ruby-1.9.1はリリースされちったしスクリトで対応できる範囲を超えているか)

この部分は SecurityErrorが出ない方向に修正されると思っていたからruby-1.9.2devで両方のパターンが SecurityErrorになったのは意外

 $SAFE=1汚染されたパスが $:($LOAD_PATH)に含まれるとき

ruby-1.9.2devでは汚染されたパスが $:($LOAD_PATH)のどの位置にあるかが重要

irb192> $SAFE=1
=> 1
irb192> $:.unshift "!tainted!".taint
=> ["!tainted!", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby/1.9.2/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby/1.9.2/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby", "C:/Program Files (x86)/ruby/lib/ruby192/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/1.9.2/i386-mswin32_90", "."]
irb192> require "cgi"
SecurityError: cannot load from insecure path - Y:/.../Desktop/!tainted!/cgi.rb
       from (irb):3:in `require'
       from (irb):3
       from C:/Program Files (x86)/ruby/bin/irb192.bat:20:in `<main>'
irb192> $:.push $:.shift
=> ["C:/Program Files (x86)/ruby/lib/ruby192/site_ruby/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby/1.9.2/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby/1.9.2/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby", "C:/Program Files (x86)/ruby/lib/ruby192/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/1.9.2/i386-mswin32_90", ".", "!tainted!"]
irb192> require "cgi"
=> true
irb192>

ruby-1.9.2devでは$SAFE=1汚染された LOAD_PATHからスクリトを requireすることはできないが汚染されていない LOAD_PATHからスクリトを先に見つけた場合はrequireに成功するruby-1.9.1(ruby-1.8.7-p72)ではどうだったかというとより厳しくて

irb191> $SAFE=1
=> 1
irb191> $:.unshift "!tainted!".taint
=> ["!tainted!", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby/1.9.1/i386-msvcrt", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby/1.9.1/i386-msvcrt", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/i386-mswin32", "."]
irb191> require "cgi"
SecurityError: Insecure operation - require
        from (irb):3:in `require'
        from (irb):3
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:20:in `<main>'
irb191> $:.push $:.shift
=> ["C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby/1.9.1/i386-msvcrt", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby/1.9.1/i386-msvcrt", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/i386-mswin32", ".", "!tainted!"]
irb191> require "cgi"
SecurityError: Insecure operation - require
        from (irb):5:in `require'
        from (irb):5
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:20:in `<main>'
irb191>

ruby-1.9.1では汚染されたパスが一つでも $:($LOAD_PATH)に含まれると(相対パスで) requireはできない絶対パスならできるがそんな書き方はしないので $:($LOAD_PATH)に追加するパスは常に untaintしなければならない

 ruby-1.9.2dev(2009-02-03)は概ね期待通りの動作だが……

requireしたときのカレトリの扱いに不満が残る

多分従来の Rubyruby-1.9.1ruby-1.8.7$:($LOAD_PATH)の要素の汚染状況なんて気にしていなかった$:に含まれるか含まれないかだけが重要2005年から現在まで変わっていないリファレスマニュアルのこの記述がそれを物語っていない

Level 1以上では起動時に以下の違いがある

  • 環境変数 RUBYLIB$: に加えない
  • カレトリを $: に加えない
  • (以下)

その方針に異議を唱えるものではないけれどこの方式にはーフレベルによる分岐が起動時に限定されるという制限があるコマドラインオプション -T を指定したときにしか有効にならず$SAFEを使ってセーフレベルをコトロールするシナリオでは機能しない

ruby-1.9.2dev$:($LOAD_PATH) の要素の汚染状況に注目することで$SAFEを使ってセールレベルをコトロールする場合で「環境変数 RUBYLIB$: に加えない「カレトリを $: に加えないのと同等の制限を課せる可能性を持っているつまり「環境変数RUBYLIBとカレトリは常に $:($LOAD_PATH)に追加されるただし汚染された状態でということ

それなのに現在の ruby-1.9.2dev$SAFE=1の下での requireに対するカレトリの扱いはruby-1.8.7よりむしろ退化している

ruby-1.8.7では $:($LOAD_PATH)"." を追加したり取り除いたりすることでカレトリの扱いをーフレベルによらずスクリトがコトロールできた

拡張子の有無で結果が変わる動作に筋の通らない ruby-1.9.1requireは論外として

ruby-1.9.2devではカレトリのスクリトの require$:($LOAD_PATH)によらずSecurityErrorになるカレトリを絶対パスで $:($LOAD_PATH)に追加することでコトロール可能だが既に含まれているかもしれない "." が邪魔をするruby-1.9.2dev$:($LOAD_PATH)に含まれる "." の汚染状況(あるいは "."が $:に含まれないこと)によってのみカレトリの扱いを変えるべきでカレトリが特別に SecurityErrorになる現在の ruby-1.9.2devには同意できない

ールレベル1ではまだスクリトを信用しているのだから少なくとも ruby-1.8.7と同等のコトロールをスクリトに渡して欲しい

requireが利用する File.expand_pathの仕様によりカレトリからの相対パスが汚染されるのだろうがFile.expand_pathrequire$:($LOAD_PATH)に依拠していることを知らないのだから requireが何とかすべき

* その後の変更でruby-1.9.1らしき挙動の requireを検出したときはセーフレベルを 1から 0に下げてプラグインを実行することになっているーフレベル0なら今回のことは関係ないからーフレベルを下げるという発想は全く頭になかったなんかこう負けた気がするからだろうruby-1.9.0だとセキュアモ(ーフレベル4)で動かないという話もあったけどどうなったんだろう


20090122() Ruby-1.9.1-RC2出ました

[tDiary] tDiary on Ruby-1.9.1-rc2 -> Encoding::CompatibilityError

#<Encoding::CompatibilityError: incompatible character encodings: UTF-8 and ASCII-8BIT>
(plugin/00default.rb):571:in `comment_form_text'
(plugin/00default.rb):616:in `comment_form'
(TDiary::Plugin#eval_src):79:in `block in eval_src'
Y:/server_root/www/ds14050/tdiary_on_ruby191/tdiary.rb:787:in `eval'
Y:/server_root/www/ds14050/tdiary_on_ruby191/tdiary.rb:787:in `block in eval_src'
Y:/server_root/www/ds14050/tdiary_on_ruby191/tdiary.rb:112:in `block in safe'

なにが ASCII-8BITったかというと Cookie

plugin/00default.rb:575: #{comment_name_label}:<input class="field" name="name" value="#{h( @conf.to_native(@cgi.cookies['tdiary'][0] || '' ))}">

ならばと UTF-8への変換を試みたならば

@cgi.cookies['tdiary'][1].encode("utf-8")
#=> #<Encoding::UndefinedConversionError: "\xE3" from ASCII-8BIT to UTF-8>

ッキーみたいに何が送られてくるかわからないものは慎重に慎重にエラーに備えて取り扱わないといけないということですね(面倒くさいな)

CGIパラメータなんかも取り扱い注意だよねcgi.rbの支援はないのかな?(他力本)


 補足エラーの原因の心当たり

Testing tDiary on Ruby1.9.1と題した日記にも関わらず少しの間っかり 1.8.7で動かしていたそのせいでキッシュが原因のエラーが出たしッシュを削除したら今度はクッキーが原因のエラーが出たという次第

ーバーの Ruby1.8.7から 1.9.1にアップデトしたタイミングでそのサーバーの日記を閲覧できなくなる人(過去3か月間にコメトした人限定)が続出ないだろう


 追記@2009-01-24: Ruby-1.9での cgi.rbとその代替(Rack)

cgi.rbも変わっていたのでした

どちらも日付が今日(2009-01-24)だ! Googleクローリング早い

tDiaryの文脈で Rackの名前を見かけてたんだけど名前から Rakeのようなものを想像していたWeb方面だったのね


20090119() Wassrという Webービスがあってそこに tDiaryというチャンネルがあってFirefoxにはライブブックマークとかいうものがあっていろいろなものを発見(コミトログの確認が svk sync + viewvcより簡単だ古い記事がちょこちょこ投稿されると思ったら delicious..から tDiaryタグの付いた URLを拾っているとほへ)

[Ruby][tDiary] require$SAFE=1と汚染された $LOAD_PATH

>irb
irb(main):001:0> RUBY_DESCRIPTION
=> "ruby 1.8.7 (2008-05-31 patchlevel 0) [i386-mswin32_90]"
irb(main):002:0> $SAFE=1
=> 1
irb(main):003:0> $:.unshift "hoge".taint
=> ["hoge", "C:/Program Files (x86)/ruby/lib/ruby/site_ruby/1.8",..., "."]
irb(main):004:0> require 'cgi'
SecurityError: Insecure operation - require
        from (irb):4:in `require'
        from (irb):4
        from :0
irb(main):005:0>

1.8.7でもこうなのだから知らない俺が抜けているのだが$SAFE=1のときに汚染された文字列を $LOAD_PATHに追加する(pushでも unshiftでも)一切の requireができなくなる

期待したいのはhoge/cgi.rbhoge/cgi.soなどが存在するときにはこのパスは汚染されているので SecurityError存在しないときはファイルの探索を続けて C:/Program Files (x86)/ruby/lib/ruby/1.8/cgi.rb (このパスは汚染されていないはず)を読み込むという動作なのだけど……

実際はそうではないのだから tDiary

tdiary.rb:12: $:.insert( 1, File::dirname( __FILE__ ) + '/misc/lib' )

というのは __FILE__ が汚染されているときにわりと危険な操作ということになる問題が起きないのは SAKURAのレンタルサーバの Ruby1.8.6だからなのか__FILE__File.dirname(__FILE__) が汚染されていることが稀だからなの(汚染されていることが実際にあるのは、20090117p01で書いたようにuntaintすることで状況が改善したことから推測でき)


問題が起きないのは SAKURAのレンタルサーバの Ruby1.8.6だからなのか__FILE__File.dirname(__FILE__) が汚染されていることが稀だからなの

両方でした__FILE__が汚染されているのは Ruby-1.9.1RC1だから(多分)


$SAFE=1のときに汚染された文字列を $LOAD_PATHに追加する(pushでも unshiftでも)と、一切の requireができなくなる

書きながら誇張だとは気付いていたのだけど(一切のの部分が)そうでない例を自分で見つけたので追記(2009-02-02)

Windowsフルパスであるいは拡張子(.rb)なしのフルパスでなら requireできる

Y:\...\Desktop\a>irb
irb(main):001:0> RUBY_DESCRIPTION
=> "ruby 1.8.7 (2008-05-31 patchlevel 0) [i386-mswin32_90]"
irb(main):002:0> $SAFE=1
=> 1
irb(main):003:0> $:.push "".taint
=> ["C:/Program Files (x86)/ruby/lib/ruby/site_ruby/1.8", "C:/Program Files (x86)/ruby/lib/ruby/site_ruby/1.8/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby/site_ruby", "C:/Program Files (x86)/ruby/lib/ruby/vendor_ruby/1.8", "C:/Program Files (x86)/ruby/lib/ruby/vendor_ruby/1.8/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby/vendor_ruby", "C:/Program Files (x86)/ruby/lib/ruby/1.8", "C:/Program Files (x86)/ruby/lib/ruby/1.8/i386-mswin32_90", ".", ""]
irb(main):004:0> require "a"
SecurityError: Insecure operation - require
        from (irb):4:in `require'
        from (irb):4
        from :0
irb(main):005:0> require "a.rb"
SecurityError: Insecure operation - require
        from (irb):5:in `require'
        from (irb):5
        from :0
irb(main):006:0> require "./a.rb"
SecurityError: Insecure operation - require
        from (irb):6:in `require'
        from (irb):6
        from :0
irb(main):007:0> require "Y:/.../Desktop/a/a"
=> true
irb(main):008:0> require "Y:/.../Desktop/a/a.rb"
=> false
irb(main):009:0> require "a"
SecurityError: Insecure operation - require
        from (irb):9:in `require'
        from (irb):9
        from :0
irb(main):010:0>