history

青木日記 RSS

<前月 | 最新 | 次月>

2004-03-05

今後の予定

この数日はプログラミングどころじゃなかったんで ほとんどマシンの電源を入れてませんでした。

今日からはしばらく暇なので、懸案をかたづけたいと思います。 まずは net/http かな。 次に比較的簡単な tdiarysearch のツッコミ検索をやっつける。 その次はその場にならないと決まらなそう。

Ripper はいつになるやらわかりません。 誰か続きを実装しませんか。 一番面倒なところは終わってるんだから、 あとはいちばん楽しいインターフェイス作りだけですよ。 ぼくにまかせてたら来年の夏休みとかになっちゃうかもしれませんよ。

(18:35)

ruby-list

冷静になって見なおすと、「わけのわからない」は余計だった。反省。

(20:14)

net/http

激しく熱い変更を入れました。

  • WebDAV メソッドを追加
  • net/https をマージ

さらに、これから PUT リクエストのボディに IO を使えるようにします。 こっちはさらに熱いぜ!

(02:03)

ruby

鬼車インポートきたー!

(02:06)


2004-03-06

BitChannel 初荒らし

そういえば、昨日 (金曜) の夕方、 BitChannel に初荒らしが来ました。 ところがその 6 時間後にはどなたかが直してくださったようです。 ありがとうございます。

ちなみに、ぼくが気付いたのはさらに 12 時間後でした。 楽してるなあ。

(03:32)


2004-03-07

net/http

さらに net/http をいろいろ変更した。

  • OpenSSL とりこみ、その 2

やっぱり require 'net/https' を必須にすることにした。 これなら OpenSSL がない環境では require が失敗してくれるのでわかりやすい。

  • リクエストボディに IO を使えるようになった。

コード例

require 'net/http'
 
Net::HTTP.start('localhost') {|http|
  req = Net::HTTP::Post.new('/')
  File.open('data.txt') {|f|
    req.body_stream = f
    req.content_length = File.size(f.path)
    print http.request(req).body
  }
}

POST に限らずなんでもいけます。

  • 同じヘッダが複数ある場合、配列で取れるようになった。

コード例

require 'net/http'
 
Net::HTTP.start('i.loveruby.net') {|http|
  res = http.get('/d/')
  p res.get_fields['Set-Cookie']
      #=> ["new=20040306123411; path=/d/; expires=Sun, 07-Mar-2004 05:52:38",
           "hoge=dxxxrag; path=/; expires=Sun, 07-Mar-2004 12:49:01"]

ようするに Set-Cookie 対策。

これでちょっと様子を見て、大丈夫そうなら正式採用とします。 1.8 はどうしよっかなあ。

(05:59)

2004-03-07

ついにねんがんの version.h を更新したぞ!

  • かんけいないね
  • ころしてでもうばいとる
  • たのむ、譲ってくれ

あー、とつぜんロマサガやりたくなってきた。特に 3 が。 好きなのは 1 なんだけど長いので真面目にやるのはだるい。 2 は自由度が極端に減ってしまったのが気に食わない。 最初はキャットに助けてもらわなかったおかげでやたら難易度高くて酷いめにあったなあ。 要塞とか草原の移動戦艦を真正面から攻略しないといけなくなる。 3 は雰囲気がけっこう好きだったけど、あいかわらずストーリーが支離滅裂だったな。

そういえばロマサガ 3 には株取引みたいなのがあったような気がする。 なんだっけあれ。

そういえば半熟英雄みたいな戦闘シーンもあったような気がする。 謎だな 3。

うわー、まずい、本当にやりたくなってきた。 買ってこようかな。

(06:51)

本日のツッコミ (全5件) [ツッコミを入れる]

よんひゃん [あおきさん、はじめまして。tdiarysearch についてなのですが、下記のような状況で動きません。
http://www.yhlee.org/diary/?date=20040307#p01
tdiarygrep を試してみたらちゃんと動いたので、とりあえずは問題ないのですが、tdiarysearch はいずれツッコミ検索にも対応されるということで、できればこちらが使いたいです。お時間のあるときにヒントをいただければありがたいです。]

ま2 [ロマサガ3は,お金儲けゲームみたいのがありましたね。私は2が一番好きです。1はバランスメチャクチャだけど人を引きつける魔力みたいのがありました。2は面白くなった分破天荒なところが減って,3以降(サガ・フロとか)とんでもゲーになりました。]

あづみ [株取引っちゅーか、目の前に金を積んで「うちの傘下に入らんか
ゴラァ!」と次々店を買収していくやつですな。
技を覚える瞬間の「ぴこーん」も好きでしたが、買収していって
新しいグループが発生する瞬間の「ぴん!」も好きでした。

ミニゲームはいっぱい遊んだ記憶あるけど、最後までクリアした
記憶が一度しかない^^]

あおき [そうかそうか、トレードでした。
「クラウディウスを知る者来たれ!」だと
百万単位でガスガス出してくれるのが気持ちいいやつ。

なんだかんだ言いつつもロマサガ 2 もやりまくったもの
です。やっぱりスーファミ時代のゲームがやりたいなあ。
もう年か……。]

よんひゃん [先日は、ていねいに対応していただきありがとうございました。
お礼が遅れてすみません。
自分でも少しずつ勉強していこうと思います。
これからも、どうぞよろしくお願いします。]


2004-03-10

Windows 上の Ruby の違い

http://ponx.s5.xrea.com/bibo/20040309.html#p02

ツッコミ入れようと思ったらエラーになってしまったので、 こちらに書いておきます。

Windows 上で動く Ruby それぞれの違いについてです。 あくまで「ぼくが理解した……」という頭書きつきで読んでほしいのですが、 まとめると次のようになります。

msvcrt というのは MS VC++ Runtime のことで、 ようするに libc みたいなもんです。 mswin32 ruby は VC++ でコンパイルして msvcrt とリンクした ruby。 mingw ruby は MinGW の gcc でコンパイルして msvcrt とリンクした ruby です。 だから mswin32 ruby と mingw ruby は拡張ライブラリを共有できます。

