トップ «前の日記(2017年12月19日) 最新 次の日記(2017年12月25日)» 編集

KeN's GNU/Linux Diary


2017年12月21日

_ [reviewml] Re:VIEW Hacks (3) 〜ビルダの仕組み

誰も見ていない気はしますが、自分の覚え書きでもあるので引き続き。

前回のコンパイラから実際の表現としてのビルダが呼び出されます。lib/review/なんとかbuilder.rbがそれで、現時点で存在するのは

 $ ls *builder.rb
 builder.rb      idgxmlbuilder.rb    md2inaobuilder.rb  topbuilder.rb
 epubbuilder.rb  latexbuilder.rb     rstbuilder.rb
 htmlbuilder.rb  markdownbuilder.rb  textbuilder.rb

review-epubmakerやreview-webmaker経由のときにはhtmlbuilder、review-pdfmaker経由のときにはlatexbuilder、「review-compile --target=なんとか」を使ったときには「なんとかbuilder」が使われます。

textbuilder.rbはtopbuilder.rbと同一、epubbuilder.rbはhtmlbuilder.rbと同一です。builder.rbは各ビルダの基底クラスなので、全ビルダに波及する何かを定義したり上書きしたりしたいときにはこのビルダのクラス(ReVIEW::Builderクラス)を対象にすることになるでしょう。

各クラスのメソッドはその性質上おおむね似通っており、次のようなメソッドがあります。

  • builder_init(no_error=false):ビルダオブジェクトのinitialize後呼び出される、ビルダ固有の初期化メソッド。
  • builder_init_file():コンパイラやドキュメントに束縛(ReVIEW::Builder#bind)された後に呼び出されるメソッド。コンパイラやドキュメント情報を基に初期値設定などをしたりする。
  • result():変換結果文字列の表示。@outputに変換結果の文字列がStringで格納されている。
  • ブロックタグ名(引数):Re:VIEWの//list、//imageなどに対応して「def list」「def image」といったメソッドが対応付けられて用意されている。引数はコンパイラで定義したものに依存するが、代表的なものとしてはlines(内包する行のString配列。通常はインラインタグを展開済み)、id(ID文字列)、caption(キャプション文字列)がある。ブロックタグの処理結果は、printまたはputsで書き出すようにする(※print/putsはオーバライドされており、標準出力の代わりに@output変数に追加される)。
  • inline_インラインタグ名(引数):Re:VIEWの@<b>、@<list>などに対応して「inline_b」「inline_list」といったメソッドが対応付けられて用意されている。引数はRe:VIEWの書式どおり当然ながら単一の文字列。インラインタグの処理結果はprint/putsではなくメソッドの戻り値として返す。
  • headline(level, label, caption):見出し処理。
  • nonum_begin(level, label, caption)、nonum_end(level):見出しの亜種で、「==[nonum] 〜」のようにしていたときにはこちらが使われる。nonum_endは「==[/nonum]」のように明示的に閉じられるか同レベルか上位レベルの別の見出しが登場したときに呼び出され、nonum環境の終了処理を行う。
  • notoc_begin(level, label, caption)、notoc_end(level)、nodisp_begin(level, label, caption)、nodisp_end(level):「==[notoc]」「==[nodisp]」の処理。
  • column_begin(level, label, caption)、column_end(level):コラムの処理。仕組みはnonum_beginなどと同じ。
  • ul_begin()、ul_item_begin(lines)、ul_item_end()、ul_end():●箇条書きの処理。ul_begin、ul_endが全体を囲む定義、ul_item_beginとul_item_endが各箇条書きを囲む定義となる。
  • ol_begin()、ol_item(lines, num)、ol_end():番号箇条書きの処理。
  • dl_begin()、dt(line)、dd(lines)、dl_end():説明付き箇条書きの処理。
  • paragraph(lines):段落の処理。
  • image_image(id, caption, metric), image_header(id, caption):実際に画像ファイルがあるときの図版処理。キャプション処理はimage_headerメソッドで定義する。
  • image_dummy(id, caption, metric):画像ファイルが見つからなかったときの代替処理。
  • image_ext():あまりちゃんと使っている気がしないが、ビルダ内での画像ファイル拡張子のデフォルト。
  • extname():変換結果の推奨拡張子。

初期設定系の定義をbuilder_initかbuilder_init_fileのどちらに追加するかですが、通常は後者のbuilder_init_fileのほうでよいでしょう。

束縛が行われた後であるbuilder_init_file()ほか各タグ処理メソッドでは、コンパイラオブジェクトや現在の処理ドキュメントのオブジェクトを参照して利用できます。

  • @compiler:コンパイラオブジェクト。
  • @chapter:現在処理中の章を表すChapterオブジェクト。
  • @book:Re:VIEWの設定やブック情報であるBookのオブジェクト。たとえば@book.config HashオブジェクトでYAML設定の内容の参照や設定ができる。

最後にビルダ挙動を変更する例として、LaTeXビルダで@<b>を\textbf(太字にする命令で、ゴシックにするわけではない)の代わりにゴシック体+太字にする例を示します。

 module ReVIEW
   module LATEXBuilderOverride
     def inline_b(str)
       "{\\sffamily\\bfseries\\gtfamily #{escape(str)}}"
     end
   end

   class LATEXBuilder
     prepend LATEXBuilderOverride
   end
 end

実際はこのままだとコード内でbを使ったときにはttfamilyにすべきで困るため、レイアウトsty側で定義したほうがよいのですが、カスタマイズの一例とお考えください。

前回、インラインタグはブロックタグに渡される前に展開されていると述べたとおり、今はinline_bの中で「コードブロック内かどうか」を判断する術がありません。PR#858を入れると@doc_statusから拾えるようになりますが、負債にもなりかねないので、このパッチはもうちょっと精査したほうがよいのかもしれません。

あとはBookやIndexについて説明が必要ですが、今日はこのへんで。