そこらじゅうからコードをかき集めてきた甲斐あって、 もうそろそろウェブから見られそうな感じ。
いや表示は別にいいんだ。表示は今回簡単だから。 問題はこの複雑怪奇なオブジェクトグラフの永続化と インクリメンタルアップデートだ。 自分でも何がどこを参照してるのかわからなくなってきたし。
やっぱり、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