ついでに Cygwin 版というのは、 Cygwin の gcc でコンパイルして、 Cygwin DLL とリンクした ruby のことです。

ただし本質的なのはコンパイラではなく リンクしているライブラリのほうなので、 対応しているビルドスイートさえあれば Linux 上で Cygwin 用や msvcrt 用の ruby をクロスコンパイルすることもできます。

よーするに、問題は動くときの calling convention と ランタイムライブラリなんです。 アーキテクチャは同じ (i386) なんですから。

でもって bcc 版がよくわからんのですが、 あれもランタイムライブラリは msvcrt なんでしょうか? それとも独自 libc?

(追記) あー、とっくの昔にうささんの説明が出てた……

(追記 2) 田村さんのところにも言及があった……

(19:36)

ロマサガ 3 衝動

結局中古で買ってしまった。1280 円で安かった。 スーファミ本体は当然のごとく動態保存されているので問題なし。 AC 電源なんてファミコンのをずっと使ってるんだけど、よく壊れないな。

(20:17)

ruby のバイナリ互換性とぎれる

丁稚な日々 3/10より

うっわ、これはまたすごいな。構造体型フラグがのきなみ変わってる。 1 ビット空けたということは、1bit GC への布石と予測してみる結合テスト。

(02:10)

本日のツッコミ (全4件) [ツッコミを入れる]

小西 [bccはbccwin32となります。Microsoftのところのmsvcrt.dllはないです。RubyはCコールなのと、関数の名前付け規則の問題で、MicrosoftとBorlandのDLLは相乗りできないのです;;]

あおき [なるほど、別 DLL でしたか。
どうもありがとうございます。]

arton [RubyExtensionProgrammingGuide Rev12が途中で切れてるんだけど、これは改修中(意図的)だから? それとも事故?]

あおき [最後の文字が途中で切れてたりするし、事故っぽいですね。
送信途中で回線が切れたとか、そういうことでしょうか。]


2004-03-13

そしてまた

Alpha のマザーボードゲット。

しかし でんげんがたりない!

(19:19)

ほん

確定申告の副作用として 2003 年は本に 40 万以上費したことが明らかになったわけですが、 2004 年はまだ 1 万しか使っていません。 その 1 万で買ったのがこれ。

『Solaris デバイスドライバ』 佐島隆博著、オライリージャパン、2003

『4.4 BSD の設計と実装』 Marshall Kirk McKusick, Keith Bostic, Michael J. Karels, John S. Quarterman 著、 砂原秀樹監訳、七丈直弘訳、ASCII、2003

このラインナップを見ると、 どうも OS がマイブームらしいということがわかります。 ま、どうでもいいですけど。

ところで『Solarisデバイスドライバ』ですが、なかなか愉快な本です。 第一章でお約束の null デバイスを作ったかと思うと 第二章がいきなり Matrox Millennium II で、 しかもビデオカードとして使うのではなくてメモリとして使うらしい。

萌える〜。

で、第三章からが本番で、 ギガビットイーサネットアダプタ TC9020 のドライバを書きます。 ちゃんと使えるドライバを全部作ってくれるのが気持ちいい。 もちろんソースコードがビシバシと出てくるし、 350 ページ中の末尾 100 ページは全部ソースコードです (Makefile も付いてます)。

燃える〜。

世の中、萌え燃えだよ。

(20:02)

本日のツッコミ (全2件) [ツッコミを入れる]

ささだ [じゃあ次はOSを独習する前に読む本ですか。]

anonymous [書籍代が40万円以上というのはすごいですね。
何かの写真で、本のぎっしり詰まった大きな本棚をみて、「おおお」とは思いましたが。]


2004-03-15

Alphaでもクロックカウント

http://mput.dip.jp/mput/?date=20040314#p01

「タイムスタンプカウンタは Pentium と Alpha と PowerPC にある」 なんて言われてしまうと Alpha でも誰かがやらなければなるまい。 "Alpha Architecture Reference Manual" を見てみると なんとなくそれっぽい PCC (Process Cycle Counter) register というのを発見した。

下位 32 ビット (PCC_CNT) は CPU サイクル N ごとにインクリメントされるらしい。 N は 1 から 16 までの実装依存……てなんだよそりゃ。 PowerPC みたいにバスクロックでカウントされるのかなあ。

一方、上位 32 ビット (PCC_OFF) は OS 依存らしい。OS? でも「OFF」はたぶん「offset」の略だろうな。 普通に実装してあれば 64 ビット整数として読めるってことか。

あっ、それも書いてあった。 OpenVMS と Tru64UNIX はプロセスごとのタイムスライスを持つようだ。 マシン全体ではないのね。

PCC レジスタは RPCC (Read PCC) 命令で読めるらしい。 ふーむ。こんな感じでいいのかなあ。

#include <stdio.h>
 
static unsigned long
rpcc(void)
{
    __asm__ volatile (
      "rpcc $0\n"
    );
    return;
}
 
#define PCC_CNT(pcc) ((pcc) & 0xffffffffL)
#define PCC_OFF(pcc) ((pcc) >> 32)
 
static void
print_rpcc()
{
    unsigned long pcc = rpcc();
 
    printf("PCC     = %016lx\n", pcc);
    printf("PCC_CNT =         %08lx\n", PCC_CNT(pcc));
    printf("PCC_OFF = %08lx\n", PCC_OFF(pcc));
}

これだと rpcc() の返り値が正しくないように見えるが、 Alpha では返り値を整数レジスタ 0 ($0) で返すので アセンブラレベルではうまくいく。と思う。 unsigned long を返す関数を定義してコンパイルしてみたら ほぼ同じコードになったのでたぶん大丈夫だろう。

この関数を使い 1 秒 sleep しつつ PCC を表示してみる。 できれば Tru64 でやりたかったんだけど、 まだ gcc を入れてないのでとりあえず NetBSD/Alpha だ。

