バカ逝くで出てきた、sh の「:」(ヌルコマンド) について。 ああ、そんなのあったなあと思いつつも、 何に使うのか思い出せなかったので、調べました。 『入門UNIXシェルプログラミング』で。 これはまじでいい本です。
この本には次のような使い道が書いてあった。
ところで、Linux だと /bin/sh がフツー bash なのでわりとなんでも通っちゃうけど、 商用 UNIX をさわってみると制限ありまくりで泣けるよね。 そのてん『入門 UNIX シェルプログラミング』 は各種商用 UNIX でもちゃんと通じる書きかたが書いてあるので非常に助かりました。 なにしろ原題は "Portable Shell Programming" だし。
(05:26)
Ruby リファレンスマニュアル刷新計画は 元々 ruby-reference-manual ML でやってることなので、 参加したい人はまずそっちに入っといてください。 この日記にも進捗は書きますけど、あくまで ML がメインなので。
参加方法
To: ruby-reference-manual@ml.fdiary.net Cc: aamine@loveruby.net Subject: 参加希望
で、本文には
を書いてください。ML のログはこちら。
http://www.fdiary.net/ml/ruby-reference-manual/
(21:16)
『GNU 開発ツール』届く。
うわ、これは……装丁がカッコイイ! でもこれは卑怯でしょ。 タイトルが日本語なら表紙にも日本語で書けえええ!
しかも紙が厚いし二色刷り。金かかりそー! でもフォントは明朝のがよかったなあ。
(21:23)
開発環境カンファレンスで発表してきました。 聞いてくださったみなさん、ありがとうございました。
他の人達がすげーまっとうにツールとかの紹介をしてたのに対して、 わたしは old type バリバリのプレゼンをやってきました。
PowerPoint のファイルもあげときますが、 台本のほうが本文があって読みやすいと思うので、 そちらを以下にダラダラとつなげます。
こんにちは、日本 Ruby の会の青木と言います。 今日は「オレポータビリティ」というテーマで 開発環境について話したいと思います。
自己紹介
まず簡単に自己紹介をしておきます。
自己紹介 (1) * 学生 * 専門は……哲学?
ふだんは大学生をやっております。 専門は強いて言うと哲学で、 プログラムは全然関係ありません。
ということは、
開発と言えば自宅
わたしにとって開発と言えば自宅でやるものです。
自己紹介 (2) * Ruby 関係者 * 標準添付ライブラリ メンテナ * 著書いろいろ
それから、普段は Ruby 方面で活動しています。 標準添付ライブラリをいくつか自分で書いて メンテしていますし、レポジトリのコミット権も持ってます。 その他にアプリケーション、ライブラリもいろいろと書きました。
それから本もいろいろ書きました。 具体的には、
著作 『ふつうのHaskellプログラミング』 『ふつうのLinuxプログラミング』 『Javaを独習する前に読む本』 『Rubyレシピブック』 『Rubyソースコード完全解説』 『Rubyを256倍使うための本 無道編』
ふつうのHaskellプログラミング や、 ふつうのLinuxプログラミング などです。
で、まあ、なにぶん Ruby 関係者ですので、
言語は ほぼ確実に RubyかC
プログラミングするときはほぼすべて Ruby か C です。
本当は Ruby だけいじって済ませたいんですが、 人が調子よくコマンドラインをたたいてるときに限って、
./lib/bitchannel/syntax.rb:398: [BUG] Segmentation Fault ruby 1.9.0 (2005-10-22) [x86_64-linux]
「……あれっ?」 なんてことが、起きるわけです。 こういうときはしょうがないので C プログラマになって ruby 本体をいじります。
さて、今日は開発環境カンファレンスってことですが、 開発環境ってのもけっこう曖昧な言葉ですよね。 依頼されたときに何をしゃべろうか迷いました。
そこで、わたしはこの「環境」という単語を できるだけ広くとらえることにしました。
部屋
まず部屋。 これは当然開発環境でしょうね。
ハードウェア
それからハードウェア。
ソフトウェア
最後にソフトウェア。
この部屋、ハードウェア、ソフトウェアを 全部ひっくるめて開発環境と考えて、 この順番で話していきたいと思います。
そこで まず わたしの部屋から始めたいと思います。
こんな感じです。
わたしには 「ヒューマンインターフェイスには金をかける」 という信条があるので、 モニタと椅子だけは高いのを使ってます。
もっとも、そんなこと言いながらマウスは 1500 円です。
(あとで高林さん (だったかな) から質問があったので追記: 椅子はコンテッサ。ついでにモニタは EIZO FlexScan L665)
ちなみに後ろはこんな感じで、
本棚で埋めつくされてます。
で、またデスクトップに戻ります。
キーボードをよく見てもらうと、 これ、右側が切断されてます。
テンキーなんてぜんぜん使わないくせに 場所を食って邪魔だったので、 のこぎりで切り落としてしまいました。 こうするとナチュラルキーボードも コンパクトになって便利です。
ところで、さきほどの写真では机の右側のほうを わざと写さなかったんですが、 ここに何があるかと言うと……
こういうものがあります。 これ全部コンピュータです。 写真に映っていないものも含めて すべて合わせると 20 台くらいあります。
しかもこれ、普通のパソコンばっかりじゃありません。 中には Alpha とか SPARC とか POWER が混じってます。 具体的には、
5 つのアーキテクチャ x86, AMD64, Alpha, SPARC, POWER
アーキテクチャ 5 つ
7 つの OS Linux, FreeBSD, NetBSD, Windows, Solaris, Tru64UNIX, AIX
オペレーティングシステムが 7 つ。 組み合わせだと、
9 つのプラットフォーム Linux/x86 Linux/AMD64 Linux/Alpha FreeBSD/Alpha NetBSD/Alpha Tru64UNIX/Alpha Solaris/SPARC AIX/POWER Windows/x86
9 つのプラットフォームがあります。
(注釈: 実は、 Development Environment Conference なので、DEC つながりで AlphaStation 500 の実物を持ってくる予定だった。 しかし出発の 30 分前に挫折)
「こんなに たくさんあって どうすんの?」
さて、マシンが 20 台くらいあるぜー、 と言うと、たいてい 「こんなにたくさんあって何に使うんだ」 と聞かれるんですけど、 主な役割は
愛でるため
愛でることです! なでて、
紺匡体 萌え〜
紺匡体萌えー と叫ぶためにあるんです。
まあ、そんなわけで、 マシンたちは なでるためにあるんですが、 せっかくマシンがたくさんあるわけですから、
ついでに Ruby のテストも している
ついでに Ruby のテストもしているわけです。
ようやく今日のテーマにたどりつきました。
前提: マシン台数も プラットフォームも 多すぎる
わたしの開発環境は アーキテクチャも OS も多すぎます。 そのような状況だからこそ、
オレポータビリティ
今日のテーマである 「俺 - portability」の話になるのです。 この オレ ポータビリティ というのは、
俺 (の) portability
……の、ことです。 つまり、自分自身の portability のことです。 「ポータブルなプログラム」と言えば いろいろな環境において 動作するプログラムのことですね。 「俺がポータブルである」というのは、 いろいろな環境でも同じように開発できる、 ということです。
どんな環境でも 同じように開発できる → オレポータビリティが高い!
今日はオレポータビリティを高める 戦略について話そうと思います。
オレポータビリティを高める戦略、その 1 は、 どうしてもこれでなきゃだめ、 ないと死んじゃう、 というソフトウェアを減らすことです。
なぜかと言えば、
どこでも使える ソフトウェアが そもそも少ない
プラットフォームの種類が多い場合、 どこでも動くソフトウェアは限られます。 例えば IDE なんて絶望的です。
たくさんソフトウェアを 使うとインストールがめんどくさい
しかも、たくさんインストールしないといけないと インストールだけでバカみたいに手間がかかります。 パッケージシステムがどこにでもあるわけでは ないですから。
実例を見てみます。 例えばこれはメインマシンのデスクトップです。
old type な人にありがちな、 味も素気もないデスクトップですね。 端末を 2 枚ひらいて、 右の端末でコード書いて、 左の端末でコマンドを打ちます。
このキャプチャに映ってる端末は rxvt なんですが、 別に rxvt でなければまずいわけではありません。 ちゃんと使えれば何でも使います。
ウィンドウマネージャは sawfish ですが、 これもやっぱりこだわってません。 単に Debian デフォルトだったから使ってるだけです。 だいたい何を使ってもそのうち慣れます。
画面は Linux ですが、別に Windows でもいいんです。 実際、このノートパソコンには Windows XP が入ってます。 Linux についても、 GNOME や KDE を使おうが使うまいがどっちでもいいんです。 どっちを使ってようと慣れれば大丈夫です。
で、端末やウィンドウマネージャは何でもいいとして、 必ずこれを使う、というものもあるわけです。 必ず使うのはこういうプログラムです。
必ず使うソフトウェア * Ruby * C コンパイラなど * zsh * CVS or Subversion * vi * 独自の開発ツール
順番に詳しく見ていきます。
使うプラグラム (1) Ruby 開発版 + 安定版ぜんぶ
まず当然 Ruby。 Ruby プログラムを書くのに Ruby がないと話になりません。
わたしは Ruby は開発版の最新を使うことに しているので、OS をインストールしたら まず CVS trunk HEAD を自分でコンパイルします。
さらに、安定版をねこそぎ入れます。 いまは 1.8 系列が安定版なので、 1.8.0 から 1.8.5 まで全部入れるわけです。 これは動作の検証用です。
ただ、たくさんあると各バージョンで 比較するのも面倒なので、
forall-rubyコマンド 横断テストの自動化
forall-ruby コマンドという自作コマンドを使います。 このコマンドは、システムにあるすべての ruby に 対して同じオプションをつけて実行するコマンドです。
例えば次のコマンドを実行すると、
~ % forall-ruby -e 'p Object.superclass' aamine@core ruby 1.8.2 (2004-12-25) [i386-cygwin] nil ruby 1.8.3 (2005-09-21) [i386-cygwin] nil ruby 1.8.4 (2005-12-24) [i386-cygwin] nil ruby 1.8.5 (2006-08-25) [i386-cygwin] nil ruby 1.9.0 (2006-08-23) [i386-cygwin] BasicObject
ああ Ruby 1.9 では Object の上に BasicObject てのが 追加されたんだなあとわかります。
使うもの (2) C コンパイラなど gcc, bison, flex, autoconf, make, ...
次に C コンパイラとか autoconf。 こいつらは Ruby をコンパイルするのに 必要なので否応なく入れます。
使うもの (3) zsh
それから zsh です。実は zsh は インストールするのが結構大変なんですが、 もう bash では生きていけない身体に なってしまったので やむなく使います。
使うもの (4) vi
それから vi。 UNIX 系の OS ならフツー入ってるので楽です。 Windows でも Cygwin を入れればついてきますし。
また、これは vim とかではなく vi であるところも重要です。 わたしはシンタックスハイライティングだとか オートコンプリートだのは 一切使わないことにしているので、 素の vi で大丈夫です。
ちなみに、素の vi はマルチバッファではないので 複数ファイルが編集できません。 そこで、複数ファイルをいじるときは シェルのジョブ制御機能を使います。
複数ファイルを編集するときは シェルのジョブ制御を使う Ctrl-z でサスペンド、 fg コマンドで復帰
もはやジョブ制御なんて知らない人もいそうですが、 こういう機能もあるんです。
使うもの (5) バージョン管理システム (CVS か Subversion)
それからバージョン管理システム。 種類はなんでもいいんですが、 わたしは CVS をメインに使ってます。
※ 追記: id:naoya さんの発表によれば CVS を使っていいのは小学生までらしい。
使うもの (6) 独自の開発ツール * ReFe * rdefs
その他、いくつか自作のツールがあります。 Ruby に特化していますが、 アイデア自体は他の言語でも変わらないでしょう。
具体的に見ますと、
ReFe Rubyのリファレンスマニュアルを 検索するツール
まず ReFe というツールです。 これは Ruby のリファレンスマニュアルを検索するツールです。
例えば String クラスの each_with_index メソッドを調べたい! というときには
~ % refe string each_with_index aamine@core String < Enumerable#each_with_index --- each_with_index {|item,index| ... } 要素とインデックスを両方与えるイテレータ。 self を返します。
と指定すればいいわけです。
ちなみに、この場合は each_with_index メソッドは Enumerable モジュールから継承したメソッドなんですが、 そういうメソッドもちゃんと検索できます。
rdefsコマンド 定義されてるクラスとメソッドをリスト
それから rdefs コマンド。 これは、ファイルに定義されてる クラスとかメソッドをリストするコマンドです。
例えばこの locale.rb というファイルに どんなメソッドが定義されてるかなーと思ったら、
~ % rdefs locale.rb module BitChannel class Locale def Locale.declare_locale(key, loc) def Locale.get(key) def Locale.key?(key) def Locale.keys def initialize def rc_table private :rc_table def [](key) alias text [] def []=(key, str) def inspect
と、いうふうに調べればいいわけです。
独自ツールのポイント * Ruby だけを使って書く * インストーラを付ける
まずツールはポータビリティを考えて すべて pure Ruby で書きます。 例えば、なぜかツールを Python で書いちゃったりしたら また Python 入れなきゃいけませんから、 とうぜんここは Ruby を使うわけです。
それからインストーラを付けること。 マシンが 20 台あるってことは、 OS のインストールも最低 20 回やるわけです。 それだけあると、ツールにもインストーラが ついていたほうが楽です。
オレポータビリティを高める戦略の 2 つめは、 ソフトウェアをカスタマイズしないことです。
なにしろマシンが 20 台からあるので、
いちいち カスタマイズ してられるか!
いちいちカスタマイズするのも面倒です。 じゃあ設定を共有するか、とか言い出すと、 今度はそっちのインフラ整備が面倒です。
ということで、ソフトウェアを細かく カスタマイズするのをあきらめます。
これも、本当にまったく カスタマイズしないわけではなくて、 「できるだけ」カスタマイズしないということです。 さすがにわたしも zsh はちょっといじりたいですし。
これを逆に言うと、
カスタマイズしなくても 使う気になるソフトだけ使う!
カスタマイズしなくても使う気になる ソフトウェアだけ使うということです。 「〜〜をインストールして設定すれば使える」 なんてのは使えないのと同じだと思いましょう。
英語で言うと、
No configuration is good configuration.
No configuration is good configuration です。 設定しないで使えるのが一番いいってことですね。
さらに日本語で言い直すなら、
ノウハウを作らないのがノウハウ
ノウハウを作らないのがノウハウです。
オレポータビリティを高める戦略の 3 つめは、 すべてのマシンでホームディレクトリの構造を統一することです。 これはまあ、あたりまえと言えばあたりまえでしょう。
各種設定を減らすためにも 共通化が重要
ホームディレクトリの構造が同じなら、 その構造を前提にしてツールが書けます。 そうすると設定が減って楽になると。
また英語で言うと、
Convention over configuration.
Convention over configuration、ということです。 日本語で言うなら「慣習じゅーよー」。
具体的にどういう構造にするかはいろいろあると思いますが、 わたしは UNIX の /usr 以下と同じ構造にしています。
UNIX の /usr 以下を真似 bin, etc, lib, share, src, var
ちなみに、src はもちろんソースコードですが、 ここには自分が作ったもの以外をまとめます。 で、
自分で作ったものは ~/c に置く
自分で作ったものは すべて ~/c に置きます。 ソースコードもツールも、すべてです。
オレポータビリティを高める戦略その 4 は、 徹底的にバージョン管理システムを使うことです。
共有するため
バージョン管理システムを使う目的は、 この場合、マシン間でファイルを共有することです。
~/c 以下は例外なく バージョン管理システムに入れる
~/c 以下、つまり自分で作ったものは すべてバージョン管理システムで管理します。 具体的には、
ソースコード
プログラムのソースコードやドキュメント。
開発ツール
さっき言ったような、独自の開発ツール。
大学のレポート
それに大学のレポートもですね。
とにかく自分が作ったものはすべてここに入れて、 バージョン管理システムで管理します。
ちなみに C は working Copy の C から取りました。
では、まとめます。 オレポータビリティを高めるための 戦略は 4 つありました。
戦略 (1) 必須ソフトウェアを限界まで削る
一つめは、「これがないと死んじゃう」 ソフトウェアを限界まで減らすことです。 これによってインストールする手間を 減らすと同時に、ポータビリティを高めます。
戦略 (2) カスタマイズしない
二つめは、ソフトウェアのカスタマイズを 半ばあきらめることです。 デフォルト設定が優秀なソフトだけ使いましょう。 No configuration is good configuration.
戦略 (3) ホームディレクトリの共通化
三つめはホームディレクトリの構造を 共通化することです。 Convention over configuration.
戦略 (4) 徹底的にバージョン管理
四つめは、バージョン管理システムを 徹底的に使うことです。 バージョン管理システムを使うことで ファイルの共有も実現できます。
結論: あたりまえのことを 徹底的にやるのが ポイント
今日の話は、どれも けっこう あたりまえのことが多かったと思います。 バージョン管理するというのも、 ホームディレクトリを同じにするというのも、 まあ普通ですよね。 でも、それを徹底活用すると、 マシンが 20 台あっても OS が 7 種類あっても 生きていけるようになるわけです。 これが今日のポイントです。
以上でわたしの発表は終わりです。 ご静聴ありがとうございました。
(16:45)
と、いうことで、いまさら DECon の感想を書く。
自分のセッションが最後だったので 「ぐはー緊張する死ぬもうだめぽ」 などと思いながら聞くのがきつかった。
一番印象深いのは……なんだろ。 今回はさすがにどれもうまくて没頭できたので、 印象も分散した感じ。
強いて言うと高林さんの Binary 2.0 話かな。 GDB でバイナリパッチを当てる話がおもしろかった。 でも「過去の経験から memcpy と memmove を間違えていると思われる」 って、そんなんソースコード見ないでわかるわけねー! (笑)
ちなみに小ネタ: objdump の出力が「memcpy@plt」となっていたと思うが、 その plt は Proceduce Linkage Table の略である。たしか。 i386/Linux では共有ライブラリの関数は 間接アクセスするようになってるんだけど、 その間接アクセスに使うテーブルが PLT。
しかし、前から思ってたんだけど、 strace は Binary 2.0 なんだろうか。 あれは /proc 見たり ptrace(2) 使ったりする話だから、 OS の話であって、バイナリとは関係なくない? いやまあ Binary 2.0って何だって言われると困るんだけど。
ここで話が突然変わるが、CVS は小学生までだ! しかし俺は小学生だから問題ない! (嘘つけ)
secondlife さんの vim 話は興味深かった。 俺は普段から vim 使ってるけど vi の範囲しか使わないので、 vim 特有のことはほとんど知らないんだよな。
そうだ、自分の話で一個書き忘れた。 「アプリケーションごとの設定方法を覚えるのがめんどくさい」 という理由を追加すべきだった。 どれくらいめんどくさがってるかと言えば、 人の考えた設定方法を覚えるくらいなら 自分でプログラム書いたほうが楽、というくらい。
はてなの開発環境はなかなかカッコイイ。 全員がノートパソコンだけど机に座ってるときはデュアルモニタにする、 というあたりが特にいいな。なんか軽快な感じがするよね。 俺も部屋の写真を入れたけど、 やっぱ部屋の写真があると見てるだけで楽しい。
宮川さんの飛行機ハック話。国際派でカッコイイ。 窓使いの憂鬱はわたしも使ってます。 日本語キーボードで英語配列にするとキーが増えて便利なんだよね (secondlife さんも同じことをやってて驚いた)。 わたしは「}」のキーを「|」、「半角」を ESC、「|」を「~/`」にしてます。 Linux でも同様に loadkeys/xmodmap で変換する (他のシステムにはシリアルか ssh で入るので変換の必要なし、 どうしょもないときは 101 キーボードをつなぐ)。
mala さんの話は、 ターンアラウンドを極限まで短くするという話が印象的。 とにかく試行回数を増やせればバグは潰せる、 試行回数を増やすほどバグは減る、 という話だったような気がする。 実に LLっぽい。
(08:35)
DECon のプレゼン作るために中断してたけど、 そろそろリファレンスマニュアルをやりますよ。
ところでなぜ締め切りが 20 日かと言うと、 21 日から 30 日まで俺が東京にいないからである。 だから 20 日までに俺の担当部分 (ウェブアプリ部分) は作ってしまう必要がある。 逆に言うと、その他の作業は 21 日以降でも大丈夫なのね。 ……いや、まあ、司令塔なしで作業してもらうというのもまた酷い話だけど。
(08:47)
えーと、いままでに出た案は
か。うーむ。
……という意味で 「すごいマニュアル」というのはどうかなッ! (なにがだ)
さらに略すと「凄マニュ」か。 どことなくサンスクリット語ぽい語感だな。
まだ続くよ
(09:26)
ずーっと昔から考えてたことで、 いまさら言い出せないよなーと思って避けてたんだけど、 str.sub(/re/, '') と同じ働きをする str.remove(/re/) って欲しくない?
(00:38)
■ ささだ [ふつうのマニュアルなんてどうか.]
■
yoosee [るファレンスマニュアル。さらに略してルファ。
小学生がワンピースと間違えて買うに違いない。]
■ shinh [はじめてコメントします。String#remove欲しいと思います。ついはじめてコメントするくらい欲しいです。]
■ shinh [全然はじめてじゃなかったようでした。はじめてじゃないのはじめてだと思うほど欲しいです。]
■
斎藤ただし [はじめまして。望ましいインターフェースってなんだろうとは自分も常々考えさせられる問題で、思わずコメントしたくなってしまいました。
String#delete!の引数にRegexpを許す方が保守的でいいんじゃないでしょうか。]
えーっと何をしなきゃいけないんだっけ。
とりあえずは俺以外でも作業できる環境を作らないとだめだな。 ということは、まず、
あたりか。
簡単なところで、割り当てリストから。 Subversion のレポジトリに ASSIGN てファイルを作っておいて、 アカウント名を書き込んでチェックインしたら OK ということにしよう。 えーと、*.rd と *.off を拡張子とってリストすれば終わりと。
次。依存関係を考えると、ツールかな。 パーサはだいたいできてるから、リストするツールを書けばいいだろう。
うむ。こんなとこか。 bc-list はパースして pp するだけという手抜き実装だ。 bc-convert は ReFe のコードを持ってきてでっちあげた。
それからサンプルファイル。 Object, String, Enumerable, Comparable があればよかろう。 あと組み込み定数と組み込み関数は記法が特殊なので俺が引き取るっと。 メソッドを置き換えるライブラリも一つ欲しいな。jcode にしよう。
最後に作業マニュアル。 ざっと書いてメール → 完。
(10:56)
もう Symbol が String に統合されるのは規定事項なのだろうか……。 やっぱ別物のほうがいいなあ。 Symbol を String のように扱いたい、というのはわかるけど、 それと継承関係を作ることは別の話だと思うんだよな。 どうせ破壊的メソッドは実装できないんだし、 いくつかメソッドを追加するだけで済ますわけにはいかないのだろうか。
やはりもう一発メールを投げてみよう。
(11:18)
ああ、そうか、ActiveSupport の件は Hash で同一視したいって話なのか。 ますます ActiveSupport が嫌いになってきた。
(11:27)
シェルスクリプトのユニットテストを書く必要が発生した。 …… shunitってあるのかな。ありそうだな。あるらしい。
うーむ。CVS HEAD 見てみたが、イマイチ好きになれない。特に関数名が。 これ使うなら「ふつりな」のときに自分で作ったやつのほうがいいや。 こんなやつ。
#!/bin/sh . ./shunit.sh assert_ok() { assert_stdout "OK" $1 assert_status 0 $1 } assert_out() { assert_stdout "$1" $2 assert_status 0 $2 } assert_out "Hello, World!" ./hello assert_out "Hello, World!" ./hello2 assert_status 77 ./add assert_out "ret=77" ./add2 assert_out "ret=77" ./sub assert_out "ret=56" ./imul assert_out "ret=2000" ./idiv assert_out "i=0; i=1" ./lvar1 assert_ok ./if assert_ok ./while1 assert_ok ./while2 assert_out "i=3; i=3; i=2; i=1; i=0" ./while3 assert_ok ./while-break assert_ok ./while-continue assert_out "i=3; i=2; i=1; i=0" ./for assert_ok ./for-break assert_ok ./for-continue assert_ok ./immscope test_finished
(13:25)
ちなみに、こんなハッシュを作って演算子をメソッド名に変換してた。
OP = { '+' => 'add', '-' => 'sub', '*' => 'mul', '/' => 'div', '%' => 'mod', '&' => 'bitand', '|' => 'bitor', '^' => 'bitxor', '<<' => 'lshift', '>>' => 'rshift', '==' => 'eq', '!=' => 'neq', '>' => 'gt', '<' => 'lt', '>=' => 'gteq', '<=' => 'lteq', '&&' => 'logicaland', '||' => 'logicalor' }
ハッシュ側のキーは文字列なんだけど、 検索するときは intern してあった罠。 世の中ままならねーんですよ。
(16:39)
そこらじゅうからコードをかき集めてきた甲斐あって、 もうそろそろウェブから見られそうな感じ。
いや表示は別にいいんだ。表示は今回簡単だから。 問題はこの複雑怪奇なオブジェクトグラフの永続化と インクリメンタルアップデートだ。 自分でも何がどこを参照してるのかわからなくなってきたし。
やっぱり、alias もさることながら、 メソッドの再定義と上書きがうぜー。 クラス名とメソッド名をキーにして完全一致検索しても まだエントリが複数あるというのが激しくウザい。
(18:23)
さてデータベース。こっからが問題だ。
ライブラリは特に問題ない。 ライブラリで定義されたクラスとメソッドのリストを持つ。 メソッドの追加や再定義に対応できるよう、 クラスの他にメソッドも持つのがポイント。
data Library = Library { name :: String, source :: String, classes :: [Class], methods :: [Entry] }
クラスにはまず constant と singleton method と instance method があり、 それぞれにエントリベースのリストと名前ベースのリストがある。
data Class = Class { name :: String, source :: String, constant :: NameSpace, singleton :: NameSpace, instance :: NameSpace } data NameSpace = NameSpace { map :: Map String MethodHolder, list :: [Entry] }
MethodHolder は「定義された Entry」「追加 Entry」「再定義 Entry」を持つ。
data NamedEntry = NamedEntry { defined :: Entry, added :: [Entry], redefined :: [Entry] }
で、最後にメソッドエントリは
class Entry def signatures :: [Signature] def source
いきなり Ruby に戻る罠。 だって抽象データにしたかったんだもん。
このように分析してみると、 Entry のアイデンティティが問題のような気がする。 Entry だけはライブラリとクラスから多重に参照されるうえ、 クラス名とメソッド名だけではユニークにならない。
解としてはライブラリ名も付ければよい。 一つのライブラリで一つのメソッドに 複数のドキュメントを提供することはさすがにないだろう。 ……ないよな?!
てな感じか。 どことなく selector namespace ぽい。
データベースはインクリメンタルに更新できるよう、 すべて遅延ロードする。
db/1.9.0/ properties library/ _builtin/ source classes methods Env/ English/ abbrev/ : : class/ ARGF/ source constant/ map/ list singleton/ map/ file filename lineno path skip to_s list instance/ map/ list ArgumentError/ Array/ Bitnum/ Binding/ : : method/ _builtin.String.new _builtin.String-captalize _builtin.String-captalize! _builtin.String-casecmp _builtin.String-center _builtin.String-chomp _builtin.String-chomp! _builtin.String-chop _builtin.String-chop! _builtin.String-clear : :
method 以下は ライブラリ名で一回切ってもいいな。 何エントリあるのか調べてから考えよう。
case 無視のファイルシステムはあとで考える。 必要なら ReFe と同じ方法を使うと。
(19:04)
よく考えると、メソッドエントリに種類が入ってるから、 クラスが持つメソッドのリストは種類に分ける必要ないな。
String/ properties source entries singleton/ instance/ contant/
さらに、list だけセーブして、ロードしたあとに Hash 作れば十分か。 これが本当に同じなら、だけど。
String/ properties source entries
おお! めっちゃシンプルになった。
(19:43)
クラスが持つエントリの種類を整理しよう。
……そうか。 これまでこの属性はクラスになければいけないような気がしていたけど、 メソッドエントリの属性にしてしまえばいいんじゃないか。 defined/added/redefined の区別はドキュメントに書いてあるんだから、 これをそのまま保存しておけば十分だ。
(21:54)
そうか。メソッドにライブラリが関係してくるのは クラスと別のライブラリで定義されたときだけだ。 んで、ライブラリ主導で検索するときは C.m で検索してから ライブラリ名でフィルタすればいいんだ。 ということは、やっぱりメソッドの ID は C.m で十分だ。
ということは、メソッドエントリは defined + added + redefined で 1 つか。
……ちょっと待てよ。 alias があるメソッドの片方だけを redefine したらどうなるんだ。
?
ええ? どうなんのこれ? ていうか、どうなるのが正しいんだよ。
ユースケースから考えよう。
ライブラリ主導の場合は、redefined エントリだけ。
クラス主導の場合は、defined + redefined。
メソッド名による検索の場合は、defined + redefined。
ライブラリのときは名前で検索したあと ライブラリでフィルタするから自動的に redefined だけになる。
よし、問題ない。たぶん。 メソッドの extent をロードしない限り変なことにはならないはず……。 ヤバいのはメソッドが減ったり増えたりする場合のクラス書き込みだけど、 これはあとで考えよう。
(01:12)
■ ドし [Ruby is teh suck!!!!!!11]
げっ、明日か! すっかり存在を忘れてた。どうしよう。 いまコード書きが調子いいから、 勢いで終わらせてしまいたいのだが……。
読書会に出て現場でコード書こうかな……。
(14:44)
サブタイは気分によって毎回変わります。
もういっかいデータベースの物理構造をまとめてみよう。 まとめ、大切。
db/1.9.0/ properties libraries/ _builtin/ properties source classes methods abbrev/ base64/ benchmark/ bigdecimal/ classes/ ARGF/ properties source methods/ file/ s._builtin filename/ lineno/ path/ skip/ to_s/ Abbrev/ ArgumentError/ Array/ BasicSocket/ BigDecimal/
これまでの考察を経て、method/ が消滅。 メソッドの位置は CLASSNAME/methods/METHODNAME/TYPECHAR.LIBRARYNAME に変えた。 TYPECHAR は singleton_method とか instance_method の種別を表すアルファベット 1 文字。
ライブラリからメソッドを得るときは CLASSNAME + METHODNAME で検索してから LIBRARYNAME でフィルタする。
あらためて考えると、TYPE と LIBRARYNAME の扱いが肝だな。 だいたいアレだ、module function がすべて悪い。 こんなものがあるから、 ドキュメントの実体をコピーしないで済ますには TYPE を最後にせざるをえなかったのだ。
(15:54)
まとめ、大切。
とか言いつつ実装の間際になって構造を変えてしまった。 なんだかんだで最初の形に近くなったな。
db/1.9.0/ properties library/LIBRARYID/ properties source classes methods class/CLASSID/ properties source method/CLASSID/TYPECHAR.METHODNAME.LIBRARYID/ properties source
こんな感じ。
(00:25)
この構造なら、 properties と source を融合しちゃえば クラスとメソッドにはディレクトリ作らなくても済むなあ。 ディレクトリ作りまくると実容量を食うし、 ディレクトリ数を減らすに越したことはない。
それはそれとして、 調子に乗っていま変換が済んでるぶんを全部つっこんだら、 何事もなく処理できてしまった。 いつもならここで何か起きそうなもんだけど。
(00:37)
~/c/rubydoc/refm/api % bitclust -d var/1.9.0 update --stdlibtree=src zsh: 25993 segmentation fault (core dumped) bitclust -d var/1.9.0 update --stdlibtree=src
なんか凄いのキトゥワァー!
(23:44)
FastCGI 化しよう。
と言ってもコードは最初から FastCGI をサポートするつもりで書いてるから、 ファイルを .cgi から .fcgi にリネームして .htaccess を書き換えるだけでいいはずだ。
あれ?
おや?
ああそうか lib/fcgi.rb をまだ置いてなかった。 FastCGI での動作を確認。
メモリ使用量はどうかな。 えーと、だいたい 20MB くらいか。これなら問題ないな。
(21:43)
ぐはー。メソッド名は URL エンコードじゃだめだー。 '/' が恐ろしいことになる。代わりに '=' を使うことにしよう。 これはこれで、GET リクエストがすごいめんどいことになるわけだが、 今回は全面的に PATH_INFO でいくことにしているのでたぶん問題ない。 つまり
.../method/Bignum/i/=2f
と、いうことだな。
そういえば URL に Ruby のバージョンが入ってないなあ。 refm の代わりに 1.9.0 とか 1.8.6 を使うべきか。
クラス名のエイリアスのことは考えてなかったあああああ!
くそう。クラスにも names を用意しないとだめか。 検索がまた面倒なことになるなあ。
そうか、もしかしてライブラリにも alias が必要なのかな。 必要かな。必要そうな気がするね。うげー。
ようするに、ライブラリ・クラス・メソッドのすべてで principal name と aliases を区別しないとだめなんだな。 別名を記述する文法も必要か。 ますますもって最低だ。
(00:56)
Copyright (c) 2002-2007 青木峰郎 / Minero Aoki. All rights reserved.
■ ひら [キーボードがSK6000だ!使ってました(^-^)
10年くらい前の名作キーボードだね。]
■ 青木 [え、このキーボードって有名なんですか。
ロゴも入ってないし、確か 7000 円くらいで、
ナチュラルキーボードのくせに安いなあ〜
っていう印象しかなかったです……。
秋葉原の俺コンスポットで買った記憶があります。
タッチパッドのついてるのとついてないのがあった。]