サブパッケージ docutils.transforms¶
Docutils のサブパッケージ docutils.transforms について記す。モジュールの
docstring によるとこのサブパッケージの機能は次のようなものだ。
初回構文解析の残作業を仕上げる
文書中のハイパーリンクを自動で生成する
文書データから情報を抽出し、索引や目次を生成する
クラス図¶
クラス Transformer と Transform を中心に据えた簡素なクラス図を以下に示す。ただし、本節の考察対象外のクラスは掲載を省略したり、クラスを意味する矩形を灰色に塗りつぶしたりしてある。
クラス
TransformSpecおよびComponentについては 基礎クラス群 を参照。
クラス Transform¶
スーパークラスはなく、代わりにサブクラスが多数派生しているというクラスだ。
データ¶
クラススコープのメンバーデータが一つある。
default_priority0 以上 999 以下の数値で、この変換オブジェクトの処理優先順位を表現するもの。サブクラスで上書きする。
オブジェクトデータは次の三つだ。
documentこの変換オブジェクトの対象となる構文木オブジェクト。
Transformerオブジェクトと共有。startnodeこの変換処理の開始ノード。おそらくこのノードを根に見立てた部分木の全ノードが処理対象。
構文木すべてのノードを対象とする変換もあり得る。その際は
startnode = Noneとしてもよい。language言語モジュール。詳しくは サブパッケージ docutils.languages 参照。
メソッド¶
apply(self, **kwargs)構文木を変換するためのメソッドだが、実装はサブクラス側になる。サブクラスでこのメソッドを上書きしないと
NotImplementedErrorが送出されることになる。
サブクラス¶
クラス Transform のサブクラスは多数存在し、このサブパッケージ内にあるモジュールで定義されている。
Transform
components.Filter
frontmatter.TitlePrompter
frontmatter.DocInfo
misc.CallBack
misc.ClassAttribute
misc.Transitions
parts.SectNum
parts.Contents
peps.Headers
peps.Contents
peps.TargetNotes
peps.PEPZero
references.PropagateTargets
etc.
一つ例を見よう。次のコードはモジュール docutils.transforms.peps から改変引用したものだ。サブクラス Contents は空の TOC をドキュメントの適切な位置に挿し込むような変換を施す。メソッド apply を上書きして、構文木ノードのサブクラス
title, topic, pending それぞれのオブジェクトを生成する。最後にドキュメントの然るべき場所に収める。
from docutils import nodes, languages
from docutils.transforms import Transform, parts
class Contents(Transform):
default_priority = 380
def apply(self):
language = languages.get_language(...)
name = language.labels['contents']
title = nodes.title('', name)
topic = nodes.topic('', title, classes=['contents'])
...
pending = nodes.pending(parts.Contents)
topic += pending
self.document.insert(1, topic)
self.document.note_pending(pending)
クラス Transformer¶
スーパークラスは
TransformSpec一つ。サブクラスはない。このクラスは継承を目的としていない。
クラス
documentの初期化メソッドでTransformerオブジェクトを生成して、メンバーデータself.transformerに収める。モジュール
docutils.coreのクラスPublisherにTransformerのメソッドを利用する処理例が見られる。
データ¶
メンバーデータはすべてオブジェクトの属性だ。
self.transforms次の 4-tuple アイテムを格納するリスト。
str: 優先度を示す文字列。後述のget_priority_stringの説明を参照。transform_class:Transformのサブクラスの型。node: 変換処理を施すノードオブジェクト。kwargs: メソッドtransform_class.applyのパラメーター。
self.unknown_reference_resolvers不明。調べる気がしない。
self.documentこの変換オブジェクトの対象となる構文木オブジェクト。
self.applied変換処理が済んだものを格納するリスト。アイテムの型は
self.transformsと同じ。self.sortedフラグ。メソッド
apply_transforms内でtransformsのソートが済んだかどうかをマークする。self.components辞書オブジェクト。キーはコンポーネントタイプを意味する文字列で、値は
Componentのサブクラスのオブジェクト。self.serialnoソートキーの管理用。後述の
get_priority_stringの説明を参照。
メソッド¶
add_transform(self, transform_class, priority=None, **kwargs)変換処理を一つだけ登録する。
transform_classはTransformのサブクラスを型として渡す。priorityは優先度。未指定ならばdefault_priorityが適用される。以降のメソッドでも同様。kwargsは変換メソッドapplyのパラメーター。self.transformsにデータが登録されるが、ここではソートし直さない。以降のメソッドでも同様。
add_transforms(self, transform_list)上述メソッドの複数オブジェクト版。
変換処理の優先度は各
Transformオブジェクトのdefault_priorityに基いて決まる。変換処理の対象ノードとパラメーターは両方とも空。
add_pending(self, pending, priority=None)変換保留になったノードに対する変換処理の登録という、やや複雑な手続きを行う。
pendingはノードオブジェクト。このメンバーデータのtransformが採用される。get_priority_string(self, priority)メソッド
add_xxxx系の補助メソッド。優先度のキーは次の形式の文字列である。'{priority:03d}-{serialno:03d}'
このメソッドを呼び出す度に
self.serialnoをインクリメントする。populate_from_components(self, components)詳細不明。というより見る気がしない。
apply_transforms(self)格納されている変換処理を優先順位に従い適用する。
self.transformsから変換データを順次popしてapplyしていく。変換処理が済んだら
self.appliedに変換データを移す。ループの途中で
self.transformsを再ソートすることがあるようだ。ということは、どこかのapplyが間接的にself.transformsを更新するということか。
感想¶
構文木を構成するノードを「変形」する処理のための枠組みを与える機能群ということだろう。個々のノードの属性を更新するような変形も、ノードの構成を追加したり削除したり置換したり順序を入れ替えたりする変形もあり得る。