基礎クラス群¶
ここでは Docutils の様々なテキスト処理クラス群のスーパークラスとして存在する
TransformSpec, SettingsSpec, Component を見ていく。以下、この 3 クラスを基礎クラスと呼ぶことにする。本節の目的は、これらの基礎クラスがどのような機能を Docutils 内のサブクラスやクライアントに提供しているのかを調査し、いずれ私が類似のプログラムを書くときに参考にすることだ。
クラス図¶
本節で登場するクラスを図に示す。
クラス docutils.SettingsSpec¶
このクラスは実行時に何かの構成・設定値を指定するための枠組みを決める。Docutils のための設定ファイルやコマンドラインオプションから値を受け取り、オブジェクトにそれをセットするという、一連のデータの流れを支える。
SettingsSpecにはスーパークラスがない。
メンバー¶
メンバーの種類はクラスデータしかない。
SettingsSpec.settings_spec = ()コマンドラインオプションの定義。次に示すような複雑なデータ構造体の
tupleだ。(option-group-title, description, option-tuples)*; option-group-title ::= text; description ::= text; option-tuples ::= (help-text, option-strings, kwargs)*; help-text ::= text; option-strings ::= e.g. ['-Q', '--quux'];
SettingsSpec.settings_defaults = Noneサブクラスメンバーデータ
self.defaultsにマージupdateされる。外部からのアクセスを意図していない。
SettingsSpec.settings_default_overrides = Noneサブクラスメンバーデータ
self.defaultsにマージupdateされる。サブクラスが上書きする。
SettingsSpec.relative_path_settings = ()設定ファイル群の相対パスを文字列の
tupleで持つ。これは設定ファイルが複数ファイルに分割されていて、それらのファイルシステム上での、ある基点からの相対パスということだろう。サブクラスメンバーデータ
self.relative_path_settingsにextendされる。
SettingsSpec.config_section = None設定ファイルのセクション名そのもの。
サブクラスが上書きする。
SettingsSpec.config_section_dependencies = None上述のデータと同様だが、優先順位がより高い。
サブクラスが上書きする。
サブクラス¶
SettingsSpecの直接サブクラスは 2 つだけある。図に示す。classDiagram direction TB SettingsSpec <|-- OptionParser SettingsSpec <|-- Component class SettingsSpec{ +tuple settings_spec$ +dict settings_defaults$ +dict settings_default_overrides$ +tuple relative_path_settings$ +str config_section$ +tuple config_section_dependencies$ } class OptionParser{ +tuple settings_spec$ +dict settings_defaults$ +tuple relative_path_settings$ +str config_section$ } class Component{ +str component_type$ #tuple supported$ +supports(str) bool }Componentでは何もオーバーライドしないが、そこからのサブクラスはsettings_specとconfig_sectionを上書きするだけのことが多い。例:config_section = 'general'
クライアント¶
主な参照箇所はモジュール docutils.core と docutils.frontend に集中している。
Component系とOptionParser系を読む。OptionParser.get_config_file_settingsを読む。OptionParser.populate_from_componentsを読む。
クラス docutils.TransformSpec¶
TransformSpecはスーパークラスがない。メソッド
get_transformsが一つだけある抽象クラスと大づかみに理解してよい。必要に応じてサブクラスがオーバーライドする。他にも細かいクラスデータや格納データの約束事があるが、そこまで調査しなくてよいだろう。
メンバー¶
get_transforms(self)クラス
Transformのサブクラスを含むlistを返すようにサブクラスがオーバーライドする。注意。サブクラスのオブジェクトではなく、あくまでもサブクラスを型として取り扱う。
サブクラス¶
TransformSpec をスーパークラスとしたクラス図を示す。
InputおよびOutputは何もオーバーライドしていないことに注意。設計ミスか?メソッド
get_transformsはComponentのさらなるサブクラスがオーバーライドする傾向がある。
クライアント¶
メソッド get_transforms を呼び出すのは何かということになる。
サブクラス
Transformerが自身のメンバーデータを組み立てるときのパラメーターとして参照する。
これぐらいしかないだろう。
クラス docutils.Component¶
Componentは Docutils のテキスト処理系クラスのためのスーパークラス。言い換えるとReader,Parser,Writerがサブクラスとなる。Componentのスーパークラスは前述のSettingsSpec,TransformSpecだ。なお、この段階ではいずれのスーパークラスのどのメンバーもオーバーライドしないままだ。
メンバー¶
クラスデータが 2 個とメソッドが 1 個ある。重要なものだけ記す。
Component.component_typeコンポーネントの種別を示す文字列とする。各サブクラスで上書きする。つまりこのようなものだ。
サブクラス
component_typeの値Reader'reader'Parser'parser'Writer'writer'実は
ComponentのサブクラスではないクラスであるInputとOutputにも同名のクラスデータがある。
Component.supported = ()種別名を集めたもの。意味は「このクラスがサポートしている種別の一覧」ぐらいだろう。
サブクラス側で上書き、実行時には変更なし。
def supports(self, format)問い合わせメソッド。意味は「このクラスは
formatをサポートしているか?」であり、この判定に先述のクラスデータを参照する。引数
formatは文字列とする。
サブクラス¶
Component の直接のサブクラスは次の 3 つである。
ReaderParserWriter
Docutils のエンドユーザーが Component から直接サブクラスを定義することはなさそうだ。
クライアント¶
主にモジュール docutils.transforms の機能が利用する。
メソッド
supportsを利用するのはFilterというTransform系のクラス。本節ではこの処理を解読しないでおく。
感想¶
SettingsSpecの設計方針は理解できるが、何か複雑だ。TransformSpecをInputとOutputが継承しているのは何かの間違いと思う。どの子孫クラスもget_transformsをオーバーライドしていない。TransformSpec.get_transformsのように、オブジェクトというよりは型を操作するやり方には馴染んでおきたい。Docutils はクラスデータを C++ 風に言えば
static constのように扱うポリシーなのだろう。クラスデータをサブクラスで上書きするという方法は私はあまり採らないので、これは大いに参考にしたい。