ネストされた構造のためのPureDocのTOC展開
有用なユーティリティコード
- TOP
- Old Archives
- ネストされた構造のためのPureDocのTOC展開
ネストTOC機能
文書からTOCを作る上で、やはり構造的にネストしたいことはあると思う。
最もポピュラーなのは、ul
をネストさせることだろう。
だが、難しいのは、例えば最初にh4
が来て、次にh2
が来て、などということがありうるのだ。そして、h3
は存在しないかもしれない。
間の全てのレベルが存在することにするのか。順に礼儀正しく登場すると仮定していいのか。
結局だが、汎用性のある仕様として次のようにした。
- 最低レベルはオフセットかまたは実際に使われた最も大きいヘッダーに基づく(数え方としてはmin)
- レベルの変遷に応じて変遷分
proc4open
やproc4close
を呼ぶ。例えば->(l, ol) { "<ul>" }
のように書く。 当該レベルまではopen/closeした後は
proc4each
を呼ぶ。def nest_expand(proc4open, proc4close, proc4each, offset=nil) result = [] mi = self.min { |i| i.level } or return nil mi = mi.level
if ! offset.respond_to?(:to_int) || offset > ( mi - 1 ) offset = mi - 1 end cur = offset self.each do |i| if i.level > cur (i.level - cur ).times {|n| result << proc4open.call( ( i.level - (i.level - cur - 1 - n) ), ( i.level - offset - (i.level - cur - 1 - n) )) } elsif i.level < cur result << (cur - i.level).times {|n| proc4close.call( (cur - n), ( cur - n - offset ) ) } end result << proc4each.call(i.level, (i.level - offset), i.title) cur = i.level end result.join
end
eRubyでは内部のメソッドがputs
すればいいような言い方をされることが多いが、それは先に出力されてしまっていたので、置換できるようにするために一旦配列に格納した。
テンプレート側の記述量が多く、また直感的でないというデメリットはあるが、なんとかうまく処理できた。
instance_evalと定数
しかし、むしろ苦戦したのは、ProfileでTOCを含めることだった。
Profileは基本的にそれ自体がPureDocを拡張したRubyコードである。
文章としてヘッダーを含めているわけでもないので、TOCを作るためのとっかかりがないのだ。
そこで結局は
- テンプレート側でテーブル手前にリンクを貼る
- profileであとから各カテゴリをヘッダとして登録する
という方法を取ったのだが、意外な理由でうまくいなかった。 というのは、
「instance_eval
で評価した場合、そのコンテキストが認識する定数にアクセスできない」
のだ。PureDocはソースをObject#instance_eval
を使って解析するため、この問題にひっかかっってヘッダーの登録ができなかった。
そこで、PureDocに登録用のメソッドを追加することとなった。
簡単に書いているが、profileは整頓されていない部分が多く、結構大変だった。