aamine@asv800 % ./rpcc
PCC     = 3a7950a5579ad207
PCC_CNT =         579ad207
PCC_OFF = 3a7950a5
 
PCC     = 309d4e756ba2cda0
PCC_CNT =         6ba2cda0
PCC_OFF = 309d4e75
 
PCC     = 26a43e187fa3ce87
PCC_CNT =         7fa3ce87
PCC_OFF = 26a43e18
 
PCC     = 1c8d622f93a4cb79
PCC_CNT =         93a4cb79
PCC_OFF = 1c8d622f
 
PCC     = 1258c7a0a7a5cd87
PCC_CNT =         a7a5cd87
PCC_OFF = 1258c7a0

えっと、なんか PCC_OFF が変化しすぎ? なんだろうなこの値は。これは NetBSD カーネルも読まないとだめか。

つづく。

(18:01)

Alphaでもクロックカウント (2)

NetBSD のヘッダファイル alpha/alpha_cpu.h で、 alpha_rpcc() という直球な関数を発見した。

static __inline unsigned long
alpha_rpcc(void)
{
        unsigned long v0;
 
        __asm __volatile("rpcc %0" : "=r" (v0));
        return (v0);
}

こう書けばよかったのか。

(18:09)

Alphaでもクロックカウント (3) Tru64UNIX の場合

一方 Tru64UNIX では、alpha/kintrinsics.h という 怪しげなヘッダファイルに rpcc() という関数の宣言を発見した。 しかし「k」intrinsics だけあってカーネルの内部関数だったらしい。

しかたがないので、まずダミー関数を書いておいて cc -S rpcc.c でアセンブリソースを生成し、return 77 に相当する部分を rpcc $0 に置き換えた。うまくいくかな。

~/c/test/rpcc % for i (a b c d e) { ./rpcc; sleep 1 }
5a0f27cda62505f6
410e81e0bf212645
286c7741d7c2c8d4
0fc9d1aff0642e68
f72717a20907be70

取れた。値の遷移には NetBSD と同じ傾向が見られる。 ますます謎だ。

(19:03)

i.loveruby.net ダウン

今日 3/15 (月) の 19:30 ごろ、 i.loveruby.net が原因不明の過負荷状態に陥ったため一時マシンを停止しました。 いちおう直ったみたいですが、まだ妙に重いですね。やばいかなこれは。

(19:46)


2004-03-16

cdr

ふと見るとホームディレクトリに cdr/ というディレクトリがあった。 「cdr? なんで Lisp?」と思ったが、 よくよく考えると CD-R を焼くディレクトリだった。

汚染されてるなあ。

(13:58)

TD4制作記 #5.1 電源パターンの強化

激しいブランクののち製作を再開。 三ヶ月も空いてしまったか……。

もう何をやってたのかすっかり忘れてるな。 ああそうか、電源パターンの強化だった。 これ、本当にやらなきゃだめなのかなあ。 すっとばしても動いたりしないだろうか。 まあたぶん動いちゃうんだろうけど、 まんがいちだめだった場合に泣きそうだしなあ。 真面目にやるか。

しかしすぐ飽きる。回路図に出てこない線なので 赤ペンで塗りつぶせるわけでもなく、たいくつだ。 それでいてこれが結構むずかしい。 回路表面の一点にとっかかりなしで二本のリードをつけないといけないので、 こう、うまく二本をいっしょにまとめて……ああっ、外れた! 片方ずつ付けると、二本目を付けてるあいだに一本目が外れてしまうし。

片側やって飽きた。電源関係の残りを先にやるか。 だまだまを作って 5V と GND に直結する。 こっちは楽しい。

やる前は大変そうに見えて実は簡単なのが IC のハンダ付けだ。 テンポよく付けていけば足一本に一秒もかからないので、 IC 一個につき一分もあれば終わる。 IC に限らず、回路をいじってる限りは進行は早い。

一方めんどくさいのは何と言ってもリード線。 長さを決めて切って被覆をむくのがめんどくさくてしかたがない。 逆に言えば、回路を自分で焼いてしまうとめちゃくちゃ簡単そうだ。

ま、そんなわけで電源パターンの強化はめんどくさい。地道にやろう。

(15:33)

TD4制作記 #5.2 リード線剥きの短縮法

だめだ、地道にやるのは性に合わない。

1. 片側だけを長めにむいておき、芯線を机で押し込んでズラす。 一本につき剥くのが一回だけで済んでちょっと楽。

2. 二本いっぺんにカッターで剥く。

3. リード線を長めに切って片側だけ被覆を剥いておく。 使う直前に剥いてないほうを切って 1. を使って両側を出す。 いちいちリード線を切らずに一気にハンダ付けできるのでちょっと楽。

ああ、激しく車輪の再開発をしてる感じ。

ところで、ずっと思ってたんだけど、何で車輪なんだろうね?

(15:44)

TD4制作記 #5.3 ウレタン線?

情報ありがとうございます。 ウレタン線……このサイトで紹介されている UEW というやつですね。

http://elm-chan.org/docs/wire/wiring.html

おおっ、これは……楽そうだ! レジスタまわりの配線もこれなら余裕でいけるかも。

(16:26)

本日のツッコミ (全1件) [ツッコミを入れる]

Yuya [信号線なら、ウレタン線を使うとか。]


2004-03-19

RHG 読書会 reloaded

明日は RHG 読書会です。 先月はお休みだったのでずいぶん久しぶりな感じですねえ。 場所・時間はいつものとおり。

(15:51)

だらだらー

ここ数日はやる気なくだらだらしてます。 TD4 の配線したり Alpha のファームウェアまわりの仕組みを調べたり。 その結果をまとめたのがこのへんのページ。

