単独でタイプセットできるパッケージファイル
この記事は、サブブログの 2016-06-25 投稿記事を移転してきたものです。
パッケージとそのドキュメントを一緒に開発したいとき、最もよく使われていると思われるのは「docstrip」という仕組みである。最近よく見かける docstrip の使い方は
dtx ファイル(コードとドキュメント本体)+ ins ファイル(dtx から sty をストリップするためのバッチファイル)のセット
だろう。あまり書き方を説明したオンライン日本語文献はほぼ見当たらないが、例えば、ut さんちの「dtx ファイル一般の話とサンプル」の節に
例として、いんちきな dtx ファイルを用意してみました (foobar.dtx.txt):
として簡単な dtx サンプルも付いた記事がある。
以下では「通常の docstrip については既知である」と仮定して(相当読者が絞られるが…)話を進める。もし知らなかった場合は、TeX Live に付属する sty2dtx という Perl スクリプトに適当なパッケージ (hoge.sty) を与えれば、それらしい hoge.dtx が得られるので試してみてほしい*1。
でも:パッケージファイルひとつにしてみたい
確かに「コードの間近に説明を書き込めて、しかも LaTeX で処理して PDF ドキュメントまで作れる*2」という点は便利である。しかし、いちいち dtx から sty をストリップするのは面倒であるし、わかりづらい。
そうなると、「こんなことはできないだろうか」と考えたくなるのは自然であろう:
- sty ファイルを直に配布
- 当然これは
\usepackage
できる - 時に
\documentclass
より前で\RequirePackage
されうる
- 当然これは
- sty ファイル単独でもコンパイルが通る(→ PDF 化できる)
- dtx 同様のコード解説を含められる
…と思ったのだが、この試みは案外なされていない。そこでやってみた。
- tcstyalone.sty (aminophen's gist)
実用に供するパッケージではなく、あくまで実装の例示である。 → と思っていたのだが、結局後で実際に exppl2e.sty(pLaTeX の実験的コードを含めたパッケージ)で実践活用することとなる。
ちょっとだけ解説
コード中に解説は書いたが、トリッキーなのでもう少し詳しく。
トリックの中心は
\ifx\undefined\@undefined\relax % (パッケージの宣言) \else % (ドキュメント用「ドライバ」コード) \fi
の部分である(以下「トリックコード」と呼ぶ)。これは〈@〉のカテゴリーコードが「パッケージとして読まれた場合」と「TeX ファイルとして読まれた場合」で異なることを利用している。
case 1: パッケージとして読まれた場合
\usepackage{tcstyalone}
あるいは
\RequirePackage{tcstyalone}
の場合、上記「トリックコード」実行時には \makeatletter
が有効になっている。すなわち \ifx
が比較するトークンは \undefined
と \@undefined
である。どちらのコントロール・シーケンスも「未定義」なので、判定は真となり(パッケージの宣言)が実行される。
case 2: TeX ファイルとして読まれた場合
$ pdflatex tcstyalone.sty
あるいは
\input{tcstyalone.sty}
のように読まれた場合、上記「トリックコード」は \makeatletter
無効である。この場合、\ifx
が比較するトークンは \undefined
と \@
である。\@
はコントロール・シンボルで、LaTeX では
\spacefactor\@m{}
と定義されている*3ため「未定義」とは異なる。すなわち判定は偽となり(ドキュメント用「ドライバ」コード)が実行される。判定部の後にくっついている undefined\relax
なる部分は、真の場合のコードの一部とみなされて、必ずすっ飛ばされることに注意。
さらなる帳尻合わせ
ここで sty を単独でタイプセットしたい場合、「ドライバ」コード部には
\documentclass{...} \begin{document} ... \end{document}
を含める必要があるのだが、先の「トリックコード」では \fi
が \end{document}
より後に来てしまう。つまり、case 1 では既に \if...\fi
が釣り合っている一方で、このままでは「case 2 の場合だけ一回分 \fi
が足りない」という問題が発生する:
(\end occurred when \ifx on line 15 was incomplete)
これを解消するため、ここでは docstrip の「\DocInput
では行頭の %
が無視される」という仕様を利用してみた。case 2 だけ余分の \fi
を %
付きで発行するのである。そうして書いたのが、例の gist のコードである。
先行研究の例
以上の実装コードを書いたあとで、別解らしきものを見つけた。
*1:実際に sty2dtx を使った例として、pLaTeX がコミュニティ版に移行した後の ascmac パッケージ (tascmac.sty) とそのドキュメント (ascmac.pdf) が挙げられる。アスキーによる tascmac.sty は元々説明なしにコードが書かれていたが、コミュニティ版では sty2dtx で ascmac.dtx を作成したのち文書が書き下ろされている。
*2:もちろん普通の sty でも「%」を使ってコメントを付ければよいわけだが、そのまま LaTeX でタイプセットして PDF 化することはできない。
*3:2014 年までは {} が無かったが、ここではどうでもいい。