昨日も明日も楽しい打ち合わせです。 午前も午後も打ち合わせです。 昨日も (なぜか) たくさんのネタが開拓されました。
(その1) 「越えられない壁」演算子
2ch でお馴染みの
C,C++ > Java > C# >> Perl > Python >>>>>>>>>>>>>>>(越えられない壁)>>>>>>>>>> Ruby
みたいなやつのこと。 確か、Array#<< の逆の操作を行う「>>」があったらどうなるか、 という話題の途中で登場したんだと思った。 優先順位はこのあたり?
+@ -@ * / % + - << >> & | ^ > >= < <= ← このへん <=> == === != =~ !~ && ||
(その2) 「隙間」理論
0-origin のインデックスは要素の隙間についている番号だという、 それ自体はそれなりに一般的な考えかたのこと。 Ruby の「点三つ範囲」は隙間理論で考えたほうがすっきりする。
ary[2...7] |<----------------->| 0 1 2 3 4 5 6 7 8 9 +---+---+---+---+---+---+---+---+---+ | | | | | | | | | | +---+---+---+---+---+---+---+---+---+
しかし ary[3...5] について 「3番目の隙間から5番目の隙間の間にある要素」 とコメントを書いておいたことから著者間で議論が紛糾し、 「じゃあインデックス 0 は何なんだ」と問われて 「そこには特殊な『論理隙間』があるんだよ!」 と強弁したことから「隙間理論」が成立した。
疲れてたせいか、なんか妙にうけた。
(その3) machine epsilon
特定のアーキテクチャで浮動小数点演算をしたとき、 (1 + e) - 1 が 0 にならない e の最小値が machine epsilon。 それが機械イプシロンと訳されていると椎名林檎っぽい *1 ね、というだけのネタ。
※1 漢字二文字 + カタカナならなんでも椎名林檎ぽいという、 激しくナイーブな論理展開。
(20:14)
http://page6.auctions.yahoo.co.jp/jp/auction/f19524674
21264 の 4 発機がありえない値段で出ている。
(20:18)
ファイルが Solaris door かどうか Ruby で判定するコード
class File::Stat S_IFDOOR = 0xD000 def door? mode() & 0xF000 == S_IFDOOR end end def File.door?(path) stat(path).door? end p File.door?('/etc/sysevent/sysevent_door') #=> true
(22:57)
知らないうちに BitChannel を徹夜でいじってしまって WikiFarm が実装された感じってのはまあ置いといて、 設定項目名が非常に一貫性に欠けるなあと思った。
どうも「……dir」には下線を付けず、 「……url」には下線を付ける習性があるようだ。
それ以外のところはだいたい下線を入れるで一定しているように見えるが command だけ cmd と省略してたりするのが微妙に気持ち悪い。 つうか、なんで cvs じゃなくて cmd_path なんだろうなあ。 ああそうか、ちょっとだけ CVS 独立にしてみようかと 余計な色気を出したのが原因だな。
あ、wc (working copy) も省略されてるか。
logfile は下線がない。やっぱ微妙だ……
(06:39)
おかしい……まだなんかおかしいぞ……。 くそ、今日は 16:10 まであるんだっけ。まずい。 そもそもこんなときに DNS の移行なんぞするのが間違いだった。 何もこんな原稿がおおづめのときに移行しなくても。
aamine AT mx.edit.ne.jp はプロバイダ止めなので、 なにかあるかたはそちらにお願いします。
ルータの 53 番が閉じてたのが原因?! まだ安心できないな。
開けたはずのポートはやっぱりちゃんと開いてたようだ。 メールが復活して、スパムがドカドカ届きはじめた。 スパムがこんなに嬉しく感じる日は初めてです。
ともあれ、御迷惑をおかけしました。
(21:27)
Haskellっぽい型無し言語ってないですかねえ。
なんつーかね、遅延評価だけ欲しいんですよ。 遅延評価したいところだけをテキト〜〜〜〜〜に書きたいんです。
そんで IO 関係は、K&R C のごとく、 ヤバげなところに警告だけ出してとにかく通しちゃう。 そんなゆるゆるな仕様の言語が使ってみたい。
(00:58)
(追記1) 静的型付けでなくなった瞬間、 Haskellっぽいとは言えなくなるような気がしないでもない。
(追記2) む、Cleanって動的型付けもできるのか?
突然思い出した。 やっぱりルータの 53 番は開けても通らなかったんだ。 で、その後ダメもとで (ルータの) ファイアウォールを切ったら通るようになった。 つまりファイアウォールにも問題があるように思える。
(22:11)
いい感じにバグやら要望やらがたまってまいりました。
えーと……、また明日!
(22:12)
うわあ。やっぱり言語の話題だと反応が多いですね。 数々のツッコミありがとうございます。
そもそもドメインが loveruby.net なくせに この日記は Ruby ネタが少なすぎる。 BitChannel を Ruby ネタということにすれば多少は増えるけど、詐欺くさいな。それはともあれ「ゆるゆる言語」、 ぼくの書きかたが中途半端だったせいで誤解を生んだようなのですが、 言語の中の一部分だけ遅延評価ではなく、プログラム全体が遅延評価ってことです。 もちろん Scheme の delay/force みたいな手間もかけずにやってほしい。
んで、肝は「やばそうなところは警告だけ出して適当に実行」って部分でした。 真面目に研究する人達はこんなヘタレなことは考えなさそうなので ^^;;;
とりあえず、Q を眺めてみようと思います。
※ 参考までに、昔の一文字言語の話題 http://i.loveruby.net/d/20020522.html#p03
(23:43)
cgi.rb には、普通に実行するとコマンドラインから パラメータを与えられる機能がありますよね。 あれの webrick/cgi 版をでっちあげました。
# cgienv.rb ENV['GATEWAY_INTERFACE'] ||= 'CGI/1.1' ENV['SERVER_PROTOCOL'] ||= 'HTTP/1.0' ENV['SERVER_SOFTWARE'] ||= 'DummyHttpServer/1.0' ENV['SERVER_NAME'] ||= 'localhost' ENV['SERVER_ADDR'] ||= '127.0.0.1' ENV['SERVER_PORT'] ||= '80' ENV['REMOTE_ADDR'] ||= '127.0.0.0' ENV['REMOTE_PORT'] ||= '33992' ENV['HTTP_ACCEPT'] ||= '*/*' ENV['HTTP_ACCEPT_LANGUAGE'] ||= 'ja,en' ENV['HTTP_HOST'] ||= 'localhost' ENV['HTTP_USER_AGENT'] ||= 'DummyAgent/1.0' script = ARGV.shift or raise ArgumentError, 'no file' ENV['SCRIPT_URI'] ||= 'http://localhost/' + File.basename(script) ENV['SCRIPT_URL'] ||= ENV['SCRIPT_URI'] ENV['SCRIPT_NAME'] ||= '/' + File.basename(script) ENV['SCRIPT_FILENAME'] = File.expand_path(script) ENV['REQUEST_METHOD'] ||= 'GET' ENV['QUERY_STRING'] ||= ARGV.join(';') load File.expand_path(script)
こんなふうに実行できます。
~/public_html/bc % PATH_INFO=/test ruby cgienv.rb farm.cgi name=FrontPage cmd=annotate Status: 200 Cache-Control: no-cache Connection: close Date: Fri, 07 May 2004 18:05:43 GMT Content-Type: text/html; charset=euc-jp Server: DummyHttpServer/1.0 Content-Length: 2332 Pragma: no-cache <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html lang="ja-JP"> 以下略
(03:07)
■
gotoyuzo [なるほど。本体に組み込むか、サンプルに突っ込んでもよさそう。
ちなみに、ApacheがターゲットならSCRIPT_URIよりもREQUEST_URIのほうがいいですね。]
RAA の SOAP インターフェイスが [ruby-talk:99611] で紹介されている。
% ruby -r pp -r soap/wsdlDriver -e ' raa = SOAP::WSDLDriverFactory.new( "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.4/" ).create_driver pp raa.gem("tmail") ' #<SOAP::Mapping::Object:0x4038a468 @category=#<SOAP::Mapping::Object:0x4035a2b4 @major="Library", @minor="Mail">, @created=#<DateTime: 13243981342437209/5400000000,3/8,2299161>, @id=600, @owner= #<SOAP::Mapping::Object:0x40352758 @email=#<URI::MailTo:0x201c598c URL:mailto:aamine@loveruby.net>, @id=45, @name="Minero Aoki">, @pass=nil, @project= #<SOAP::Mapping::Object:0x4038a274 @dependency=[], @description= "TMail is an email handling library.\r\nAlmost all RFC2822/MIME specification is supported.\r\n", @download= #<URI::HTTP:0x201c99ba URL:http://i.loveruby.net/archive/tmail/tmail-0.10.8.tar.gz>, @history=[], @license="LGPL", @name="tmail", @short_description="TMail", @status="stable", @updated=nil, @url=#<URI::HTTP:0x201cb954 URL:http://i.loveruby.net/en/tmail.html>, @version="0.10.8">, @updated=#<DateTime: 10597199881960969/4320000000,3/8,2299161>>
おおっ。これは凄い。なんか無性に凄い。
以下は、同じく ruby-talk で紹介された、 プロジェクトのバージョンアップを自動化するスクリプト。
name = 'sampleproject' pass = 'sampleproject' gem = raa.gem(name) gem.project.version.succ! gem.updated = Time.now raa.update(name, pass, gem)
いいねえ。便利だねえ。 何かのバージョンを上げてみたいな…… (本末転倒)
どういうメソッドがあるんだろう。
~ % ruby -r pp -r soap/wsdlDriver -e ' raa = SOAP::WSDLDriverFactory.new( "http://www.ruby-lang.org/xmlns/soap/interface/RAA/0.0.4/" ).create_driver puts raa.methods(false) ' | sort dependents gem list_by_category list_by_owner list_created_since list_owner list_recent_created list_recent_updated list_updated_since names owner search search_description search_name search_owner search_short_description search_status search_version size tree_by_category update update_pass
へー。
(01:47)
class に対応する end は def に対応する end より重い。
def に対応する end は if に対応する end より重い。
だからおれとしては end か {} かというよりも、 この二種類の end を区別できるほうが嬉しい。
かと言って end class とか end def と書きたいかというと、 それはそれでまた気持ち悪い。 dne とか ssalc よりはマシだけど。
それで結局、現実的には
class C def m if .... .... end end end
こんなふうに class の内側に空行を入れることで 対応しているのであった。
(02:41)
WikiFarmっぽいものが実装できた。 まだ自分で公開サーバに設置しないあたりに完成度の低さが見てとれます。
そろそろ ver 0.3 を出そう。
(01:35)
BitChannelComment で 「WindowsでCVSは辛いからsubversionに対応してほしい」 という要望が出てるんだけども、 よく考えたら fork 連発してる時点でだめだよな。
いや、同期実行しかしてないので spawn を使えばいいんかなあ。 VC++ な Ruby でパイプってつなげるんだっけ。
確か使えるってレシピブックに書いた記憶がある。 ということは使えるんだろうな。じゃあ問題ないか。
そういえば subversion には C API があるんだっけ。 Ruby インターフェイスはないのかな。ないらしい。
……
……いや、書かないって!
■ ささだ [BitChannel を Subversion で使うメリットってどういうのがあるんでしょうか。あんまり思いつきません。CVSが入ってないってことはないだろうし。]
■
kjana [subversion の ruby binding はメンテナがおっつかなくなったんで obsoleted,
だったと思う.http://www.sodan.org/%7Epenny/diary/020816.html#0824 という
頃には少なくともコンパイルは通っていたようだし.]
■
青木 [む、なるほど、インターフェイスはいちおうあったんですね。
ありがとうございます。使うかどうかわからないけど、
眺めてみます。]
■
青木 [いや、入れるのが大変ということじゃないかな > WindowsでCVS
と、少なくともぼくはそう解釈してたんですけど。]
■ 提案者 [WindowsにCVS入れるのが大変ということです、はい。それに比べてSubversionは鼻をほじりながらでも入れられるほど簡単なのです。]
■
ano [CygwinのCVSではまずいの?
CygwinSubversion(ソースからmake)もやったことあるけど何故かCVSよりよく動いてた。
あと単にマシンが調達できないという理由ならlinux on coLinuxでCVSでもいいと思うけど。
そもそもどうしても絶対Windows上で動かさなければならないのですか?]
■
ささだ [「Windows で CVS を入れるのがつらい」という部分をスコーンと読み飛ばしてました。そうか、大変だったのか。WinCVS だったら鼻歌交じりで出来た記憶があるんですが、Win上にリポジトリを作って管理したことがないんであまりあてにならないかも。(しかし、何が辛いのだろう)
Subversion はどうにも信頼性が。ディレクトリまできちんと管理するなどの点でsvnはとてもすばらしいと思うんだけど、BitChannel はそういうの必要ないし、CVSでええやん、と考えてました。]
■ 提案者 [なんか反対意見が多いので提案は撤回します。青木さんのリソースを無駄に消費させてしまうのも申し訳ないので。すみません。]
■
ano [でもSubversion好きですけどね。
Apache動かしてその上でCGI動いてCVS動かしてとなると、WindowsでやるほうがLinuxとかBSDでやるより「わざわざ」感が大きいので、WindowsでやりたいからSubversion、というのはよくわからん論理であったのでした。WindowsにもCVSあるし。
Subversion対応が実現するならWindowsでなくてもバックエンドをCVSじゃなくSubversionで動かしたい人もいるんじゃないかなあ、と書いておこう:)]
■
ano [ちょっと待った。
http://i.loveruby.net/w/BitChannelImplementation.html
大文字小文字を区別しないファイルシステムでは動作が変になる。
がーん、そもそもWindowsだめじゃん。]
■
青木 [実はメソッドを二つ変更すれば通るのですよ。
module FilenameEncoding あたりを見るとよいと思う。]
■ ささだ [あー、反対するつもりは無くて、単純に何がうれしいのかわからなかっただけです。青木さんならさくさくと作ってくれるに違いない。]
■ 青木 [ふっふっふ、そいつはどうかな……]
■ ささだ [ああそうか、Rubyでバージョン管理システム作り直すんでしたっけ。]
■
とおりすがり [ ちょっと話がそれますが、Subversionって不安定なんですか?
会社のバージョン管理システムCVSからSubversionにしようかなって思ってたとこなんで気になります。
自宅で使ってるかぎりでは大丈夫そうですが。
まあ実際使うときには、バックアップとるんでしょうけど。]
一日考えたがやはり納得がいかないな。 警察はできるだけ一般的で普遍的な問題にしたてあげようとしてるけど、 ぶっちゃけて言ってさ、今回問題になってるのって 一般的な著作権侵害問題ですらないだろ。 だってこれって、金と権力のある側が既得権益を確保するために パワーを行使してるだけじゃん。 そんなつまらないことのために可能性が潰されるっていうのが一番腹が立つ。 ついでに言えば、そんなつまらない事情がまかりとおってしまうこの社会にもまた腹が立つ。 やっぱり「インターネッ党」でも作って利益づくで対抗するしかないのかしら。
(01:00)
いやいや、遠慮するこたないと思いますよ。 何を言われてもぼくが不要と思えば実装しませんし、 自分で必要だと思ったから To Do に入れたわけです。 要望はストレートに言ってくれたほうが助かります。
イントラネットで動かす場合を考えると Windows 2000 あたりは重要なターゲットですし、 インストールが簡単になるにこしたことはないと思います。 最終的な目的は「共同作業をすること」であって 「BitChannel を使う」ではないのですから、 プラットフォームの違いとかバックエンドの違いなんてのは本質的とは言えません。 本質的でない部分はできる限り気にしないで済むのが適切です。
その前提を踏まえたうえで特に Subversion 対応を考える理由としては、 まずマーケティング的な効果が挙げられます。 どう考えたって「CVS 対応!」よりは 「Subversion 対応!」のほうがインパクトがあるに決まってる。 なにしろ流行りものだし。
第二に、サーバ構築の手間が挙げられます。 現在は基本的にローカルレポジトリを念頭に置いて開発してますが、 別にリモートでまずいってことは全然ありません。 特にこれからは CVS で直接手を出せるようにしたいと思っているので、 そうなればリモートレポジトリも重要になるでしょう。 が、しかし、CVS サーバの構築って死ぬほど面倒なんですね。 その点 Subversion はサーバを作るのが簡単なので、 対応しておくにこしたことはないと思います。
ただしここで一言言っておきたいのですが、 ぼくは Subversion を信用していません。 だから Subversion に対応しても自分では使いませんし、お勧めもしません。
(18:35)
『Rubyレシピブック』 2800 円で 5 月 28 日配本だそうです。 配本つーことは、本屋にはもうちょい後にならぶ? あ、31 日出版となってるな。
とにかくそのあたりです!
(19:27)
Subversion を信用できない理由はただ一つで、 Berkeley DB を使ってるからです。 別に RCS じゃなくてもいいんだけど、 テキストベースのデータベースでありさえすれば何も文句はありません。 なぜテキストがいいかと言えば、 いざとなったら ls と cat と vi で管理できるからです。 バイナリデータベースは vi で直接いじれません。
もちろん反論があるのは知ってますが、 これまで見た限りでは説得力を感じませんでした。例えば "Dispelling Subversion FUD" では「普通データためるなら RDB (= バイナリデータベース) 使うだろ、 なぜ Subversion には文句を言うのか」と言ってますが、 ことバージョン管理システムに関しては文句を言われるべきだと思います。
なぜならば、バージョン管理システムの本質とは即ち安心担保システムだからです。 昔のコードは全部残ってるからどんどん変更してください、 プログラムもデータベースフォーマット (RCS) も枯れてて安定してます、 それでも万一の場合はエディタで直接編集できます、 という保証があるからこそ安心してソースコードをいじれるんです。 いつ古いコードに戻れなくなるかわからないという不安があったら XP なんかできません。
ここで重要なのは心理的な効果であって、 本当に vi 編集が必要になるか、それで復旧できるかどうかは問題ではありません。 「もしそうなっても安心だ」と思える (信じられる) ことが肝心なのです。 その点、ぼくは vi で編集できればどうにかなると信じられます。 しかし vi が使えないんでは直す自信はありません。 従って Subversion は信じられません。 さらに言えば、そういう心理的な安心感を考慮してくれない Subversion 開発チームも信用できません。
(22:43)
まあ CVS に比べりゃ不安定だと思いますが、 (一般的なアプリケーションに比べて) 特に不安定ってことはないんじゃないですか。 いや、使ってないから知りませんけど。
しかしぼくが文句を言いたいのはあくまで データベースの設計それ自体であって、 プログラムの安定度じゃないということは追記しておきたいと思います。 また、新しい機能がほしいわけでもありません。 さらに言うならば、CVS サーバは文句なしに最低です。
(22:51)
あとさー、Subversion の新機能って 実はたいして嬉しくなくない?
Windows でもチェックアウトできんの?
別に PNG が画像的に diff できるってわけじゃないんでしょ?
ふーん。
これは重要な進歩だな。
必要な人は必要なんだろうけどねえ。
あるにこしたことはないよね。
この点は文句なしに素晴しい。つーか CVS がダメすぎ。
ということで総合すると、おれにとって文句なしに長所で、 どうしても欲しいと思える特徴は「サーバ構築が容易」ってところだけだ。 あとはどうでもいいか、CVS でも妥協できるレベルだな。
(23:03)
今週土曜日は RHG 読書会です。 案内は
あたりを参照してください。
ちなみに今回は p.267 (10 章「パーサ」の途中) からで、 たぶん「状態付きスキャナ」に入るでしょう。 きついんだここが。
(03:44)
■
sugi [Subversion を信頼してないというのは、やはりまだ枯れてないということでしょうか。
それとも、他に理由があったりするのでしょうか?]
■
とおりすがり [新機能がそんなに魅力的でないというのはあくまで「よりよい CVS」ですから仕方がないですね。
心理的安心感に関しては、コミットごとに dump すればそれなりに得られます。dump してしまえば、フォーマットは単純ですし、手で編集も出来ます。]
■ なかだ [コミットごとにdumpしてCVSに…]
■
ano [MSWin版ではfork未対応で停止しますね(当然か
http://ruby-talk.com/blade/60221
入れてごにょごにょしたら動きました。]
■
青木 [なるほど、win32-popen なんてのがあるんですね。
ありがとうございます。こちらでも動作を検証してみます。]
■ 青木 [両方の嫌なところだけ合成されるに 20 ルピー > dumpしてCVS管理]
■ テシ [個人的にはテキストベースの方がエンコード云々で全く信用ならないんですが・・・]
■
rero [>テキストベースのデータベースでありさえすれば何も文句はありません。
こう言ってるのだから,データベースは1世代で構わないわけでしょう.ということは,「コミットごとに dump」とは別問題ですね.じゃあ,berkdb でも dump して vi で編集して undump すればいいのでは?たまにしか起こらないデータ破壊の対策として毎回効率の悪いテキストベースのデータベースを使うなんて.]
■
青木 [逆に言えば、速度しか利点がないじゃないですか。
俺は速度よりも安心感が欲しいんです。]
■
rero [dump して vi で編集して undump では駄目なんですか?
「安全性」ではなく「安心感」ってところがミソなんですかね.安全性を追求するならもっと他のやり方がありそうな気がするので.]
■
rero [>バージョン管理システムの本質とは即ち安心担保システムだからです。
これも個人的には納得できません.安心感を得ることが本質なら,もはや差分管理はやらないと思います.ハードディスクも巨大化していますし.差分管理しなければ diff も DB も不要になります.
実際は diff や branch など,情報整理の利便性が追求されていると思います.]
■
青木 [> dump して vi で編集して undump では駄目なんですか?
データベースが壊れていたら dump が動くとは限りません。
> >バージョン管理システムの本質とは即ち安心担保システムだからです。
>
> これも個人的には納得できません.安心感を得ることが本質なら,
> もはや差分管理はやらないと思います.ハードディスクも巨大化
> していますし.差分管理しなければ diff も DB も不要になります.
> 実際は diff や branch など,情報整理の利便性が追求されていると思います.
べつに差分じゃなくてもいいんじゃないですか。
「それなりに手軽に使えて、すぐ元に戻せるシステム」
のうちで今のとこベストなのが CVS だから使ってるだけで、
その実装がすべて理想にかなっているなんて言ってません。]
■
rero [> 「それなりに手軽に使えて、すぐ元に戻せるシステム」
> のうちで今のとこベストなのが CVS だから使ってるだけで、
> その実装がすべて理想にかなっているなんて言ってません。
なるほど.]
Winny = internet - URI
という公式を思いついた。
(17:37)
(追記) 最初は nameless internet と書いたけど、 これだとちょっと意味合いが違うな。 identifier-less のほうがいいか。
とんでもないことがわかったぞ……
Microsoft は Winny の成功を見て WinFS を開発したんだよ!
な (ry
(17:43)
http://www.hyuki.com/tf/20040513081624.html
結城さんに同意してもらえるとかなり心強いですねえ。 いや実を言えば
「いまだにテキスト信奉かよ、おめでてえな (w」
とか
「オールドタイプはすっこんでろ」
とか煽られまくるのではないかと怯えてたんですが、意外にないっすね。 単に見てる人が少ないせいか、はたまた反論するまでもないと思われたか……。
(21:41)
今回はいつにも増して各種雑談に熱が入っていたため 10.3 スキャナしか読めず。記録はいつも通り RWiki に書きました。
一言で要約すると XML と YAML と Ruby スクリプト。 それぞれの特性に合わせて選びましょうね、 という、はしょってしまうとあまり面白くない結論?
BitChannel の設定ファイルも Ruby スクリプト (bitchannelrc) ですが、 これはあえてユーザにスタートアップの責任を押しつけ敷居を上げようとして採用しました。 もうちょっと真面目な理由としては、 Ruby のロードパスとか $KCODE を設定するのが楽そうだったという事情もあります。
ちなみに、Ruby スクリプトを使うにしてもデータを受け渡す方法には いくつか選択肢があり、それぞれ長短があります。
@datapath = '/var/tdiary'
$DATADIR = '/var/tdiary'
module AppConfig DataDir = '/var/tdiary' end
def bitchannel_context require 'bitchannel' BitChannel::Repository.new({:datadir => '/var/bitchannel'}) end
{:datadir => '/var/tdiary'}
ちょうど arton さんの日記にも設定ファイルの話があるなあ。
今回の RHG 読書会で akr さんに教えてもらったところによると ruby-cvs はローカル CVS の代わりに使えるそうです。 なんで、これをダイレクトに使うオプションを作ろうと思ってます。
(22:39)
5/31 発売予定の『Rubyレシピブック』の内容を簡単に紹介しておきます。
まず、この本はクックブックの類で、 かなり細かい、独立したセクションに分割されています。 話題がつながっているわけではないので、頭から読む必要はありません。 必要になったときに検索して読んでください。
※ いまのところ本文を公開する予定はありませんが、 本文を検索して見出しを出すシステムは欲しいねえ…… と勝手に話し合ってます。
ぼくは文字列・環境・IPC・オブジェクトの 4 章を担当しました。 その中では文字列処理、特に日本語処理を重視しています。 紹介した処理について逐一マルチバイト処理が可能かどうかチェックして、 できないものにはその旨追記し、代案を示します。
また、対応する Ruby は 1.6.7〜1.8.1 (基準は1.8) です。 こちらもまた全処理について動作をチェックして、 バージョン間の非互換をすべてリストアップし、 可能ならバージョン独立な書きかたを示しました。
ついでに言えば、今回は Windows での動作についてかなり真面目に調べました。 ただし NT 系のみです。9x 系は忘れてください。
最後に、そのうち項目見出しも公開します。
(23:51)
[ruby-talk:99910] Pure Ruby FastCGI performance bug?
「pure Ruby 版の fcgi ライブラリを使っている場合、 長いデータを送ると反応が妙に遅れることがある」らしい。 もしかしてこれって家の BitChannel で時々ピタッと止まるのと同じ現象かな。 なんだろうと思ってたんだよー。
……
調べるだけのつもりだったのに、 うっかり書き直してしまった……。
やっぱり止まるじゃん。だめじゃん。
とりあえず pack テンプレートの signed と unsigned を間違ってるだろう。
うううう、なんだこれは。 BasicSocket.for_fd を使うと次々にプロセスが増殖していく。 やっぱり Socket.for_fd でないとだめっぽい。
一回だけ accept してると思ってたのに、 実はセッションごとに回線がブチブチ切れていた。 ということは、むしろ積極的に close すべきなのか? あ、直った。
嘘だった。 連続でリクエストするとなぜか SEGV するようになった。 原因もわからず停止するよりはこっちのがマシか? いや、GC 関係なのでやっぱり嫌だ。
いや違う、また嘘。ruby が二週間も前のやつだった。 二週間前の HEAD なんて、食料で言えばとっくに賞味期限切れレベルである。
Ruby をアップデートしたらなおった! 10000 リクエスト連続でもへこたれない。すばらすい。
そんなわけで、リライトした fcgi.rb 置いておきます。
そういえば無意識のうちに Ruby 1.8 を仮定していたような気がするな。 HEAD までは必要ないはず。
(06:05)
オリジナルの fcgi.rb ならこんな感じでなおりそうな気がする。
--- fcgi.rb.org 2004-05-19 06:25:10.000000000 +0900 +++ fcgi.rb 2004-05-19 06:25:12.000000000 +0900 @@ -239,6 +239,8 @@ rescue LoadError end # type of request end # until @ns.eof return nil + ensure + @ns.close end # accept def close
起きたときに気が向いたらテストします……。
(06:29)
だめだやっぱり徹夜はだめだ、 こんなところで close してどうする。こうか。
--- fcgi.rb.org 2004-05-19 06:25:10.000000000 +0900 +++ fcgi.rb 2004-05-19 06:43:31.000000000 +0900 @@ -197,6 +197,7 @@ rescue LoadError def accept rec = Record.new if @ns.eof? + @ns.close @ns, = @server.accept end until @ns.eof?
本当に練る。もとい寝る。
(06:44)
wema で箱と線を書けてるんだから、 同じ手法で任意の (無向) グラフを描画できるはずだ。 とうぜん Wiki のページとハイパーリンクも描画できるだろう。
どうやってきれいなグラフにするかが問題か。
いやもしかして、自動できれいにしなくてもいいんじゃないか。 wema を改造して付箋 (ノード) 移動だけを許し、手動で並び変えたらどうだろう。 つまりビジュアルな FrontPage みたいなものになる。 グラフを (制約の多い) 言語で表現しておいて Wiki のページとして保持すれば、 自動的にバージョン管理や diff や annotate の対象にもできる。
(18:24)
tdiarysearch バグ直しの日々。
なんかねー、day モードで初期化すると title_navi.rb が Month オブジェクトを作りにいって、 そこでなんかエラーになるらしい。 しかたがないので @mode="month" で初期化してみる。 こういう逃げかたをすると他のプラグインでエラーが起きそうで嫌だが、解決策が思いつかない。
これはチェックしてるはずなのにおかしい……と悩んのだが、 Diary オブジェクトを作るときに自分で @show をセットしなければいけなかったらしい。
tdiarysearch のほうは簡単そうだったので対応した。 「簡単そうだったので」とか言ってるわりに意外に手間取ったのは秘密だ。
(04:22)
編集の衝突を検出しそこねていたのを修正した。 原因は (CGI クエリーの) org と orig のスペル間違い。 余分なクエリーもチェックしてねこそぎ弾いたほうがいいかな。
(01:41)
淡々とバグ報告を書く日記というのもおもしろくないなあ。 やはりもうちょっと感想とか思想っぽいものを書くべきかもしれない。 ルサンチマンとか純粋持続とか差延とか、 ちょっと高級そうな雰囲気漂う専門用語も ふんだんに散りばめてだ (思想違い)。
話は変わるが、昔ウェブ日記を小バカにするときに 「一般人の日常生活なんて描写されてもおもしろくもなんともない」 というような言いぶんがあったが、果たしてそうであろうか。 例えばいくらなんでも 「生協のボールサインは 10 円安い」とか 「70 円コーヒーの砂糖はキャラメルのような味がする」とか 「松屋の転機。鬱」とか、 いやすみませんこれは全部ぼくの (紙の) 日記に書いてある話題なんですが、 そこまであからさまに日常な日記は意外とないのではないか。
だからどうだと言われても困ります。 今日は散文モードなんです。
今日突然思いついたんだけど (と、ここで突然―――高階的に―――思いついたんだけど (という括弧の入れかたは arton さんぽいと思った (さすがに三重に括弧を重ねると読みにくいな (やはりS式には構造的に欠陥があ(以下略)))))、 思うに俺は「今日突然思いつ」くことが多いような気がする。 それこそ akr さんが「ふと気づ」くのと同じくらい多いような気がする。 tdiarygrep を駆使して検証してみよう。
思ったより少なかった。
えー、ここでスタックから話題を戻しますよ。 今日突然思いついたんだけど、 うわっ、何を思いついたか忘れたよ。 困ったな、プログラムのアイデアだったんだけどな。
あ、思い出した。 『Rubyレシピブック』の検索の話だ。
『Rubyレシピブック』をオンラインで検索できる CGI を作ろうと思って、 tdiarysearch と BitChannel からコードを切り貼りして書いたのね。 とりあえず基本機能は動いたんだけど、 やっぱり「章を限定して検索」とか 「サンプルコードのみ検索」とか欲しいよなあ、って思ったのだった。 アイデアじゃないじゃん。
なんか、ここまで話題が迷走するということは睡眠不足っぽいのでもう寝ます。
補足: なぜか「つれづれなるままに」の次に 「やうやう白くなりゆく」と出てしまい それ以外の可能性を考えられなくなってしまったので やむなく原文を検索したところ、こんなサイトを発見した。
これはなんと言うのだろう―――恋^H 故意^H^H 未必の故意^H^H^H^H^H いわゆる、「不覚にもワラタ」という気分でしょうか。いとおかし。
(02:37)
■ arton [「松屋の転機。鬱」の公開に一票。想像もつきません(と書いて突然気付いたが銀座の松屋じゃなくて豚ドンの松屋か……)]
■ ただただし [つーか、紙の日記をつけてるのがオドロキ]
■
青木 [やっぱ最後は紙ですよ。バッテリー切れないし軽いし閲覧性能
抜群だし視野角広いし。液晶なんざ敵じゃないです。
ちなみに「松屋の転機」は、国立(くにたち)駅前の松屋が工事を
始めてしまってこれからどこで朝食を食べたらいいんだ困ったな、
というだけの話でした。しかもいつのまにか近くに吉野家が
できてたことがわかったのでどーでもいいらしいです。]
■ ogino. [つーか、紙に日記にも「VS アジの開き」とか書いてあるのかどうか気になる。]
■ 青木 [それはありえナイ……]
くくくくそ〜〜〜! CVS が古いとまだだめらしい。 外部コマンドはこういうとこが苦しい。
これか! これが原因か!
* A behavior change in `cvs up -jrev1 -jrev2' for modified files with a base revision of rev2 (ie, checked-out version matches rev2 and file has been modified). The operation is no longer ignored and instead is passed to diff3. This will potentially re-apply the diffs between the two revisions to a modified local file. Status messages like from a standard merge have also been added when the file would not or does not change due to this merge request ("[file] already contains the changes between [revisions]..."). (cvs-1.11.16/NEWS より)
この変更は 1.11.10 か。うぅ、これを回避する方法は…… sticky にせずに古いリビジョンをワーキングコピーに復活させなきゃだめなのか。 一番手っ取り早いのは CVS/Entries 書き換えかなあ。
(20:05)
http://www.kyoto-np.co.jp/article.php?mid=P2004052700029&genre=C1&area=K00 (京都新聞「winnyの衝撃(1)罪に問われた利用者」)
内容はどうでもいいとしてさ、
初期ノード、IPアドレス、キャッシュ…。 高度な専門用語が飛び交う会社員の公判。
高度な専門用語?!
(22:00)
■ 通りすがり [http://www.haruya.net/news/read.php?dat=1084410067]
■ shiro [wilikiでは、2つのバージョンA, Bと共通の祖先Cがある時に、C->AのeditlistとC->Bのeditlistを並行して当てる(というか、両方をキューにしといて当てられるものを当ててゆく)というふうにしています。CVSのmergeはもちっと賢い気がします。]
■
zunda [ごめんなさーい。
$ rpm -q cvs
cvs-1.11.6-81
$ /usr/local/bin/ruby -v
ruby 1.9.0 (2004-05-21) [i686-linux]
なんだけど。
(早くビルドマシンがほしいのう…)]
■
青木 [CVSのマージ機能だと候補を両方入れてくれたりしますしね。
自分でマージのコードを書くのも面倒だし、なんとかして
CVSの機能を使うようにしてみようと思います。]
げげげ、ruby-lang.org もか。 ここまでオープンソース関連が狙われてるところを見ると、 意図的にやってるんだろうなあ。しかも日本のサーバばっかりとは。
レポジトリ……独立してるのは去年の 12 月のしかないや。 あとは全部 cvsup で上書きされちゃってる。
(18:33)
再起動直後、tDiary に 10 発くらい同時アクセスを食らって load average が 1720 まで上がっていた。さすがにこれはきつい。 本気で負荷削減策を考えるべきか。
(20:41)
disp_referer2.rb の負担が大きいのは以前からわかっているので、 もっと単純なリファラ解析プラグインを書いてみた。 あんまり変わらない。CPU パワーよりも I/O が問題なのか?
FastCGI にしてみた。 微妙に速くなったような気がするがそれほどでもない。 スタートアップよりも処理自体が重いってことだな。
(01:13)
あとは tDiary の設計を変えるくらいしか思いつきません。
などと言いつつ、さらにあがいてみた。 月ごとのとき (mode=month) にはリファラを表示しないようにして、 かなり速くなった。
残るは latest だ。 リファラを表示しなきゃ速いけど、 毎日リファラを見るために日単位のページを見るのも面倒だな。
……む、(自作の) リファラ整形プラグインを外すと異様に速い。 かなり処理をシンプルにしたはずなんだけど、これでもまだ重いのか。 重くなるとしたら検索エンジンからのリンクを排除してるところしか ありえないから、検索エンジンの数が多すぎるってことか。 ということは、自分のところに来る検索エンジンだけを 厳選して列挙すればずいぶん計算量を減らせるのではなかろうか。
減らすまでもなかった。 検索エンジンかどうか判断する正規表現を一つに統合し、 手動で共通パターンをくくりだすことで劇的に高速化できた。
ちなみにこんなの。
def search_engine?(url) %r[\Ahttp:// (?:(?>[^.]+)\. (?: google | yahoo | netscape | msn | metacrawler | webcrawler | altavista | odn | lycos | fresheye | goo\.ne\.jp | eniro\.se | excite | naver\.co\.jp | euroseek\.com | aol | allthweb\.com )[\./] | (?:[^/.]+\.)*search | (?>[^/]+)/search | bach\.\w+\.kobe-u\.ac\.jp/cgi-bin/metcha.cgi | brisbane\.t-online\.de/ | dir\.dion\.ne\.jp | find\.walla\.co\.il | i\.yappo\.jp | infoseek\.co\.jp | infobee\.ne\.jp | odin\.ingrid\.org | srchnavi\.nifty\.com | www\. (?: infoseek\.co\.jp | ceek\.jp | eniro\.se | redbox\.cz | kensaku\. | hotbot\. | planet\.nl ) )]xi =~ url
(03:12)
昨日ふれた「独自のリファラ解析プラグイン (refctl.rb)」 が欲しい人は CVS で取ってください。 cvs -d :pserver:anonymous@cvs.loveruby.net:/src co tdiarytools で取れます。 ただし後に述べるように、tdiary.rb にパッチが必要です。 これもやはり CVS に入っている、tdiary.rb-referer_day_only.diff を当ててください。
refctl.rb は解析というよりはフィルタです。 単純に検索エンジンからのリンクを除外して アクセスの多い順に並べているだけなので、 00default.rb とあまり変わりません。 ちょっと特徴的なのは URL のホスト部分を見ることで、 同じホストから来たリファラはアクセス数に関らず隣に並びます。
いずれにしても disp_referrer2 に比べると機能が低すぎるので 代用にはならないでしょう。 あくまで機能をあきらめて速度を稼ぐ類のプラグインです。 以下のようなポリシーの元に仕様を決めました。
このポリシーの元ではリファラ情報は三つのクラスに分割できます。
できるだけ重くならないようにクラスを判定するため、 latest へのアクセスはすべてアンテナとみなして アクセスが来た時点で特殊な URL にマップします (tdiary.rb にパッチが必要)。 検索エンジンは自動では判定できないので、 disp_referrer2 が使っている判定方式を流用します。
ただしここで disp_referrer2 の実装をそのまま使ってしまうと 速度はほとんど変わらなくなります。 昨日書いた通り、disp_referrer2 のボトルネックは検索語を取得するコードです。 大量のリファラに対して大量の正規表現 (しかも効率が悪い部類に属するパターン) を適用しているため、計算量が極端に上がっています。 refctl.rb では、何を検索したのかという 情報をあきらめることによって計算量を下げました。
ちなみに、細かくベンチマークを取ってみると、 必ずしも情報を減らさなくても速度は上げられることがわかります。 例えば ja/disp_referrer2.rb に以下のような正規表現があります。
%r{^http://.*?\bgoogle\.([^/]+)/(search|custom|ie)}i
これを以下のように変えるだけで コストは大きく下がります。
%r{\Ahttp://(?:[^./]+\.)*?google\.([^/]+)/(search|custom|ie)}i
工夫したのは以下の点です。
この工夫の意義を証明するため、 以下のように極端なケースにおけるベンチマークをとってみましょう。
# ベンチマークテスト require 'benchmark' n = 100_0000 url = 'http://a/' + ('googl.' * 10) + 'com' Benchmark.bm(16) {|x| x.report('original') { n.times do %r[^http://.*?\bgoogle] =~ url end } x.report('after') { n.times do %r[\Ahttp://(?:[^./]+\.)*?google] =~ url end } } # 結果 user system total real original 6.960000 0.000000 6.960000 ( 6.967214) after 0.910000 0.000000 0.910000 ( 0.911670)
実に 7 倍速。いろいろな条件で計測してみたところ、 改善後のパターンは改善前のパターンに比べ 25%〜800% の速度向上が見られました。 特に上記のようにマッチが失敗する場合に速度が向上します。
しかしこれでは失敗する場合にしか速度が上がらないように見えるので、 もう少し実地に近い条件でもデータをとってみましょう。 家に来る実際のリファラは 240 種類前後、 このうち Google のリファラが 100 種類前後、 平均 URL バイト長は 120 バイト、うちホスト部分が 21 バイトです。 一方 disp_referrer2.rb には正規表現が 59 個登録されています。 これを元に平均的なマッチ環境を想定し、 上記二つの正規表現の実行時間を測定すると、 Celeron 333A のマシンでは以下のような差が付きました。
user system total real dispref 0.910000 0.000000 0.910000 ( 0.913449) aamine 0.200000 0.000000 0.200000 ( 0.197613)
以上から、 正規表現マッチ部分については平均 450% の速度向上が期待できます。 disp_referrer2 の消費時間全体に対して正規表現マッチがどれくらいの 割合を占めているかはきちんと計測していませんが、 以前ベンチマークをとったときには parse_as_search が上位に来ていたので相当有効だと思います。 キャッシュと Nora がなくても現状の 2〜3 倍速はいけるんじゃないかな。 特にリファラが多い環境では効果が高いはずです。
(19:30)
http://www.dm4lab.to/~usa/ruby/d/200405c.html#id20040530_P1 より
> _ 「オープンソース関連が狙われてるところを見ると、 > 意図的にやってるんだろうなあ」って、最近やられてる > のはたいていCVSの穴からやられてる(らしい)わけで、 > そうなると必然的にオープンソース関連のところばかり > になるんじゃないでしょうか。
そっか。因果が逆の可能性があるわけですね。
(21:22)
■
通りすがりのバグ指摘人 [RSS を
http://http://i.loveruby.net/d/20040530.html#p01
のように吐いてます。]
■ ささだ [正規表現はさっぱりわからないんですが、onigurumaと以前の正規表現エンジンで、傾向は同じものなんでしょうか。]
■
青木 [RDFのバグの御指摘ありがとうございます。
その場しのぎでプラグインを修正したのが間違ってました。]
■
青木 [今回のはマッチの意味を考えてパターン自体をせばめて
いる (マッチしない文字列を増やした) ので、どんな
エンジンであっても性能がよくなる可能性が高いです。
例えば元のパターンは 'http://host/google.com/search'
や "aaa....a\nhttp://google.com/search" にもマッチ
しますが、変更後のパターンだとマッチしません。
つまり表現を変えただけではなくて、意味が違うんです。]
■ 青木 [あ、%r<\Ahttp://[^./]*?google> だとさらに速い。]
■ 青木 [嘘だ。[^./] じゃ排除しすぎだろ。]
■
zunda [ヒントをありがとうございます。正規表現を変えて試してみましたが、ほとんど速度は変わりませんでした。よくみてみたら、disp_referrer.rbの中で検索エンジンの正規表現を使う回数は、もともとあまり多くないようにしてあったのが原因のようです。
爆速disp_referrerを夢みてたんだけど…。あ、もしかして変な小細工するより総当たり=~の方が速いか?…続く(おい]
Copyright (c) 2002-2007 青木峰郎 / Minero Aoki. All rights reserved.
■ kawaji [Scheme に遅延評価できる仕組みって無かったでしたっけ?
マクロだったかな?]
■ shugo [delay/forceですかね。]
■ mput [delayは手動で指定してもまぁいいけど、forceは勝手にかかってほしいなと思うのはmputだけ?Promiseが値として評価されそうになったら自動でforceしてくれるとずいぶん楽になる気がしますが…]
■ KM [論文誌にこんなのがhttp://www.ipsj.or.jp/members/Trans/Jpn/03/2001/4211/article014.html]
■ kjana [Q とか。"streams" (a "lazy" variant of lists) っていうのが about にあったってだけですが。
http://q-lang.sourceforge.net/]