そういえば、その途中でクロックカウンタの使いかたも判明しました。 PCC_OFF (PCC の上位 32 ビット) と PCC_CNT (PCC の下位 32 ビット) を足すと目的の値が出るらしいです。 ただその値はプロセスごとのクロックカウントなので、 絶対時間を計測するのには使えない模様。 この仕様はファームウェア (正確には PALcode) レベルで決まっているので ユーザレベルから手を出すのは困難です、というか無理です。 カーネル内なら PALcode の管理してる領域に手を出せるのでどうにかなりそうです。

(16:13)

SKK 派の意見

SKK じゃないと原稿が書けない人間としてひとこと言っておきたい!

なぜ SKK が好きかと言えば、変換単位が小さいからでしょうね。 確かに MS IME とか ATOK とかその他いろいろな IME は 長い文章を一気に変換するのは優秀です。 でも、逆に言えば文章が長くないとうまく変換できないわけですよ。 例えば文を一気に書いてから一部をちょっと手直しする場合、 結局文節や文字単位で変換することになる。

でもって、長い文章を書くときに重要なのはどっちだと思います? 文章を最初に入れるときか、後から追加修正するときか。 統計をとって調べたわけじゃありませんが、ぼくは後者だと思います。 だいたい追加修正のほうが時間がかかるし、たくさんやるんです。 だから、効率を考えるなら追加修正機能にこそ注力しないといけません。 その点において現在の主流である連文節変換 IME は全く能力不足です。

(16:35)

vi派の意見

実は vi が好きってのも同じ理由だな。 最初の一回が早いエディタより、 その後の追加修正が早いエディタのほうが好きだ。

(16:45)

矛盾

でも SKK は Emacs で使ってるんですけどね……

(16:46)

ssh

ようやく Tru64UNIX のホストにも ssh でつながるようになった。 かねがね思ってたんだが、ssh の設定は OS ごとに差がありすぎだ。 public key の設定 (ログインされる側) だけでもこんなにある。

  • SSH1/SSH2 共用で authorized_keys, authorized_keys2 が両方ある
  • SSH2 only で authorized_keys だけ
  • authorization にキーファイル名を記述して別ファイル

頼むから、こんなところで多様性を追求するのはやめてくれ。

(19:33)

本日のツッコミ (全7件) [ツッコミを入れる]

shugo [では一文字単位で入力できるt-codeを、とか。]

青木 [t-code にも興味はあるんですが、
学習コストが大きすぎるのがちょっと……。]

ただただし [若いうちがチャンスだわよ >T-code]

t15u [vi+T-Codeは快感です。2週間くらいかけて気合でT-Codeの
ひらがな全部覚えれば後はまぜ書き変換使ってジョジョに
なんとかなります。]

