サブパッケージ docutils.readers

本節では Docutils のサブパッケージ docutils.readers を見ていく。このサブパッケージが提供する機能は、入力データから文書情報を読み取り、メモリ内に構文木オブジェクトを生成するクラス群ということになる。

クラス図

クラス docutils.readers.Reader を中心とした簡易クラス図を以下に示す。これまでに述べたクラスについてはグレーアウトしたり、記載そのものを省いたりしている。

classDiagram direction TB Reader --> Parser: parser Reader *-- Input: source Reader *-- document: document Component <|-- Reader Reader <|-- ReReader ReReader <|-- doctreeReader Reader <|-- standaloneReader standaloneReader <|-- pepReader Reader --> Values: settings class Component{ +str component_type$ #tuple supported$ +supports(str) bool } class Reader{ +str component_type$ +str config_section$ #str input +get_transforms() +set_parser(str) +read(Input, Parser, Values) #parse() #new_document() } class ReReader{ +get_transforms() } class doctreeReader{ #tuple supported$ +str config_section$ #parse() } class standaloneReader{ #tuple supported$ +tuple settings_spec$ +str config_section$ +get_transforms() } class pepReader{ #tuple supported$ +tuple settings_spec$ +str config_section$ +get_transforms() #parse() }

クラス Reader

クラス Reader は入力から文書テキストを読み取り、構文木オブジェクトを構築するための全てのクラスの共通スーパークラスという位置づけだ。

文書テキストから構文木オブジェクトを生成するために、クライアントは InputParser の型を両方指定する。

データ

次の二つはクラスデータだ。

component_type

スーパークラスの同名属性の上書き。値は文字列 reader で固定。

config_section

スーパークラスの同名属性の上書き。値は文字列 readers で固定。

以下はオブジェクトのメンバーデータだ。

self.parser

クラス docutils.parsers.Parser のサブクラスのオブジェクト。これが生の入力テキストデータを構文解析する。

self.source

クラス docutils.io.Input のサブクラスのオブジェクト。生のテキストデータそのものか、テキストファイルを指すか、あるいはそれ以外の何かか。

self.input

入力テキストデータ。self.source から直接得られる。

self.document

構文木オブジェクト。文字列 self.input を構文解析して得られるオブジェクト。

self.settings

何かの構成項目を表現するオブジェクトらしいが、この階層では new_document 関連でパラメーターとして振る舞う。

メソッド

かなり単純な構成になっている。

__init__(self, parser=None, parser_name=None)

オブジェクトを初期化する。

オプションとして、このタイミングで構文解析オブジェクトをセットアップできる。しない場合は別途 set_parser をクライアントが明示的に呼ぶ。

get_transforms(self)

スーパークラス Component からの上書き。さらに三種類の変換処理を増やしてある。

set_parser(self, parser_name)

この読み取りオブジェクトの管理する構文解析オブジェクトをセットアップする。

read(self, source, parser, settings)

入力から情報を読み取るメソッド。具体的には読み取りアンド解析。

  • クライアントに対する主なインターフェイスとなるメソッド。

  • 設計意図としてはこのメソッドは上書きされない。

  • 呼び出し直後に self.document の構築が完了した状態になる。

parse(self)

文字列 self.input を構文解析して構文木オブジェクト self.document を構築する。

  • 設計的にはこのメソッドは private 扱いと見える。少なくとも public のつもりではない。クライアントが Reader オブジェクトに対して parser を呼び出す意図はないだろう。

new_document(self)

クラス document のオブジェクトを生成して返す。

  • 実装は utils.new_document を呼び出すだけ。

  • メソッドの立場は、GoF デザインパターンの Factory Method パターンにおけるオブジェクト生成メソッドだろう。ただし、これを上書きするサブクラスが全くない。

サブクラス

  • クラス ReReaderget_transforms が劣化した Reader という扱い。書き出しクラス UnfilteredWriter とともに用いられることが多い。

  • クラス doctree.ReaderReReader のサブクラスだ。ここではメソッド parse を上書きして、 self.document == self.input としている。つまり構文木オブジェクトがもうあるので、二度解析しないということか。

  • クラス standalone.ReaderReader よりも変換処理が増えている。

  • クラス pep.Readerstandalone.Reader のサブクラスであるが、変換処理の一部が変更されている。

オブジェクト生成

クライアントは所望のモジュールから読み取りクラスそのものではなく、関数 docutils.readers.get_reader_classimport する。この関数に名前を渡すと、クラスが返ってくるので、呼び出し元がそこからコンストラクターを呼び出す。

この手法は Docutils で多用されている。

クライアント

モジュール docutils.core でオブジェクトの生成処理が確認できる。

def set_reader(self, reader_name, parser, parser_name):
     """Set `self.reader` by name."""
     reader_class = readers.get_reader_class(reader_name)
     self.reader = reader_class(parser, parser_name)
     self.parser = self.reader.parser

感想

ここは特に問題ない。