読者です 読者をやめる 読者になる 読者になる

only ディレクティブの微妙なうごき

only ディレクティブを組み合わせるとあれこれ微妙な挙動が発生するようです。

最初は toctree と only ディレクティブの組み合わせについて悩んでいたのですが、
他にも only ディレクティブに関わる動きを @shimizukawa に教えてもらったので
合わせて紹介します。


toctree が 2重登録される

only ディレクティブの下に toctree ディレクティブを配置すると、
その toctree が 2重登録されてしまいます。

例えば、次のような reST を書いてみます。

.. index.rst

heading
========

.. toctree::

   sub
.. sub.rst
sub

.. only:: html

   .. toctree::

      subsub1

.. toctree::

   subsub2
.. subsub1
subsub1
--------
.. subsub2
subsub2
--------

subsub1 用の toctree が only ディレクティブの下に定義されていますね。

これをビルドすると次のような出力になります。
f:id:tk0miya:20140823112334p:plain

subsub1 が 2回表示されてしまいます。
subsub1 は 1度しか登場しないはずなのにおかしなことになっています。

ちなみにこのバグはすでに修正されているので、
1.3 がリリースされたときには解決するはずです。

toctree が 2重登録される(その2)

さて、さきほどのケースは only ディレクティブの条件を満たす場合のお話なのですが、
only ディレクティブの条件を変えて、条件が成立しないようにするとまた動きが変わります。
sub.rst の条件文を書き換えてみましょう。

sub

.. only:: never_matched

   .. toctree::

      subsub1

.. toctree::

   subsub2

この状態で make html すると、不思議な状態のドキュメントが生成されます。

まず index.html を確認します。
f:id:tk0miya:20140823131428p:plain

表示されている toctree を見ると、only ディレクティブで
除外されているはずの subsub1 が表示されています(今度はただしく 1つだけ)。

次に sub.html を確認してみます。
f:id:tk0miya:20140823131539p:plain
こちらのページでは、index.html では toctree に含まれていた subsub1 が表示されていません。
2つのページで矛盾があります。

また、よく見てみるとサイドバーの "Next topic" のリンクが subsub1 になっています。
ここも矛盾していますね。

ちなみに subsub1.html を見てみると、内容がそのまま HTML に変換されています。
ただ、ヘッダーの "previous" のリンクが自分を指していたりするなど、
奇妙な形に変換されてしまっています。

numbered の番号がスキップされる

続いて、先ほどの文章に numbered オプションを付けてみます。
そうすると、セクション番号が壊れてしまいます。
f:id:tk0miya:20140823132312p:plain

除外されたはずの subsub1 に番号が付いているのですが、
なぜか 1.2 からスタートしています。
1.1 がどこかに行ってしまっているわけですね。

glossary が登録される

only の中で glossary の登録を行うと、その only 条件を満たさない場合でも
その内容が用語集に登録されます。

.. only:: never_matched

   .. glossary::

      Sphinx
        a document generator

      docutils
        documentation utilities

このイシューでは他にも doxygenclass や toctree なども解釈されていると報告されています。

セクションの順番が入れ替わる

セクションと only を組み合わせるとセクションの順番が変化するというものです。

これは、次のようにセクションタイトルに対して only ディレクティブを指定すると発生します。

section1
========

.. only:: html

   section2
   ========

.. only:: html

   section2-1
   ----------

これを変換すると次のような順序で評価されます。

  • section1
    • section2-1
  • section2

これは現在の reST パーサ(docutils)の仕様(というか only ディレクティブの制約)のようです。

原理をつかもうと docutils の reST パーサを読もうとしたのですが、
仕組みを理解するのがハードモードだったので 1時間程度でギブアップしてしまいました…。

まとめ

only ディレクティブは docutils には存在せず、Sphinx で追加されたディレクティブであるため、
立て付けが怪しい部分がいくつかあります。

また、処理の順序の関係で「表示はされないが、内部的に処理はされている」というものも多くあります。
toctree や glossary などは only によって表示は行われないけれど、
内部的な処理は行われてしまっているために発生しているもののようです。


これらは今後改善される可能性もありそうな気はしますが、
仕組み上回避が難しそうなものもあるので、
直るかどうかはあまり期待しないほうがいいかもしれません orz