kawaji [tmail の時代が来る! のかな?
http://www.icann.org/tlds/stld-apps-19mar04/mail.htm]

青木 [もう年なので t-code は覚えられませんと言ってみる]

青木 [商標とっといたら儲けられたのかなあ > .tmail]


2004-03-23

RHG読書会 reloaded #7

土曜の記録を火曜に書くってのはいかがなものか。 とりあえず、全般的な記録は RWiki からどうぞ。

今回は対象範囲が短いわりに興味深い論点が多くありました。

個人的に一番面白かったのは $SAFE の話かな。 あのあともうちょい考えたんですが、確かに今の $SAFE の仕様は変です。 すんごく単純に考えると、 $SAFE=1 では tainted なオブジェクトは多いほどよいはずです。 一方 $SAFE=4 では tainted なオブジェクトは少ないほどよいはずです。 これは明らかに矛盾している。

ちなみに $SAFE=4 の理想的な姿はどうかと言うと、 (今の仕様で言う) tainted オブジェクトがない状態から始めて 公開してもよいオブジェクトだけを taint し、$SAFE=4 に入るのがベストでしょう。

それからまた別の話題で、正規表現の名前付きキャプチャ。 いまは括弧にマッチした部分は $1, $2... のように番号でしか取れないけど、 それを名前で取りたいという話です。 akr さんはローカル変数に代入されるのがベストだという意見でした。 こんな感じかな?

if /xxx(?k=foo:....)xxx(?k=bar:....)/ =~ str
  p foo   # マッチすると代入されている
  p bar
end

正規表現中の文法は議論を覚えてないので今でっちあげました。 なお、この機能は正規表現リテラルを直接書いた場合だけ働き、 埋め込み式 #{....} がある場合も機能しません。

一方、ぼくの意見はこんなんです。 あくまで現在の延長線上でしかない仕様ですね。

if m = /xxx(?k=foo:....)xxx(?k=bar:....)/.match(str)
  foo, bar = *m.select(:foo, :bar)
  p foo
  p bar
end

あっ、そうだ、Binding を明示的に渡すというのはどうだろう!

if /xxx(?k=foo:....)xxx(?k=bar:....)/.match(str, binding())
  p foo
  p bar
end

先生、とても組み込みライブラリの仕様には見えません!

ああ、あとそれから、POOS (Plain Old Open Source) っていうネタもあったなあ。

RHG読書会・二次会

読書会が一次会なのか……。

「ネタバレ防止本棚」にはかなり笑った。

そういえば「Rubyの会」がもうすぐ発足するらしい。

RHG読書会・三次会

酒井さんから「代数」について学ぶ会。

RHG読書会・その後

さらにそのあと、終電のなくなった酒井さんにつきあって 笹田さんの研究室にお邪魔してきました。 メンバーは笹田さん・酒井さん・shelarcy さん・青木。

いやあ……

いろんな意味で濃かった。

(21:11)

本日のツッコミ (全5件) [ツッコミを入れる]

こさこ [正規表現リテラルの場合だけ機能するということで満足するかしないか、という選択の問題だと思います。]

shiro [飛び入りしますが、正規表現リテラルを「プログラムコードの一部」とみるか、組み込みであっても外部のオブジェクトと見るかの差とも言えるかも。正規表現リテラルがfirst class objectとして扱われていないなら、わざわざ正規表現オブジェクトを作成するまでもなく、正規表現のマッチコードを自体を周囲のコードのコンパイル結果に埋め込んでしまう、という選択肢が考えられるわけで。そういう文脈で考えればレキシカルにマッチ結果が束縛されるのは自然ですね。]

akr [読書会では Regexp は、String を受け取ってマッチ可能かどうかを真偽値を返しつつ、
副作用としてキャプチャした部分文字列をローカル変数に代入するクロージャである、
という考え方を述べました。
(もちろんマッチオブジェクトを $~ に代入すると言う副作用もあっていいわけです)

言いませんでしたが、この考え方を押し進めると、
Regexp A の中に #{} で Regexp B を埋め込むのは、
特殊な関数呼び出しであって、そうだとすれば
B 内のキャプチャは B がリテラルとして記述されたスコープにおけるローカル変数への代入になるのが自然であるとも考えられます。]

shiro [Schemer的には、副作用よりは束縛の導入にしたくなります。こんな感じ:

(with-regexp #/(?k=foo:...)(?k=bar:...)/
... ;; ここでfoo, barが束縛されている
)

ただ、これだと別の箇所で出てきたregexp Bを埋め込むってところのセマンティクスが難しいかなあ。

いずれにせよ、これはおもしろそうなんで、ちょっといじくってみようと思います。]

akr [問題は first class な pattern はどうあるべきかってところですかね。
なんか、いかにも論文がありそうな感じ。]


2004-03-24

正規表現の名前付きキャプチャ

with-regex は Ruby 的にはブロックでしょうね。

/xxx(?<var>.....)xxx/.if_match(str) {
  p var
}

こっちのほうが binding よりはマシっぽい。

でも else が書けないのは嫌だな。かなり無理矢理だが、 マッチしなかったらメソッドが nil を返すってことにして……

/xxx(?<var>.....)xxx/.if_match(str) {
  p var
} or return nil

うわ、読みづらっ! これはだめだー。

正規表現の名前付きキャプチャ (2)

http://cvs.m17n.org/~akr/diary/d2004_03.html#a2004_03_24_1

名前付き括弧の利点は、括弧の順番が変わっても大丈夫というところだと思います。 そういう利点があるんだから、多少コードが長くなってもいいんじゃないでしょうか。 メソッドを呼ぶと知らないうちにローカル変数に代入されてるってのは やっぱり想像しにくいですよう。

(02:46)

本日のツッコミ (全2件) [ツッコミを入れる]

kjana [/(?<s1>foo).*(?<s2>bar).*/.match(string) {|m| p m[:s1]} とか.
MatchData#[] が Symbol を受け付けるようにするだけ.微妙....

if m = regexp.match(string)
puts m[:foo]
else
puts "nothing matched."
end

ってな書き方はできる.Regexp の埋め込み? 気にしちゃいけない :-P]

akr [$~[] に名前を使うことに関しては、[ruby-dev:19785] で、まつもとさんが、
「1.9がはじまったら私の方でやります。ちょっと待っててね。」と述べています。

したがって、(ちょっとというのがいつのことかはともかくとして)それはそうなるはずです。

ただ、それだけだと $1 より短くはならないと思うんですよね。]


2004-03-25

やふおく

ヤフオクに凄いものガっ!

http://page.auctions.yahoo.co.jp/jp/auction/65997681

AlphaServer ES40 だよー。21264 が 4 発。 いいなあっ。

どうも、春に Alpha が出る確率が高いような気がする。 やっぱこの時期に放出されんのかね。

(07:53)

ロマサガ 3

とりあえずフォルネウス (影) をぬっころしておいた。 やっぱ四魔貴族戦の音楽はかっこいいなあ。影も実体も。

それにしても最初にやったのが 8 年前だけあってすっかり忘れてる。 「ぬれてにあわ ぬれてにあわ」とか「きょ・う・じゅ」とか、 本筋と全然関係ないキーワードは覚えてるんだけど。

(10:15)

Ripper

四月になったら Ripper に手を出そうかと思います。

(10:29)

BitChannel / 日本語ページ名 (1) とりあえずネタ

ホームを歩きながら Wiki で日本語ページ名を扱う方法を考えていたら すごいアイデアを思いつきますた!

「t-code エンコーディング」

[[ ]] の中に t-code でページ名 (もちろん日本語) を書いておくと 変換後の文字列がページキャプションになる。 変換前の文字列が URL になる。

(15:11)

正規表現の名前付きキャプチャ (2)

http://cvs.m17n.org/~akr/diary/d2004_03.html#a2004_03_25_1

簡潔であり、かつ変更に強い記法が一番よいという点は同意します。 しかし、まず他のメソッド内でローカル変数に代入させるという操作自体が、 ぼくは Ruby 的でないと思うのです。 つまり、ローカル変数に代入させるということ自体をまずあきらめている。 そしてローカル変数がだめなら他の変数系は論外だし、 そうなるとどうしてもメソッド呼び出しくらいはやらなきゃだめでしょう。 それじゃどうせ m[:foo] と比べてたいして短くならないんだから これ以上短くするのは潔くあきらめたほうがよいと思います。 以上が前回の発言の背景です。

また他に akr さんの案で弱いと思うのは、 リテラルとして書かれた場合にのみ働くというところです。 この自動代入機能 (と仮に呼ぶ) は、 確かに変化に強い記法の中では最も簡潔であって、プログラマに好まれます。 従ってプログラマはできることならそちらを使いたいので、 正規表現を複数のパーツに分割したり定数に入れたりするのをやめてしまうかもしれません。 これはより広い視点で見たときにコードの質を落とす圧力となるのではないでしょうか。

と、ここまで書いたところで全然違う活用案を思いつきました。 MatchData の特異メソッドにするってのはどうだろう。

m = /xxx(?<foo>....)xxx/.match(str)
p m.foo

(16:18)

BitChannel / 日本語ページ名 (2) まだひっぱる

t-code と同軸のネタで、 ローマ字入力しておくとひらがなに変わるというのもあります。 別にカナ打ちでもいいですが。

さらに、SKK 風にシフトを入れて打つと WikiName っぽくなるので それを適当に変換するという無理無理なネタも考えました。 submit すると変換候補をリストアップして返してくるので、 そこから選びます。

無駄すぎる。

(16:58)

BitChannel / 日本語ページ名 (3) こっからマジネタで

マジにネタレスというのはどうだろ。 「マジパンにレタス」と少し似ている。

どうでもいいか……

唐突に話を始めます。

現在 BitChannel は日本語ページ名を認めていません。 BracketName はあるんですが、[a-zA-Z0-9] 以外が入ってるとリンクになりません。 日本語ページ名のいい実装を思いついてから許可しようと考えているからです。

では、どんな条件を満たすのが (BitChannel 的に) いい実装でしょうか。 少なくとも以下の条件は必要だと考えています。

  • URL が % まみれになるのは許容できない
  • URL にはできるかぎり意味のある名前を付けたい
  • 同じタイトルのページが複数存在してはならない
  • 「新規作成」が必要になってはならない
  • 同一 Wiki 内の特定ページにリンクを張る方法はただ一つでなければならない
  • ソースコード上と表示画面上の見ためは同じであってほしい

えらい厳しい要求にも見えますが、 WikiName だけの Wiki ではこの条件がすべて満たされています。 したがって日本語を入れる際にも この条件は満たしたまま導入しなければ我々の負けです (そういう問題か?)

なお WikiName の特徴としてもう一つ挙げられるのが、 文字を追加するのではなく、文字を削ることで意味を持たせる点です。 できることならこの特徴もエミュレートしたかったんですが、 あまりにも無理そうだったのでやめました。 人間、限度はわきまえないといかん。

BitChannel / 日本語ページ名 (4) リンク作成スキーム

まず Wiki ソース上でリンクを作成する方法について考える。

[1] BracketName。[[ ]] でくくって指定する。 ソースと表示画面で見ためが違うのがちょっと嬉しくない。 またどんな文字列でもリンクにできてしまうのは両刃の刃。

[2] 1 の変形で、””や「」でくくる。 こちらの場合は ””などの区切り文字自体も表示されることが多いようだ。 その点で 1 よりは多少よい。しかし見ためがあまり嬉しくない。

[3] はてなキーワード方式。 既存の日本語ページ名と一致する部分文字列が自動的にそのページへのリンクになる。 この方式は特殊な工夫を併用しないかぎり ページの作成に「新規作成」メニューが必要になるので許容できない。

[4] スペースで区切られた部分文字列が「××の××」であった場合、それをリンクとする。 「××」は漢字・カタカナ・ひらがなのいずれかでなければならない。 行頭に置くと pre ブロックの文法と衝突するのが問題。 マッチしすぎそうなのが問題。 直感的でないのが問題。 ルールが独特すぎるのも問題。

[5] XXXXX-no-XXXXX をリンクとする。 これをひらがなに変換してページ名とする。 漢字は使えない。

[6] t-cod(ry

[7] 任意桁を縦読みしたときに「リンク」ってなってたらリンク

[8] 「→」を前にくっつける。本質的には BracketName とたいして違わない。 (SKK だと zl で「→」が出せることに頼って他の IME ユーザを度外視した作戦)

[9] 一文字だけの行が三行以上続いてたら全部つなげてリンク

[10] ある行が「××の××」という形式だったらリンク

なんかあれを思い出すね、傘の使い道をたくさん考えなさいってやつ。

BitChannel / 日本語ページ名 (5) ページ名 → URL マッピングスキーム

次に、ページ名を URL にマッピングする方式について考える。

[1] ページタイトル文字列をそのまま URL エンコードして生成する。 最も一般的だが、この方式は URL を意味不明かつ % まみれにするので許容できない。 また URL が内部文字コードに依存する点は明らかに問題である。

[2] ID 方式。システム側がページに ID を割り振り、URL ではそちらを使う。 この方式は URL が意味不明になるので許容できない。

[3] 最初にページを作るときにアルファベット名を指定させ、URL ではそれを使う。 この方式では最適な URL を生成できるが、 ページ作成の手間が多少増えるのが問題である。

[4] ページ名を kakasi にかけて無理矢理アルファベットに変換する。 この方式では 3 におけるページ作成の手間を削減できるが、 必ずしも読みやすいとは言えない。 またインストールの手間も増える。

[5] だから t-cod(ry

BitChannel / 日本語ページ名 (6) 小まとめ

現実的なのは BracketName と生成時の別名指定か。 「ソース上と表示画面上の見ためが同じ」 というポリシーだけ捨てれば採用できる。 でも、本当にそれでいいのかなあ。おもしろくないなあ。

おもしろさだけで言えば「××の××」形式だろう。 「××の××」ってのは、なーんとなく 「形容詞 + 名詞」のページが多いかと思って選んだんだけど、 ちゃんと統計をとって決めれば意外と使えるかもしれない。

それにつけても眠い。 眠いからこんなはっちゃけたないようがないようなないようになってるわけか。

(19:33)

MonaWiki

そういえば、メインバックエンドに CVS がいる Wiki で MonaWiki というのがあるんですね。例によって YukiWiki 系だそうです。

http://www.hyuki.com/yukiwiki/wiki.cgi?MonaWiki

(19:42)

本日のツッコミ (全5件) [ツッコミを入れる]

ねたに混じれ酢 [それで、そのURLからはページ名がすぐに思い浮かぶのですか?
>t-code使いの方々]

shiro [「リテラルとして書かれた場合のみ」:処理系の立場からすると、動的なregexpはevalするコード、リテラルは地のコードってことなんで不自然じゃないですね。むしろregexpを言語外のエンティティとして扱ってきた歴史が、両者の混在に対してなんか落ち着かない感じを覚える理由なんではないかと(自分では)思います。]

ねた(に混じれ酢)\\1 [(少なくとも私は)思い浮かばないですね。謎の文字列にしか見えません。
またその文字列のとおりにキーボード上で指を動かしても、脳内デコードはできません。]

t15u [漢字->指の動き○、漢字->謎の文字列×、
指の動き->漢字×、謎の文字列->漢字×
私の場合もこうです。
わかりにくさを利用してパスワードをT-Codeでいれることがあります。]

青木 [そうかあ、t-code エンコーディングはだめですか。
とすると流用できそうなのは、単に圧縮度の高いエンコード手段、
くらいでしょうか。]


2004-03-26

正規表現の名前付きキャプチャ

http://cvs.m17n.org/~akr/diary/d2004_03.html#a2004_03_26_1

そうか、MatchData のメソッドにマップする案は既に出てたんですね。

ちなみに「$ 変数ステ」の流れに思いきり逆行して $~name てのはどうでしょうか。 だめですね、はい。

さて、「Ruby 的でない」だけではわからんと言われたので どこが Ruby 的でないと思うか説明します。 Ruby 的でないと思ったのは、 「正規表現をクロージャと考えれば」というところです。 現在 Ruby でクロージャを作るにはブロックを使うか、 メソッドやクラスを定義するか eval するしかありません。 つまり eval 以外は「{....}」か「予約語〜end」です。 正規表現の文法はこのどちらでもないので クロージャ (を作る文法だ) とは認めたくありません。 また eval に似せるなら dynamic scope でないといけません。

だから逆に言うえば「{....}」か「予約語〜end」ならクロージャでもいいです。 ただし %r{....} なんてのは嘘くさいので嫌です。

またそこは我慢するとしても、 その場合は /regexp/ の「/」と「/」の間が文法的なスコープに なるのではないでしょうか。例えば /xxx(?<a=>....)xxx/ は、

lambda { ....; a = xxx; .... }

であって、Ruby ルールでは a は外からは見えないはずです。 もっとも

a = nil
re = lambda { ....; a = xxx; .... }
p a

であれば納得できますが、この場合、 a = nil は正規表現よりも前になければいけないと思います。 つまり以下のように書くのなら納得できます。

# パターン1
a = nil
if /xxx(?<a=>....)xxx/ =~ str
  p a
end
 
# パターン2
a = nil
re = /xxx(?<a=>....)xxx/
....
if re =~ str
  p a
end

一方、yacc のように部分パターンごとに アクションが指定できるというのはアリだと感じます。 アクションブロックの文法がブロックに似ていれば違和感を感じません。 例えば

/xxx(??.....){|name| p name }xxxx/ =~ str

とか……。

あ、でもこの場合はそもそも名前付きとは言えませんね。 しかもブロック内なので代入してもブロックローカル。 ブロックが複数あるときに情報を渡すのがめんどくさい。 バックトラックしたらどうなるのか混乱する。 などなど、いろいろな罠がありそうです。

あああああ! そうか! 正規表現一つで済まそうとするからいけないんだ! 正規表現パターンとアクションを組にできるようにして、 それを合成して作ればいい。

pat1 = /xxx/ {|tok| p str }
pat2 = /yyy/ {|tok| p str }
re = /aaa#{pat1}aaa#{pat2}aaa/

awk だな。awk すぎる。#{...} を使って直接埋め込めばテンポラリ変数も不要か。

re = /aaa#{
       /xxx/ {|str| p str }
     }aaa#{
       /yyy/ {|str| p str }
     }aaa/

むむ……意外といけそうな気がしてきた。

うーん。 でも、こういうアクションみたいのは共有して嬉しいことはなさそうだから、 ブロックは正規表現にではなくマッチする場所に所属するべきか。

/re/ { .... } がパターンとブロックの組を新しく作って返せばいいのかな。 ついでに Regexp#on_match を作って同様の操作ができれば ブロックだけオーバーライドできる。

WikiName = /([A-Z][a-z0-9]+){2,}/
 
def compile(src)
  syntax = / #{ WikiName.on_match {|str| .... } }
           | #{ URI.regexp(%w(http ftp)).on_match {|str| .... } }
           | #{ /[<>&"]/ {|c| escape_html(c) } }
           /x
  src.gsub(syntax) {....}   # ここで破綻
end

だめだ、使えない。 このセンはあきらめよう。

(04:29)


2004-03-27

BitChannel 更新

  • 藤本さんにプレビューパッチをいただいたのでとりこんだ
  • Diff ページで + と - の行に span を付けた
  • View 以外のページはロボットを拒否するようにした (とりあえず meta のみ)
  • History から各リビジョンの annotate へリンクを張った
  • エンコーディングを明示的に統一するようにした

ちょっと様子を見て 0.2 を出しますか。

ちなみにコメントボックスと日本語ページ名を実装したら 1.0 にします。

(06:02)

BitChannel 日本語ページ名 (7)

もういっこ考えついた。 単語の「日本語 → アルファベット」の組をたくさん登録しておき、 登録単語 2 or 3 個以上を組み合わせた場合のみページ名となる。 登録した単語のアルファベット名を連結して URL を作る。

あらかじめ SKK 辞書あたりから単語をひっぱっておけば それなりの範囲をカバーできそうだが、 どう考えても実用には足りないので変換時に登録を許すことにする。 [[ ]] でくくると強制リンクとなるが、 この内容が登録済み単語の組み合わせに分解できない場合は 分解できるまで何度でも新しい単語を登録させる。

疑問

  • アルファベットや数字との組み合わせを許すか
  • 単語数に上限を設けるべきか
  • 下限は 2 か 3 か
  • 「あ」から「ん」まで登録してしまうと結局なんでもいけそう
  • 同様に、いろんな単語を登録しまくるとページをリンクだらけにできる
  • てなことを考えると、単語にもそれなりの制限をかけるべきだろう

利点

  • 文法的にはかなり WikiName に近い
  • 単語を厳選しておけば不適切なページ名を自動的に排除できる。 例えば初心者がつけがちな、文章そのままのページは事実上作れない。
  • アルファベット表記が同じになる場合には単語登録自体を拒否すれば、 同音異義語問題を事前に解決できる。

欠点

  • 新しくページを作るのがさらに面倒になる
  • 登録した「日本語 → アルファベット」の組を変えると URL も変わるのか? (現実的にはページ作成時に決めるんだろうな)
  • 単語追加時の処理がそうとう重そう

(12:19)

本日のツッコミ (全5件) [ツッコミを入れる]

id派 [http://www.kanzaki.com/docs/Style/URI.html
のように長い目で見てURLに文書のタイトルを入れるべきではないという意見もあります]

非ID派 [本当に「件名を入れるべきではない」と書いてありますか?
(たしかに、「件名による分類は避けるべきだ」という記述はあります。)]

id派 [『最初はたいていうまく行くように見えるのに、あっという間に違ってきます。』と書いてあります。]

青木 [元々の文章が曖昧なのがいかんと思いますが、これは
やっぱり分類 (ディレクトリ) に関する話でしょう。
その証拠として、直後に「よい」 URL の例として
".../chairs" が提示されています。一切名前を使う
べきでないのなら、識別子 chairs は不適切です。

また、ちょっと方向性の違う話ですが、そもそも URL が
変わって困るのは、自分の欲しい情報にたどりつけなく
なるからです。しかし Wiki においてはページ名を変え
たら新しいページへのリンクを作るのが一般的ですから、
被害は最小限にとどめられると思います。]

青木 [(補足) プログラムで自動化する場合は例外ですが、
現実的に見て HTML と HTTP を使ったレガシーシステムに
そこまで厳密性を期待するのは間違いだと思います。]


2004-03-28

net/pop

sprintf がらみの酷いバグを指摘されたので修正。

POPS はどうしようかなあ。 これ以上 start の引数を増やすのは嫌だから、 net/https みたく new してセットするようにしようかな。

(14:41)

BitChannel / mod_ruby対応で悩む

今日はひたすら実装の日なのです。

1. mod_ruby だと $0 が false になっている

Apache.request.filename で代用。

2. fork すると直後に SEGV

謎だ。例えば次のようなプログラムを実行すると、

# fork.rbx
 
def log(msg)
  File.open('/tmp/log', 'a') {|f| f.puts msg }
end
 
log "pid=#{$$}: start"
pid = Process.fork {
  log "pid=#{$$}: (child) fork OK"
  exit 0
}
log "pid=#{$$}: (parent) child=#{pid}"
dummy, status = Process.waitpid2(pid)
log "pid=#{$$}: waitpid=#{status.inspect}"
print "HTTP/1.1 200 OK\r\n"
print "Content-Type: text/plain\r\n"
print "Content-Length: 3\r\n\r\nOK\n"
log "pid=#{$$}: program exit"

ログがこうなって、SEGV で落ちているらしいことがわかる。

pid=23072: start
pid=23072: (parent) child=23079
pid=23072: waitpid=#<Process::Status: pid=23079,signaled(SIGSEGV=11)>
pid=23072: program exit

なお環境は以下の通り。

  • ruby 1.9.0 (2004-03-16) [i686-linux]
  • apache 1.3.28 (with/without mod_ssl)
  • mod_ruby -rversion_1_0 (apxs)

(21:47)

(追記) Ruby が古いだけだった。情けない。

BitChannel / mod_ruby対応 (2)

やっぱりいろいろ間違っていた。

  • 実行順序の勘違いで、waitpid されていなかった
  • その結果としてコマンドが失敗しても無視されていた
  • さらにゾンビが大量発生 (CGI だと発覚しない)
  • そして問題の根源は CVS レポジトリのパーミッション間違い

CGI のときは suexec していたのでレポジトリが 一般ユーザ所有になってたのだが、 mod_ruby だと httpd 権限なのでロックできなくて落ちると。

これで一通り通るようになったんではなかろうか。

(22:57)

BitChannel 更新

書き忘れてたけど他にもいろいろ入れました。

  • コメントボックス追加。行頭に [[#comment]]
  • メニュー変更: Recent を後ろに
  • 文法追加: CSV なテーブル (行頭に「,」で開始)
  • 文法追加: 「-」で始まる UL
  • 文法追加: 「>」による引用 (1 レベルのみ)
  • 細かいバグをみっつばかし修正

何気にでかい変更だったりする。

一連の変更が落ち着いたらリリースしますので、 それまでは以下のあたりを参照して CVS から取ってください。

(23:02)

BitChannel更新 (2)

  • mod_ruby に対応しました。index.cgi がそのまま使えます。
  • FastCGI に対応しました。index.fcgi を使ってください。

(00:14)

netのSSL関係に関して

結論から言うとソケットを受け取るのはやりません。

まず HTTP の場合、 HTTP 1.1 ではホスト名が必要になるので意味がありません。

POP のほうは、クラスでプロトコルを分岐するのはやめたいので採用しません。 クラスで分岐する方法だとほとんどハードコーディングになってしまうんで。

あと、APOP の使えるサーバだと無差別に APOP スタンプを渡してくるので 中田さんパッチの後半はまずいです。

(00:37)

BitChannel / めも

思いついてしまったヤバ気な機能たち

更新されるそばからサーバープッシュで diff をたれながす。 Wiki における tail -f

限定 drb。 BitChannel に存在する便利そうな Ruby オブジェクトを 無造作に Marshal して返してくるサービス。 tDiary のプラグインから使ったりするといいことがあるらしい。 問題は Ruby のバージョンが違うと泣くことと、 あんまりおもしろいオブジェクトがないことか。 うーん。

(04:38)

本日のツッコミ (全6件) [ツッコミを入れる]

なかだ [そもそもAPOPってinitializeのときに分かってないとダメなもんですか。
こういうのを考えてるんですけど。
http://nokada.jin.gr.jp/ruby/pops.diff
むしろNet::Protocol(のサブクラス)はホスト名とか受け取らずに、
オープンされたIOを受け取るようにしたほうがいいんじゃないかとか。]