「Sphinxをはじめよう 第二版」が出ます
みなさん、Sphinx 使ってますか? Python や Linux カーネルのドキュメントでご存知の Sphinx の書籍、「Sphinxをはじめよう」が改訂されます。
今週末の #技術書典 で僕らが書いた #Sphinxをはじめよう の第二版が発売されます。しかも今回は紙媒体!(電子版もあるよ)。これからSphinxを触ってみようかなと思っている方におすすめです。細かな加筆をしているので、第一版をお持ちの方にもおすすめです。 #sphinxjp
— Takeshi KOMIYA (@tk0miya) 2017年10月17日
#Sphinxをはじめよう の第二版は 1) Sphinx-1.6 に合わせて加筆 2) 基本のマークアップの説明をアップデート 3) みんな大好きmarkdownの説明をAppendixとして収録 4) 画像系のツール/サービスとの連携まわりの章を追加 とあれこれいじってます。
— Takeshi KOMIYA (@tk0miya) 2017年10月17日
ちなみに紙版の #Sphinxをはじめよう は、各種イベントでオライリーさんが出展しているときに買えるみたいです。(もしかしたら直販でもいけるかも?) 紙が大好きなみなさんは #技術書典 のオライリーブースにまっすぐゴー!
— Takeshi KOMIYA (@tk0miya) 2017年10月17日
#sphinxをはじめよう はオライリーさんのブースで手にとっていただけます! (というのを書き忘れてました) #技術書典
— Takeshi KOMIYA (@tk0miya) 2017年10月17日
計画当初は 2章だけ加筆して、残りは微調整するだけだったはずなのですが、第一版を読み直して手直ししているうちに、1章と2章は大幅に書き換えることになりました。基本的な内容は同じですが、図を入れたり説明を整理するなどしたので、旧版より読みやすさが上がっているはずです。
目次はこんな感じです。「6章 画像の変換と埋め込み」と「付録 C sphinx-quickstart の設問一覧」、「付録 E Windows への make コマンドと sh コマンドのインストール」、「付録 F Markdown で書いてみよう」あたりが新しい内容です。
- はじめに
- 1章 Sphinx とは
- 2章 Sphinx のインストール
- 3章 議事録を書いてみよう(HTML への変換)
- 3.1 Sphinx によるドキュメント作成の流れ
- 3.2 プロジェクトの作成
- 3.3 議事録を書こう
- 3.4 HTML テーマを使おう
- 3.5 まとめ
- 4章 PDF に変換してみよう
- 4.1 インストール手順書を書いてみよう
- 4.2 いくつかのパートに分けて文章を書く
- 4.3 まとめ
- 5章 EPUB に変換してみよう
- 5.1 画像を埋め込む
- 5.2 他のページを参照する
- 5.3 EPUB に変換する
- 5.4 書籍の出力オプションを設定する
- 5.5 まとめ
- 6章 画像の変換と埋め込み
- 6.1 基本中の基本、figure ディレクティブ
- 6.2 Cacoo を利用する
- 6.3 まとめ
- おわりに
- 付録
基本的には初心者向けの本ですので、これから Sphinx を使ってみたいという人向けの本ですが、
既に使っているという人でも、まわりに reST/Sphinx を布教するときの役に立つかと思います。
僕のこの夏の努力の結晶なので、興味がある方は是非とも見ていただけるとありがたいです。
2016年を振り返る / 2017年の抱負
あけましておめでとうございます。正月なので、毎年恒例の抱負エントリです。
年末にがーっと連続エントリを投稿したのでもう大体振り返り終わったんじゃないのか、とは思うのですが、それはそれ、これはこれということで振り返っていきます。
2016年の抱負 として挙げたのは
- Sphinx のバグ/タスクを減らす
- blockdiag のバグ/タスクを減らす
- なにか使えるツールをリリースする (少なくとも一本以上)
- 技術書を読み続ける
- コードを書く時間を維持する
- 体重維持
の6個でした。
まずはそれぞれについて振り返っていきます。
Sphinx のバグ/タスクを減らす:△
メンテナ活動をがつがつしていたので、さぞかしバグが減ったでのでしょう? と思ったのですが、減る勢いより増える勢いのほうが強くて押し切られました。元旦時点で 606件のイシュー + PR があります。
ほぼ安定して月に 60件(日に2件)以上のペースで減らし続けているはずなのですが、それでも追いつけないというのは非常に厳しいですね。
blockdiag のバグ/タスクを減らす:✕
Sphinx に空き時間をすべてつぎ込んだたので、なにもやってませんね。
そろそろ諦めてきました。
いじりたい人がいないのであれば、そろそろ放棄ですかね…。
なにか使えるツールをリリースする (少なくとも一本以上):◯
2016年に新しく作ったのはこのあたり。
- GitHub - tk0miya/sphinxcontrib-toc
- GitHub - tk0miya/sphinxcontrib-github_ribbon
- GitHub - tk0miya/sphinxcontrib-jsonschema
- GitHub - tk0miya/sphinxcontrib-apiblueprint (ベース部分は 2015年だけども…)
Sphinx の片手間に Sphinx 拡張を手がけるような人生だったようです。
ちょいネタが多めだったのですが、ちょっとは使ってもらえそうな拡張なので、◯評価にしてしまおうと思います。
技術書を読み続ける:◯
引き続き 2016年も 新宿 Book-a-thon に助けられました。
もうこのイベントなしには本は読み進まないであろうという確信があります。
結局読み切った本は The Web Explorer と Re:VIEW 本の 2冊だけです。
実践DDDと TeX by Topic は内容が難解で読み進めるのに苦労している(しかも途中で他の本を読み始めてしまった)ので、なかなか進みがよろしくないです。
また、今年は SoftwareDesign の連載があったので、そのレビューにかなり Book-a-thon の時間を使ってしまいました。
Re:VIEW本は非常に感銘を受けたので、いつか実践をしてみたいですね。
今年はちゃんと読書の時間を確保して、ちょこちょこ前に進んでいきたいところです。
コードを書く時間を維持する:◎
Sphinx メンテナ業をやっていたおかげで、これは胸を張って達成したといえます。
(仕事では github を使っていないので、この履歴はオープンな活動のみです)
大きい課題をやっつけているとき、ML の返事を書きまくる日、レビューしている日など、コミットばかりしているわけにもいかないので、毎日草を生やすことはできていませんが、結構安定して活動していたと思います。
これまでは活動している時期としていない時期がはっきりと分かれていて、全体ではまあまあぐらいの活動量だったので、ぐっと活動が見える人になったのではないでしょうか。
体重維持:◯
2015年末が 65.0kg で、先ほどはかってみたら 66.0kg でした。
グラフを見てると多少の揺れはあるものの、65〜66kg 前後で安定しているようです。
今の職場が駅徒歩 0分のところで、通勤の負荷がなくなったにもかかわらず、なんとかキープできてよかったです。
その他の振り返り
技術的な話となるとやはり Sphinx ネタが多くなるのですが、その他プライベートではちょこちょこ動きがありました。
備忘代わりに書き留めておきます。
体調が不安定だった
なんだか体調が安定しない年でした。
- 頭痛とめまいに襲われて CTスキャンをしたり MRI を撮ったり (結局原因がわからないうちに落ち着いてしまった)
- キーボードのタイプしすぎなのか、手首や肘にダメージを負っていたり (まだ続いている)
- 検診でポリープが見つかったり (でも、病院に行ったら勘違いだとわかった)
- 胸に違和感があったり (原因不明だけど、いまは落ち着いている)
どれも原因がはっきりしないうちに症状が落ち着いてしまったので、一時的な不調だったのかなーってことで済ませてしまっていますが、頭脳は子供でも体はもうすっかりおっさんだということがわかりました。
いまは肘以外はとくに悪くないので、ぼちぼちいたわって生きていきます。
旅行しまくった
マイルやふるさと納税で宿泊券をゲットしまくったので、あちこち旅行に行ってきました。
- 高遠 & 飛騨方面
- 浜松らへん (Ingress)
- 鹿児島 (帰省)
- 京都 (RubyKaigi, 弊社タイムインターメディアに支援してもらった)
- 京都 + 高松/岡山 (Ingress)
- 大垣 (Ingress)
- 上高地
- 秋田 (日本橋ヨヲコ先生の個展を見に行ってきた)
Ingress がきっかけで遊びに行くことが多かったようですね。
イベントそのものはあまり参加していないのですが、毎回あたりをウロウロしています。
また、趣味で埋めていっている道の駅探訪マップもちょっとずつ埋まってきました(青が2015年以前、緑が2016年、赤は未訪問)。
いろいろ行けてたのしかったものの、おかげでお財布の中がかなり寂しいことになってしまいました。
宿泊券やマイルを使っても、ガソリンは減っていくし、ご飯は食べますもんね…
今年は控えめに生きていくつもりです。いまのところは。
まとめ / 2017年の抱負
去年の抱負の成果は ○ 4つ、△ 1つ、× 1つでした。まあまあですね。
というわけで、さっくり今年の抱負。
- ひきつづき Sphinx のメンテナ活動をする
- もうしばらく、飽きるまではメンテナ活動しようと思います
- あと 2.0 への道筋を決めていきたい
- そういえば Sphinx-Users.jp の 2017年の会長に就任したので、ひきつづきなんかやります
- Sphinx 以外のネタにも手を出す
- Sphinx ばかりだとすぐに飽きてしまいそうなので、たまには別のことも織り込んで…
- なにか使えるツールをリリースする (少なくとも一本以上)
- いつもの。今年もなにかがんばりたい。
- 技術書を読み続ける。時間を取る。
- 引き続き。ただし、今年はやや時間が確保できなかったので、今年は回復を目指すつもり。
- 家の片付け
- メンテナに時間を注ぎすぎて、身の回りがすこし荒れているので、なんとかしたい
- 健康生活
- 言わずもがな。
Sphinx in 2016
昨日は Markdown の 2016年を振り返りましたが、今日は Sphinx の 2016年を振り返りつつ、
2017年の目標を適当に挙げてみようと思います。
2つのメジャーリリースと 13のマイナーリリース
今年は 1.3.4 から 1.5.1 まで、合計で 15のリリースを行いました。
2014年が 1.2.1 から 1.2.3 までの 3リリース、2015年が 1.3 から 1.3.3 までの 4リリースだったとの比較すると、コンスタントに改善を続けられたと感じています。
もうひとりのメンテナである清水川氏と相談し、Sphinx ではリリースポリシーを刷新しました。
おおよそ 1ヶ月おきに 1回のバグフィックスリリース、6〜8ヶ月おきに 1回のメジャーリリースを行うつもりで進めています。
少し前の記事にある通り、メンテナのリソースも十分にあるというわけではないので、あくまで目標でしかありませんが、今年は無事にこの間隔が守れました。
次のメジャーリリースは夏頃に予定されている 1.6 です。
まだ具体的に動き出してはいないですが、API の整理やいくつかのあたらしい機能が実装される予定です。
いまだに手が出せていない HTML5 サポートや TeX まわりの改良など、やりたいことはいくつもあるので、その中からピックアップしながら作業を進める予定です。
Sphinx メンテナチーム
少し前に記事にしたとおり、2016年は活発的に活動するメンテナが増えました。
2015年末に自分が復帰したのは、チケットの消化にはかなり大きな変化があったと自負しています。
2015年には 350件ぐらいしかクローズできていなかったものが、2016年は1000件以上クローズできています。
先程触れたリリースの件と合わせ、テンポよくメンテナンスが行われるようになっています。
また、TeX 使いの jfbu が加入したのはメンテナチームにとってかなり大きい変化です。
これまで TeX に強いメンバーがいなかったので、おっかなびっくり修正したり、もしくは問題が放置されていたりと、結構ひどい状態だったのですが、かなり改善がありました。
1.5 系ではその恩恵をかなり得られるはずです。
引き続き、彼と一緒に TeX まわりの改善を続けていこうと思っています。
いつか TeX 出力でもテーマ的なものが実現できるといいですね。
Sphinx の各種イベント
2016年も安定して Sphinx+翻訳 Hack-a-thon と Sphinx Tea Night が開催されていました。
ふたつのイベントは引き続き、毎月開催され続ける予定です。
一方、SphinxCon は開催されませんでした。ちょっとタイミングが合わなかったので、2017年にリベンジしたいと思います。
タイムリーにこんなお誘い? もありましたしね!
2017年はRe:VIEWとSphinxの合同イベントをやりたい
— masayoshi takahashi (@takahashim) 2016年12月30日
Software Design 誌での Sphinx 連載
連載も 2年目に入って、応用的な内容が続いています。いろんな分野に広がっていてとても面白いですね。
自分も合計で 4回ほど寄稿しました。
いままで説明されていなかった分野の記事を書いたり、不足がちな機能を補うためにあらたな拡張を書いたりしました。
sphinxcontrib-jsonschema や sphinxcontrib-apiblueprint を新たにリリースしたり、sphinxcontrib-textstyle にパッチを投げまくったりしました。
先日は toc 拡張を作ったりしましたし、やはり発表ドリブン、記事ドリブンでなにかをやるのはコードが生まれて楽しいですね。
アドベントカレンダー
2016年はアドベントカレンダーは特に開催されませんでした…が、そのかわりにこのカウントダウン連載をやっていました。
本当に白紙の状態で書き始めたので、調べ物をして、コードを書いてと大変な毎日でした。メンテナンスも放置状態ですしね。
来年はみんなで、負担を分散してできるといいですね。
せめて、ひとりでやるにしても事前にネタを仕込んでおきたいところです。
まとめ
とくにまとまりなく終わります。やっつけ気味ですみません…。
みなさま、 2016年はお疲れ様でした。2017年も引き続きよろしくお願いします。
(もう年は越してしまったのだけど、一応 12/31 の記事の体で)
Markdown in 2016
Markdown、あなたのすぐとなりに潜む問題
昨日は toc 拡張の話ついでに、現在の Sphinx と markdown を取り巻く環境について愚痴ったわけですが、Markdown 業界は 2016年のこの時期になっても、いまだに共通的な仕様が決まっていません。
2004年、John Gruber によって生み出された Markdown は、12歳を迎えた現在、さまざまな markdown 処理系を持っています。
そして、不幸にも実装によって markdown の処理はそれぞれ異なってしまっています。
これは Markdown の仕様が曖昧であることと、それぞれの処理系で文法の拡張を行っていることから来ています。
Markdown 処理系による違い
Markdown の仕様が曖昧であることは、さまざまな混乱を生み出しました。
babelmark2 が示すように、同じマークアップであっても処理系によって出力結果が変わってしまうということが起きています。
これに対して、2014年10月に CommonMark プロジェクトが立ち上がります。
CommonMark プロジェクトは Markdown のあいまいな仕様を整理しなおし、マークアップごとにどういう風にレンダリングされるべきか、また解釈の優先順位はどうなるべきかなど、詳細な仕様を定めることをゴールとしたプロジェクトです。
昨日触れた recommonmark も、この CommonMark に準拠した実装のひとつです。
(より正確には、CommonMark 仕様に準拠した python 実装である CommonMark パッケージを Sphinx から利用できるようにラッピングしたものです)
文法の拡張と方言化
もうひとつの Markdown の問題は文法の違いです。
オリジナルの Markdown には必要最低限のマークアップしか定義されておらず、それ単体では表すら書くことができません。
オリジナルの Markdown では表や脚注、定義リストなど、幾つかの要素を持っていないため、
ドキュメントの内容によっては表現できないものがあります。
Markdown には HTML を含めることができるので、HTML をごりごり書くことで回避はできますが、あまりスマートではないですよね。
こうした課題を解決するために、おおくの Markdown 処理系で文法を拡張しました。
有名なのものとしては、多くの人が使っている GFM こと Github Flavored Markdown や
PHP Markdown Extra などが挙げられます。
他にも拡張したものは数多く存在します(参考: Wikipedia Markdown#利用例と方言)
こうして、Markdown には "基本的な文法” は同じだが、ちょっとしたおまけの文法がある Markdown の方言が雨後の筍のように大量に存在するのです。これが現代のバベル、Markdown なのです*1。
2016年に起きたこと
2016年は Markdown の大きな節目になる…はずでした。
CommonMark 1.0 がリリース…されなかった
commonmark.org には、以前からこんな記述があります。
When is the spec final?
The current version of the CommonMark spec is complete, and quite robust after a year of public feedback … but not quite final.
With your help, we plan to announce a finalized 1.0 spec and test suite in early 2016.
しかし、あと2日弱で 2016年が終わろうとしている今日現在でも、1.0 はリリースされていません。
11月18日には 0.27 がリリースされていますが、いつごろ 1.0 はリリースされるのでしょうか。
CommonMark が定まることで、処理系ごとにマークアップが異なっていた問題は徐々に収束していくものと思われます。
もちろん、これから各処理系を手直しして CommonMark に合わせていく作業は残っていますが、
Markdown の標準化に向けては大きな一歩になるはずです。
(まだ 1.0 とはいえ、かなり形になってきているものなので、各ライブラリでは対応が進んでいるとなお良いのですが…)
Markdown が RFC に登録された。media type として。
以前から Markdown を RFC に登録しようという動きはあったのですが、ついにそれが実を結びました。
RFC7763 The text/markdown Media Type と RFC7764 Guidance on Markdown: Design Philosophies, Stability Strategies, and Select Registrations がそれです。
これまで説明してきたとおり、処理系によって解釈がまちまちだったり、さまざまな方言が存在する状況で、Markdown はどのように標準化されたのでしょうか?
ふたつの RFC では、Markdown に関するパラメータが次のように定義されました。
- IANA で markdown の方言を Markdown variants として登録管理することになった
- media type には text/markdown を使うことになった
- このふたつを組み合わせて Content-Type ヘッダで text/markdown; variant=Original と指定できる
つまり、RFC は Markdown の “文法” を標準化したのではなく、
1. Markdown の文法が分断されていることを追認した上で、
2. どの文法を使っているのか(使うのか)を variant として media type で示すことができる
という標準化だったのです。
わかりますね? IETF でもばらばらになった方言はどうにもならなかったのです。
RFC7763 には次のような説明があります。
Markdown variations (some might say "innovations") are designed to
be broadly compatible with humans ("humane"), but not necessarily
with each other. Therefore, syntax in one Markdown derivative may
be ignored or treated differently in another derivative.
意訳:
まとめ
- Markdown の標準化はちょっとずつ進んでるみたい
- でも、まだ方言問題は解決しそうにない
- もし処理系を作る場合は方言を増やさないようにしましょう
おまけ
CommonMark にテーブル記法を足そうとか、recommonmark (CommonMark 処理系)に様々な便利文法を足そう、みたいな提案やイシューが並んでいるのを見て、まだしばらくは方言問題は解決しないんだろうなあ、と感じました。
Sphinx から完全に reStructuredText を追い出した話
いくつかの記事で紹介されているとおり、 recommonmark を使うと Sphinx で markdown を使うことができます。
- Software Design 2016年4月号 Markdownで始めるSphinx
- MarkdownでSphinxできるようになったので試してみた(前編) - 意識の高いLISPマシン
- Markdownで書けるSphinxの構築 - Qiita
しかし、recommonmark を利用しても、ドキュメント構造(toctree)を記述するためには部分的に reStructredText を使う必要がありました。
.. toctree chapter1 chapter2 chapter3
これは、文法を拡張する仕組みを持たない markdown の (commonmark の)構造上、仕方がないのですが、せっかく markdown でドキュメントを書いているに、一部 reST 記法を使わなくてはならないのは、少しもにょっとしますね。
どうせなら、完全に reST を書かなくてもよい仕組みがほしいところです。
sphinxcontrib-toc
ということで、sphinxcontrib-toc を作りました。
sphinxcontrib-toc は toctree を表現する .toc ファイルを用意することで、reST を書かずにドキュメントを作ることができます。
使い方はたったの 3ステップです。
1. 以下のコマンドでインストールします。
$ pip install sphinxcontrib-toc
2. conf.py で拡張を有効にします。
extensions = ['sphinxcontrib.toc']
3. index.toc というファイルに、ドキュメントを構成するファイルを列挙します。
chapter1 chapter2 chapter3 ...
4. 最後に、不要となった index.rst を削除します。
$ rm index.rst
あとはビルドするだけです。
$ make html
大きいドキュメントを書くときは
大きいドキュメントを書きたい場合は、複数の .toc ファイルを作り、親の .toc ファイルから子の .toc ファイルを参照します。
chapter1/index chapter2/index chapter3/index
そして、子の .toc ファイルにはその章や節を構成するファイルを列挙します。
# 章タイトル section1 section2 section3
子の .toc ファイルでは markdown のタイトル記法を使って章や節のタイトルが指定できます。
(省略した場合はドキュメントのタイトルが適用されます)
sphinxcontrib-toc の仕組み
sphinxcontrib-toc は .toc ファイルを通じて toctree を生成します。
内部ではあたらしいファイルタイプを Sphinx に登録し、.toc ファイルが見つかるたびに sphinxcontrib-toc が呼び出されるようになっています。
そして、sphinxcontrib-toc は .toc ファイルをパースして、toctree を生成します。
これは 1.4 から導入されたソースパーサ(Source Parser)という仕組みを使っています。recommonmark もソースパーサのひとつですから、じつはふたつのモジュールは同種の拡張として実装されています。
.toc ファイルは設定ファイルのような見かけですが、実はドキュメントとして処理されています。
これで完璧!?
さて、これで Sphinx と markdown の組み合わせでドキュメントを作ることができます。
github や qiita、そのたたくさんのプラットフォームで使われている markdown でドキュメントが書けるのです!最高ですね!
と盛り上げてみたものの、実際書いていくと、まだ問題はいくつか残っています。
- recommonmark は CommonMark の範囲のマークアップしかできない
- 表、定義リスト、脚注、顔文字などを書けない
- recommonmark はディレクティブやロールが使えない
前者については、commonmark の仕様上の問題ですので、recommonmark に代わる別の markdown パーサが出てくるのを待つ必要があります。
個人的な実験プロジェクトとして sphinxcontrib-markdown というのを作りかけのままにしていますが、これが完成すると github flavored markdown にも対応したものができるはずです。
興味がある方は手伝っていただけると非常にありがたいです。
後者は markdown の文法をさらに大きく変えることになります。
利便性は高くなりますが、あらたな markdown 方言を生み出すことになります。
実は recommonmark にも AutoStructify という拡張文法が存在します。しかし、こうした方言を利用した場合、別の処理系にはドキュメントを持ち運ぶことができなくなります。
ここはトレードオフになる部分ですので、どのようにマークアップすべきかも含めて、ツール選びを検討すると良いでしょう。
Sphinx コードの半減期と未来予想図
Twitter で流れてきた コードの半減期とテセウスの船 | 開発手法・プロジェクト管理 | POSTD を読んで、興味深かったのでさっそく Sphinx のコードでも実行してみました。
その結果がこちらです。
コードの増え方は時期によって波がありますが、やはり Sphinx もコードの量は右肩上がりに増えています。そして、古いコードは徐々に整理されて少なくなっています。
面白いのは、生き延びた古いコードはある程度安定しているためか、削除されることが少なくなってきている一方で、新しく追加されたコードは入れ替わりが激しい傾向が読み取れます。
Sphinx はまだコードの追加と削除が繰り返される、活発なプロジェクトだということがわかります。
モジュールごとの半減期
さて、せっかくの機会ですから、別の角度からも見てみましょう。
このグラフは Sphinx の主要モジュールの年代ごとのコード比率です。
以下のコマンドでえいやっと計算しました。
$ find sphinx/environment -type f -exec git annotate {} \; | perl -ne 'm/(\d+)-\d+-\d+/; print $1, "\n"' | sort | uniq -c 155 2007 180 2008 128 2009 81 2010 80 2011 6 2012 10 2013 272 2014 42 2015 1159 2016
directive, builders, writers, util, ext, application などの主要なモジュール群は 40〜50% 程度の実装が 2010年までに実装されたものだということがわかります。
一方、domains や environment は 25% 程度とコードが入れ替わっていることがわかります。
また、environment を除くモジュールは約 25% 前後が 2016年にコミットされたものだということがわかります。
ここ 1年であちこちに手を入れていったので、その成果がここに現れているということですね。
さて、2016年に変更されたものでも、ひときわ目立つものがあります。見ておわかりの通り、 environment です。
なんと environment モジュールは 50% 超が 2016年製のコードです。
大きく書き換わった environment モジュール?
いったいこの 2016年、 environment モジュールに何が起きたのでしょう?
種明かしをすると、実はコードの内容は大きく変わっていません。
2016年10月、 https://github.com/sphinx-doc/sphinx/pull/2945/files という PR が取り込まれました。
これは、environment をリファクタリングし、いくつかの細かいモジュールに分割する変更です。
モジュール化にあたり、インターフェースを定義するなどの多少の調整は行っていますが、これまでのコードからは大きく変化はありません。
つまり、この 50% という大きな変更はファイルの分割によって発生しているものでした。
実は git blame が理解していないだけで、そんなに大きい変更ではなかったんですね。
生まれ変わる Sphinx
それでは、どうして Sphinx プロジェクトではこのような変更を行ったのでしょうか?
その答えは Sphinx のコードの複雑さにあります。
Sphinx は数多くの人に使われていて、多くの API によって拡張可能となっているにもかかわらず、その内部は結合度が高く、モジュールの粒度もかなり大きいままです。
現在、このおおきな Sphinx のコアモジュールを整理する動きがあります*1。
特に environment モジュールはコードベースが巨大で、持っている機能や責任範囲も広く複雑です。
担当する責務をいくつか例に上げると、
- ドキュメントソースの読み込み
- ドキュメントの中間データの管理、保存
- その他の中間データ(インデックスやドメインデータなど)の管理、保存
- 目次データの生成
- 更新されたドキュメントソースの検知
- アセットファイル (ダウンロードファイルや画像ファイルなど)の管理
- ログ管理
- パス変換
- ビルド中のコンテキスト情報の保持
- 参照(リンク)の解決
- ドメイン機能の提供
- インデックスの管理、解決
- etc. etc.
などがあります。
あきらかに単一責任の原則に反していますし、メンテナンスをしている側からも非常にわかりづらい、魔窟化したモジュールのひとつでした。
というわけで、あの PR ではこの魔窟を切り広げるための第一歩として投げ込まれたものです。
ただ、これはあくまで一歩目でしかありません。
まだまだ続く Sphinx のリニューアル
今後も Sphinx の構造をシンプルにしていく活動は続きます。
(個人的な) ゴールとして、次のようなことを目標にしています。
Sphinx はさまざまな API を提供する大きなフレームワークの一種です。
Sphinx 自体もそのフレームワークを利用している (HTML 出力や LaTeX 出力などは拡張として実現している) のですが、一方でフレームワーク部分はあまりきれいに整理されておらず、どちらかというとモノリシックな構造でできています。
今後はモジュール化をすすめ、フレームワーク部分をより整理したものを目指していきます。
おそらくその過程で、Sphinx コアはスリムで拡張しやすくなり、整理された API セットがみつかっていくでしょう。
今のところ、このスリムな Sphinx & API セット を 2.0 とすべく、こつこつリファクタリングを繰り返しています。
次は…?
いまはログまわりの改修を進めています。
https://github.com/sphinx-doc/sphinx/pull/3267
Sphinx はメッセージ出力、ログ出力を application, environment という 2大モジュールで経由するようにデザインされています。
そのため、ログを出力するにはどちらかのインスタンスを持っている必要があるため、単にログを出力したいがために application オブジェクトが渡されているなど、無駄に結合度が高い作りになっていました。
この PR では、これらを切り離し、python の logging パッケージで置き換えようとしています。
*1:なんとなく他人事っぽく書いてみたものの、動いているのは自分なので「やってます」が正しいですね
Linux カーネルでの Sphinx 利用法を見てみよう
年末カウントダウン Sphinx 連載、第3弾です。
一切下準備をせずに連載を始めたので、早くも息切れをしています。
だれかと約束をしたわけでもないのに急にアドベントカレンダー的なものを始めるのは、なんだか死に急いでいる気がしてきました。
今回は、今年から Sphinx の利用者に加わったある大型プロジェクトについて紹介しましょう。
そのプロジェクトとは、世界最大級の OSS のひとつである Linux カーネルです。
現在の Linux カーネルドキュメント
今年開催された LinuxCon Japan 2016 で Linux カーネルのドキュメントに Sphinx を使うという発表がありました。
Linus Torvalds氏が登壇、「約10週間のリリースサイクルは続く」 - クラウド Watch
それから約 5ヶ月。現在はどうなっているのか見てみましょう。
Linux カーネルのドキュメントは https://www.kernel.org/doc/ で公開されています。
最初に目に入るのは (new sphinx format) という記述が目に入ります。
そして docbook format の方には (deprecated) の文字が。
というわけで、いまでは Linux カーネルのメインのドキュメントには Sphinx が使われています。
リンクをたどると見慣れた readthedocs テーマで生成されたドキュメントが現れます。
カーネルドキュメントに Sphinx が採用された経緯
LinuxCon 2016 のプレゼンを聞いていた @senopen 氏は当時こんな風にツイートしています。
(当時、仕事中にこれが流れてきてかなりびっくりした覚えがあります)
#linuxcon カーネルのドキュメント。
— せのぺん (@senopen) July 14, 2016
・txtファイル:2000+
・DocBook:カーネルの心臓の記述
・Doxygen形式と似たのKerneldocコメント:55000個。
カーネル開発者がシステムを作った。
make htmldocs
#linuxcon 問題点が。
— せのぺん (@senopen) July 14, 2016
・遅い
・brittle
・設定とmakeが難しい
・他のDocumentation/ディレクトリと統合がない。
最近変えた。
markdonwを導入。その後AsciiDocに切り替えた。
#linuxcon
— せのぺん (@senopen) July 14, 2016
AscIiDoc
利点
・汚いDocBookを回避
・よりよい文書
欠点
・パフォーマンス
・文書館のリンク
・Ruby依存
#linuxcon
— せのぺん (@senopen) July 14, 2016
何がやりたいか。DocBookはやめたい。
簡単なマークアップを使いたい(Markdonw,AsciiDoc,Sphinx)。
フォーマットされていない文書にもそのまま使いたい
東道された文書ツリーを作りたい。
#linuxcon それでSphinxに目をつけた。
— せのぺん (@senopen) July 14, 2016
・コードの文書化に特化
・世界的な利用
・DocBookやLaTeXに頼らない。
で,Sphixを使うことで合意が取れた。
kerneldocコメントはいつも動作して,RST指示文を追加できる。
DocBook から移行をするのは理解できるものの、なぜ asciidoc ではダメだったのか、
Ruby 依存とはどういうことかと疑問に思っていたのですが、
その答えは LWN.net への投稿 で説明されていました。
asciidoc と Sphinx のどちらを採用するかの判断理由として、次のように説明されています。
But it seemed that neither tool would work as-is, or at least we wouldn't be able to get their full potential without extending the tools ourselves. In the kernel tree, there are no tools written in Ruby, but there are plenty of tools written in Python. It was fairly easy to lean towards Sphinx in this regard.
超訳:
Grant Likely summed it up this way: "Honestly, in the end I think we could make either tool do what is needed of it. However, my impression after trying to do a document that needs to have nice publishable output with both tools is that Sphinx is easier to work with, simpler to extend, better supported.”
超訳:
- どちらのツールでも要求は満たせた
- 両方試した結果、Sphinx の方が使いやすく、簡単に拡張できて、サポートがよかった
どうやら、既にカーネルの構成管理ツールとして Python が使われていたので、どちらかといえば Python を使ったほうが楽だろうという判断のようですね。また、Sphinx の方を気に入ってくれたようです。
(サポートが良かった、というのはどういうことなんでしょうかね。特に何かをした覚えはないのですが)
ちなみに Part.2 では移行や、あたらしいドキュメントの書き方について説明しています。
個人的にツボった所だけ抜粋しておきます。
grepping and reading reStructuredText is much easier than the angle-bracketed mess that is DocBook.
reST を grep したり読んだりするのは、DocBook のタグよりはるかにかんたんです。
It's a nice vision, I hear angels singing when I think about it and so on, it's where I want to go.
(数年後、包括的で読みやすいドキュメントができることについて)
そう考えると天使の歌声が聞こえます。
カーネルドキュメントはどのような設定になっているのか
カーネルドキュメントの設定は ここ から参照できます。
読み進めていくと、極めて一般的な、Sphinx の基本設定だけで構築されていることがわかります。
primary_domain が C になっているのは、やはり Linux カーネルですね。
primary_domain = 'C' highlight_language = 'none'
LaTeX のプリアンブル部には、いくつかの設定が指定されています。
- 色やスタイルなどの指定
- landscape 出力の準備
- XeLaTeX 用のフォント設定
また、巨大なドキュメントであるため、PDF もいくつかに分冊して出力するようになっています。
このあたりは Python のドキュメントでも培われた、ドキュメントを小分けにするテクニックをうまく使っているようですね。
latex_documents = [ ('doc-guide/index', 'kernel-doc-guide.tex', 'Linux Kernel Documentation Guide', 'The kernel development community', 'manual'), ('admin-guide/index', 'linux-user.tex', 'Linux Kernel User Documentation', 'The kernel development community', 'manual'), ('core-api/index', 'core-api.tex', 'The kernel core API manual', 'The kernel development community', 'manual'), ('driver-api/index', 'driver-api.tex', 'The kernel driver API manual', 'The kernel development community', 'manual'), ('kernel-documentation', 'kernel-documentation.tex', 'The Linux Kernel Documentation', 'The kernel development community', 'manual'), ('process/index', 'development-process.tex', 'Linux Kernel Development Documentation', 'The kernel development community', 'manual'), ('gpu/index', 'gpu.tex', 'Linux GPU Driver Developer\'s Guide', 'The kernel development community', 'manual'), ('media/index', 'media.tex', 'Linux Media Subsystem Documentation', 'The kernel development community', 'manual'), ('security/index', 'security.tex', 'The kernel security subsystem manual', 'The kernel development community', 'manual'), ]
また、カーネル特有の設定として、いくつかの拡張を利用するようになっています。
extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'cdomain']
ここで指定されている kerneldoc, rstFlatTable, kernel_include, cdomain という4つの拡張はドキュメントと一緒にコミットされている
カーネル専用の Sphinx 拡張です。
それぞれどういう効果のある拡張なのか、ひとつずつ見ていってみます。
カーネルドキュメント専用の拡張
kerneldoc
外部スクリプトである kernel-doc コマンドを呼び出して、カーネルのソースコードからコメントを抽出するディレクティブ kernel-doc を提供します。
抽出したコメントは reST として解釈され、ドキュメントに埋め込まれるようです。
rstFlatTable
list-table のようなリストベースの記法で、なおかつセル結合に対応したテーブル系ディレクティブです。
このページ のサンプルでわかるように :rspan: と :cspan: というふたつのロールを使ってセル結合を行います。
また、セルが足りない場合は自動的に補ってくれる autospan 機能もついています。
やや ad-hoc なマークアップではあるものの、複雑な表を作りたい場合は便利そうです。
kernel_include
環境変数などを含んだパスに対応した include ディレクティブである、kernel-include ディレクティブを提供しています。
おまけ
Linus が reStructuredText を書いているのか気になって調べてみたら、
過去半年で彼が Documentation/ ディレクトリ以下にコミットしたの、これだけだった。
https://github.com/torvalds/linux/commit/852d21ae1fcdf0e4de6b5bfa730d29cb013c7ff3
(その他はすべてマージコミット)
.rst ファイルに symlink を貼ったのも、Sphinx を使ったの一部、ですよね? (弱気)