2016/01/27

技術書編集者として「これはやられた!」2015年の本

技術書の年間ランキング的なものについて、編集者たちに「これはやられた!」と思う他社の本を候補として出させたら面白いのでは、という会話を小耳にはさみました。これはまたとないアマゾンアソシエイトの機会!ということで、勝手に自分の候補を上げてみます。

と思ったものの、新刊の技術書をそんなにたくさん読んでいないうえに、去年「これはやられた!」と思った本はいずれも技術書ではなく、どちらかというと数学書っぽい本ばかりでした。それでも、ジュンク堂池袋本店の「新春座談会 このコンピュータ書がすごい! 2015年版」で取り上げられた本ばかりだし、たぶん技術者が読む(べき)本としても妥当なはずです。

コンピュータは数学者になれるのか? -数学基礎論から証明とプログラムの理論へ-

いま自分の本棚を見返したら、この本の隣にたまたま『日本の著作権はなぜこんなに厳しいのか』が並んでいて、一瞬だけ姉妹書に見えました。疑問形タイトル、文芸系とかビジネス系の出版社だと割と普通に見かけるけど、自分で本を企画するときには扱い方がわからず避けてしまうので、そういう書名を使いこなせる編集者になりたいです。というか、たぶん疑問形タイトルって、「これは既成の考え方をなぞった本ではなく、なおかつ人類は読むべきである」ことについて相当な自信がないと付けられない書名な気がします。

この本の場合、コンピュータと数学者のことを「算術計算に秀でたモノ」と考えている人にとっては、確かに「既成の考え方をなぞった本」ではないのでしょう。しかし、コンピュータとは自分が考えたプログラムが本当に動くことを確かめるためのものであるという人や、数学者はコーヒーから証明を生成する仕事であると気づいている人にとっては、どこかで見聞きして知っていたり知らなかったりする話にぐさっと明快な筋道を通してくれる本でした。一般向けの数学の読み物で見かける話も含まれてますが、call/ccは背理法ありの古典論理で純粋関数型言語は直感主義論理に対応しているんだという第5章のクライマックスに至る話を素で楽しめるのは、実際にプログラムを書いている技術者の特権だろうと思います。

出版社は青土社です。選択公理の読み物として一部で有名な‟The Pea and the Sun: A Mathematical Paradox”(Leonard M. Wapner)の翻訳である『バナッハ=タルスキの逆説 豆と太陽は同じ大きさ?』をはじめ(原書しか読んでないので翻訳の出来は知らない)、意外に「え?」っていう理学系の本も出してくるし、割と好きです。「現代思想」とか「ユリイカ」でも思想的な文脈で現代数学の記事をたまに掲載しているし、そのうち計算機科学や機械学習の特集もあるに違ない。

圏論の歩き方

Haskellを使うのに圏論はいらないって言うけど、みんな圏論圏論って言ってるので、どうしたって圏論が気になりますよね。そんな人間を狙いうちする本が日本評論社から発売されました。タイトルどおり、圏論の名所をめぐるツアーガイドのような本です。いつか自分の足で行ってみたいけど余裕がなくて行けない場所へ行った気になれる本です。去年の夏に読んで、いまこうやって記事を書くつもりで内容を要約しようとしても、さっぱり具体的な言葉にできないんですが、そのへんもツアーガイドに似ています(実際、「地球の歩き方」なんかにしても、行く場所を決めるときに読んだ内容をあらためて説明しろと言われても言葉に詰まりそう)。

正直、この本のうち計算機に関する部分については、まさに自分でこんな本を作りたかったという気にさせてくれる本でした。この本が企画として面白いと思うのは、コンピュータ書でいえばフレームワークに対する「クックブック」のような本を、数学の一分野で形にしてしまった点です。数学書、コンピュータ書でいえば「コードの動作について説明しただけ」だったり「コード読めばわかるよね」だったり、そんな立ち位置の教科書が少なくない気がします。コンピュータ書の場合には、実行例を見せることで「どんな場面でどんなコードが必要なのか」を説明できたりしますが、それを数学書でやったのがこの本なのかなあと思いました。いわば「圏論の実行例」。あるいは「圏論のクックブック」。もし何らかの事情で圏論について本当に「わかる」必要があるなら、体系的に書かれた教科書を読みながら紙と鉛筆で勉強するのが近道なんですが、そうやって教科書の証明を読み進めるときの「実行例」だけが本として、しかも圏論みたいな分野で出たということで、自分のなかでは「これはやられた!」一冊でした。

あなたの知らない超絶技巧プログラミングの世界

自分が過去に企画にできなかった本が企画化され、しかも想像以上に出来がいいのだから、「これはやられた!」一冊として選ばざるをえない。発売当時、くやしさをばねに紹介記事を書いたので、そちらを読んでください。

2016/01/08

英数字文字列を任意位置で改行するTeXパッケージを使う話

技術系のドキュメントでは、長い連続した英数字からなる文字列を等幅フォントで組む必要に迫られることが多々あります。 本文中にそんな文字列が連続して出現する原稿を、字間が異常に空いたり版面をはみ出したりすることなく組版するためのベストプラクティスは、有識者の間でも意見が分かれるようです。 うまく自然な改行位置に収まるように原稿のほうに手をいれられればベストですが、政治的経済的な理由で困難だったり、そもそも解説内容からして無理筋という場合もあります(Javaの変数名とかJavaの変数名とか)。

よくあるのは、空白やハイフンや記号文字の直後に恣意的な改行位置を指定する、という方法でしょう。 変数名を英単語の組み合わせだとみなすなら、この方法が自然に思えます。 キャメルケースの大文字の手前を恣意的な改行位置にすることもありうるでしょう。

しかし、「英単語として有意味な改行位置」は、このような文字列にとって必ずしも適切な改行位置ではないはずです。 たとえば、空白とかハイフンで区切ってしまうと、文字列のその部分に文字通り空白やハイフンがあるのか、たまたま改行があって空白やハイフネーション記号が挿入されているのか、区別しにくくなります。 キャメルケースの大文字の手前で改行されていると、その位置に文字通りの空白が入る可能性が気になって仕事になりません。 もちろん読者として読むなら意味を考えて区別できるんですが、作り手側にいると「勘違いして読まれたらまずいのでは」という不安をぬぐえないということです。

で、最近は、任意の文字間で改行するという思い切ったルールにするほうが理に適っているのではないかと考えるようになりました。 つまり、英数字の文字列ではあるけど、日本語や中国語のように組むわけです。 任意の音節区切りで改行くらいのほうが穏当な気もしますが、Webページだとword-wrap: break-word;が指定されている例も見かけるし、これをTeXでやってみようというのが本題です。

結論から言うと、seqsplitというパッケージがあります。もともとはDNAなんかの塩基配列を組むためのパッケージで、TeX Liveにも入ってます。 つまり、acgtの4文字からなる長大な文字列をページに組むことを目的にしています。 これを以下のような感じに使うことで、任意の位置で改行可能なバージョンの\textttが実現できます(実行例

\usepackage{seqsplit}
\usepackage{fancyvrb}
\VerbatimFootnotes

\makeatletter
% \def\seqinsert{\ifmmode\allowbreak\else\hspace{0pt plus 0.02em}\fi
\def\wordwraptt{\begingroup\obeyspaces\do@codeline}
\def\do@codeline#1{\texttt{\seqsplit{#1\relax}\endgroup}}
\makeatother

\begin{document}

Wikipediaによると、Brain*uckでは
\wordwraptt{%
++++++++[>++++[>++>+++>+++>+<<<<-]%
>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>%
.<-.<.+++.------.--------.>>+.>++.%
}というHello World!プログラムが書けます。

\end{document}

fancyvrbパッケージを読み込んでいるのは、\VerbatimFootnotesを使うためです。 このコマンドが提供するような仕組みがないと、\wordwrapttを脚注に配したときにスペースがなくなってしまいます。

改良したい点として、事前に中身の文字列を数えてあまり短いものは改行しないようにするといった処理もしたほうがよさそう。 (\penaltyによる調整は試してみたけれどあまりうまくいかなかった。)

なお、上記のような異常ケースでない場合は、Listingsというパッケージを使って\lstset{breaklines=true, breakatwhitespace=true}という設定をしてあげることで、そこそこ妥当な結果になるかもしれません。

(追記)さっそく改良案をいただきました。

あながちネタでもないと思っていて、似たようなことは考えていました(さすがに雪だるまをつかう発想はなかったけれど)。 上の例のコードブロックではコメントアウトしてある\seqinsertの再定義部分を書き換えると、このようなことが可能になります。


宣伝

TechBoosterがC89で頒布した6点のラインナップでは、上記のような仕組みを使うことで、Re:VIEWからでは制御困難な長い変数名の折り返し調整をなんとかしてみました。 が、コマンド中のスペースの存在を根本的に見逃すという大変残念かつ申し訳ない失敗をしています。本当にすみません。 電子版はなおっているはずなので、本誌に挿入されているQRコードでぜひ電子版も入手してください><

TechBooster in C89 特設ページ

というわけで、いろいろ微妙なTeXマクロだけど(LaTeXのことは知らない)、冒頭のツイートで思い出したのでネタとして。

2015/12/29

2016年賀状

年賀状書いた。
%!PS
(ps3d.inc) run
<< /PageSize [285 420] >> setpagedevice

-70 0 100 translate3d
[0 0 690 2] set-eye
[2 1 0.5] -45 rotate3d

/setrandcolor { % def
    /r1 {rand 5 mod 3 div} def
    /r2 {rand 4 mod 4 div} def
    /r3 {rand 3 mod 4 div} def
    r1 r2 r3 setrgbcolor
} def

/DS-Chocolade findfont [140 0 0 400 0 0] makefont setfont

1 1 20 { % for
  newpath
  0 1 20 { % for
    /y exch def
    0 y 320 mul moveto
    (2016) true charpath
  } for
  2d-path-convert
  clip
  gsave

  newpath
  0 20 300 { % for
    /x exch def
    /w 20 def
    gsave
      x 0 0 moveto3d
      x w add 0 0 lineto3d
      x w add 6000 0 lineto3d
      x 6000 0 lineto3d
      x 0 0 lineto3d
      closepath
      setrandcolor
      fill
      grestore
  } for

  grestore
  0.7 0 0.1 setrgbcolor
  stroke
  showpage
} for

2016.pdf by Keiichiro Shikano

今年はBill CasselmanさんのPostScript用3Dライブラリ ps3d.inc を利用しました(参照)。 使っているフォントは DS Chocolade。 スターウォーズは関係ないんだからね。

ps3d.inc はとても読みやすいソースで、しかも開発者のBillさん自身が Mathematical Illustration という本でわりと丁寧にマニュアルっぽいものを書いてくれているので、PostScriptで3Dを描いてみたい人にはお勧めです。 この本自体も、PostScriptを書きながら初等幾何も学べるという、実に面白い内容です(年に一回しか開かないけど)。 ただ、概説より先の解説はちょっと端折り気味なので、結局はこのライブラリの技術的根拠になっている Jim Bulin's Corners 1 も参照するはめになったけどな! ちなみに、Jim Bulin's Corners の vol.1 は元同僚が翻訳書(アフィリエイト)を出したので日本語で読めるんです。すごい。

過去のやつ。

2015/12/24

Re:VIEWな原稿のためのTeXフォーマットを作ってみたよ

tl:dr
  • これはTeX & LaTeX Advent Calendar 2015の24日目の記事である
  • Re:VEIW、LaTeXでPDFを作るんなら、そもそもRubyもRe:VIEWそのものも不要じゃない?
  • そこでRe:VIEW記法を直でコンパイルするTeXを作ってみた

(ここから本編)

今年の自分の仕事を軽く振り返ってみたところ、前職での最後の出版物となった『エクストリームプログラミング』をRe:VIEWを使って制作したり、無職になってから声を書けていただいた同人サークルTechBoosterの書籍制作でRe:VIEWが圧倒的に利用されていたり(年末のコミケで新刊解説書も売ってるよ!)、これまでになくRe:VIEWとの因縁めいた縁を感じる一年だった気がします。そこで、なにかRe:VIEWに関連したネタで記事が書けたらいいなあと思いました。

というわけで、TeX & LaTeX Advent Calendar 2015のためのネタとして、Re:VIEWとTeXがもっと仲良くなれるかもしれない方法を考えてみました。TeX & LaTeX Advent Calendar 2015の昨日12月23日の担当はdoraTeXさん、明日最終日の担当はzr_tex8rさんです。

さて、Re:VIEWの話を書くと決めたはいいものの、今年のTeX & LaTeX Advent Calendarには「今さら人に聞けない、TeXのキホン」という重点テーマが設定されています。Re:VIEWがTeXのキホンとは思えない。そこで、とりあえず形だけでも重点テーマを消化すべく、まずはTeXのキホンのひとつといえるアクティブ文字について説明することにします。TeXのキホンに興味がない人は「2. Re:VIEW風のシンタックスで書けるTeXを作ってみた」まで読み飛ばしてかまいません。

アクティブ文字とは

TeXとかLaTeXには、俗にいうマクロとかコマンドと呼ばれるものがあるのはご存じですよね。 バックスラッシュとか円記号の後ろに英文字が並んでるやつです。 このマクロとかコマンドを使って、ページに出力する要素の構造を指定したり、繰り返し入力する手間を省いたり、特殊な記号を入力したり、装飾を施したり、絵を描いたりできるのでした。

このマクロやコマンド、ほとんどの場合は「\から始まる文字列」(専門用語ではコントロールシーケンス)という形式の名前で定義するんですが、実はもう一つ方法があって、それが本節のテーマであるアクティブ文字です。 ようするに、単なる文字がまるでマクロやコマンドのように定義済みの内容に展開される機能がTeXにはあって、それをアクティブ文字と呼んでいます。

アクティブ文字「~」(チルダ)

アクティブ文字の代表例は「~」(チルダ)です。 ふつうのTeX環境における「~」には、HTMLにおける&nbsp;と同じく、ノーブレークスペースという機能が割り当てられています。 つまり、改行されるのは嫌だけどアキが欲しいような場所に「~」を挿入することで、TeXの組版処理を制御できます。

See Figure 1.1.  % 「Figure」と「1」の間で改行される可能性がある

See Figure1.1.   % 「Figure」と「1」の間で改行されないが、アキもない

See Figure~1.1.  % 「Figure」と「1」の間で改行されず、アキも入る

この挙動が、実はTeXの実装でハードコードされている機能ではなく、次のような感じでアクティブ文字「~」として「定義」されているというわけです。

\catcode`\~=13
\def~{\leavevmode\nobreak\ }

\catcodeというのが文字の種類(カテゴリコードと呼ばれています)を変更するためのTeXプリミティブで、「13」がアクティブ文字のカテゴリコードです。\catcodeで文字のカテゴリコードを13に変更すると、通常のコントロールシーケンス(バックスラッシュで始まる文字列で作れるやつ)とまったく同じ要領で、\defを使って動作を定義できます。

好きな文字をアクティブ文字に変更してみよう

もちろん、自分で好きな文字をアクティブ文字に変更して、その動作を好きなように定義することも可能です。 たとえば、「*」という文字を「\item 」に展開できると楽ができそうですよね。

\begingroup
\catcode`\*=13
\def*{\item }

\begin{itemize}
* 箇条書きが、
* こんなに、
* 書きやすく!
\end{itemize}
\endgroup
あるいは、文中の「8」という文字をすべて雪だるまにすると楽しそうですね(scsnowmanパッケージマジ便利)。
She's the last of the V8s!

\begingroup
\catcode`\8=13
\def8{\scsnowman[hat=true,muffler=red,arms=true]}

V8! V8!

\endgroup

問題は、こんなふうに気軽に「*」や「8」の意味を変えてしまうと、「*」や「8」という文字を本来の意味で使えなくなってしまうことです。とくに「*」は、文章中で使えないだけならまだしも(それだけでも困る場面はあるでしょうが)、\section*{連番なしの節タイトル}のような一般的なコマンドで使えなくなってしまうのは困ります。 実際、上記の2例では、\begingroup\endgroupを使うことで、これらがアクティブ文字として有効になるスコープを制限しています。

そんなわけで、こんなに便利で楽しいアクティブ文字ですが、ふつうにTeXやLaTeXで文章を書くときに利用できるものは最初に紹介した「~」のみです。残念ですね。 (改行文字を段落の終わりとして再定義して特定の環境内で暗黙に利用しているようなケースはあります。)

Re:VIEW風のシンタックスで書けるTeXを作ってみた

アクティブ文字で、なにかもっと面白いことはできないでしょうか。

前の節では、「*」という文字を再定義して\itemのように使う方法を紹介しました。 よく考えるとこれは、Re:VIEW記法における箇条書きのシンタックスそのものです。 ひょっとしたら、アクティブ文字をさらに駆使することで、バックスラッシュと波カッコというTeXやLaTeXの記法(悪名高い)に縛られずに原稿を執筆できるところまで持っていけるのではないでしょうか。いや持っていけるに違いない。

シンプルな箇条書きの記法

長い前置きはこれくらいにして、ここからはさまざまなRe:VIEW記法をTeXで実装していくことにしましょう。 まずはRe:VIEWの箇条書き記法をTeX上で再現してみます。

新しい段落が「*」で始まったらitemize環境に入り、新しい段落が出てきたら抜けて、その間に出てくる「*」は問答無用で\itemにするが、それ以外の「*」はそのまま印字する、という動作なら、*をアクティブ文字にしてこんな感じに書けそうです。

\newif\if@itemize
\chardef\active=13
\begingroup
\catcode`\*=\active
\gdef*{%
  \ifvmode\@itemizetrue\begin{itemize}
    \everypar={\end{itemize}\@itemizefalse}
  \fi
  \itemize@to@eol}%
\endgroup

\def\itemize@to@eol{\begingroup\catcode`\^^M=12 \@@itemize@to@eol}
{\catcode`\^^M=12 \catcode`\^^I=5 %
 \gdef\@@itemize@to@eol#1^^M{\review@itemize@head#1 \endgroup}}
\def\review@itemize@head{\if@itemize\item \else*\fi}

TeXやLaTeXのシンタックスは捨てることにしたので、ほかのコマンドに「*」が出てくる心配はいりません。 冒頭で\catcode`\*=\activeとして実際に文書を作成してみましょう。

ただしこの実装だと、同じ行に「*」が二回出てくるとおかしなことになったり、あとに何かしら段落が存在しないと意図しない結果になったりします。 本当ならもっと作りこむべきなのでしょうが、そもそも軽量マークアップ言語なんて制作者の技術的な都合で仕様が決まるものなんだから、ここはそういう仕様ということにして先に進みます。

Re:VIEWのインラインコマンド

Re:VIEWには@<command>{content}という形式のインラインコマンドがあります。 これを同様にアクティブ文字を濫用して実装してみましょう。

\begingroup
\catcode`\@=\active

\gdef\codereview{code}
\gdef\bfreview{b}

\gdef@<#1>#2{%
  \def\reviewname{#1}
  \ifx\codereview\reviewname\texttt{#2}\fi
  \ifx\bfreview\reviewname\textbf{#2}\fi}
\endgroup

こちらはTeXの記法に近い(?)ので比較的安直に実装できます。 上記では等幅にするコマンド(@<code>{...})と太字にするコマンド(@<b>{...})だけを定義していますが、必要に応じて好きなものを追加してください。

章見出しや節見出し

Re:VIEWでは「=」で行を書き始めると個数に応じて階層的なヘッダになります。 これをTeXで実装しましょう。めんどくさいですが、処理自体は素直なものです。

\begingroup
\catcode`\==\active
\gdef=#1#2{\let\@tmpa#1\let\@tmpb#2%
  \ifvmode \@headertrue\inc@header@cnt
    \ifcat\noexpand=\noexpand#1 \inc@header@cnt\let\@tmpa\relax
      \ifcat\noexpand=\noexpand#2 \inc@header@cnt\let\@tmpb\relax
  \fi\fi\fi
  \eq@protected\@tmpa\@tmpb}
\endgroup

\newif\if@header
\newcount\header@cnt
\def\inc@header@cnt{\global\advance\header@cnt by 1}
\def\reset@header@cnt{\global\header@cnt=-1}

\reset@header@cnt
\def\eq@protected{\if@header\proc@header\else =\fi}
\def\proc@header{%
  \expandafter\gen@header\header@cnt}
\def\gen@header#1{\@headerfalse%
  \ifcase #1 \review@chapter
  \or        \expandafter\review@section
  \or        \expandafter\review@subsection
  \fi\reset@header@cnt}
\def\review@chapter#1\par{\edef\chapstring{#1}\chapter[]{\chapstring}}
\def\review@section#1\par{\edef\sectstring{#1}\section[]{\sectstring}}
\def\review@subsection#1\par{\edef\subsectstring{#1}\subsection[]{\subsectstring}}
現状だとページの柱や目次に章タイトルを出力できないなどの問題は残っていますが、とりあえずできたということにします。
見出し行があるだけでずいぶんマークアップ言語っぽくなりますね。

Re:VIEWの環境

Re:VIEWでは//foo{から//}のような書式で特殊なスタイルのための環境を設定できるようになっています。 これもLaTeXの環境の記法に似ているので簡単に実現できるかなと思ったんですが、そもそもTeXには真のパターンマッチがないので、ややトリッキーな仕掛けが必要でした。

\begingroup
\catcode`\/=\active
\gdef//#1#{\begingroup\catcode`\/=\active\def//{}
  \csname review@#1\endcsname}
\endgroup

\long\def\review@list#1{\begin{alltt}#1\end{alltt}\endgroup}
\long\def\review@quote#1{\begin{quote}#1\end{quote}\endgroup}
\long\def\review@read#1{\begin{quote}#1\end{quote}\endgroup}
\def\review@footnote#1{\footnote{#1}\endgroup}

ここでちょっと悩ましいのが、よく似た記法を持つ//footnoteのようなRe:VIEWコマンド(波カッコがない点に注意)の存在です。これにも対応するには本気でパーザを書くことになりそうなので、//footnoteコマンドでもコンテンツは波カッコで囲むということにします。 つまり、この時点でRe:VIEWとは互換性のないシンタックスになってしまっていますが、軽量マークアップ言語なんて制作者の技術的な都合で仕様が決まるものなんだから(ry

あとなんかallttの中の改行処理がうまくいってないとか、入れ子への対応が不十分とか、課題は残ってるけど深追いしない。

Re:VIEWっぽい原稿をデフォルトでロードするTeXプログラムを作る

これらの定義をプリアンブルに書いたりスタイルファイルに書いたりして、LaTeXの \begin{document} ... \end{document} の間で実行するだけでも面白いといえば面白いのですが、どうせなら、.reファイルから直接PDFを組版できる独立したコマンドがあると便利ですよね。 というわけで、上記のマクロたちをフォーマットとしてまとめておきました。

revtex: TeX with Re:VIEW syntax
https://github.com/k16shikano/revtex

いちおう補足しておくと、TeXの文脈でフォーマットといったら、initexを使ってダンプする(あるいはダンプした)ファイルのことです。 そのフォーマットをデフォルトで利用するrevtexという新しいTeXの実行ファイルを作ることで、Re:VIEWっぽい記法の原稿を直接コンパイルできるようにしようというわけです。

日本語を組版したいので、ベースにするのはuplatexコマンドとします。 uplatexの実行ファイルをrevtexという別名で用意し、上記のフォーマットをかませて使うように設定すれば、こんなふうにTeXで直接、ほぼRe:VIEW記法の原稿をコンパイルできるようになります。

$ ls -la /usr/bin/revtex # revtexはuplatexのシンボリックリンク
lrwxrwxrwx 1 root root 16 Dec 22 12:28 /usr/bin/revtex -> /usr/bin/uplatex
$ cat sample.re          # sample.reは(ほぼ)Re:VEIW記法のファイル
= はじめてのUNIX

== 実際すごい

重金属を含んだ酸性雨が降りしきるなかをものともせず、
@<b>{マグロツェッペリン}//footnote{巨大飛行船}が回遊する!

* ネオサイタマ
* マルノウチ・スゴイタカイビル

その頂から退廃的な高密度ネオン看板が瞬く地獄めいた都市の喧噪を見下ろす影がひとつ急降下した。コワイ!

== もっとすごい

「こんにちはニンジャ・スレイヤー=サン。」
そういって敵は姿を見せぬまま@<code>{UNIX}端末にログインした。

= インガオホー

こんにちはダークニンジャ=サン。ハイクを詠め!

//quote{
トチノキ、フユコ……
}

#@# fin
$ revtex sample.re       # ほぼRe:VIEWな原稿がTeXでコンパイルされる
This is e-upTeX, Version 3.14159265-p3.6-u1.20-141210-2.6 (utf8.uptex) (TeX Live 2015/Debian) (preloaded format=revtex)
 restricted \write18 enabled.

kpathsea: Running mktexfmt revtex.fmt
...

いうまでもありませんがRubyもRe:VIEWも不要です。最後にdvipdfmxが何か言ってますが、無視する方向で。 生成されたPDFを以下に張っておきます。

画期的ですね。

実は、少なくともひとつ、どうにも解決できないダサい制限があって、原稿ファイルの末尾にオリジナルのRe:VIEWではコメントとして無視される「#@# fin」という行を書いておく必要があります。 TeXは組版をするとき、\endというプリミティブで原稿ファイルの終端に到達したことを知るのですが、Re:VIEWにはそのための記法がないので、こうしてお茶を濁しているわけです。

(追記) と思い込んでいたら、e拡張には\everyeofなるそのまんまなプリミティブがあると教えてもらいました。 これを使うと、確かに最後の行が不要になるので、ひそかにあきらめていた行コメントも実現できました。(追記おわり)

免責と今後の展望

auxによる参照解決とか、エスケープとか、いろいろさぼってるので実用品ではありません。 また、これ以上Re:VIEW対応率をあげようとか、バグを直そうとか、そういう予定もたぶんありません。 むしろ、あらためてMarkdownっぽいのを実装するほうが面白そうかも。

参考資料

TeX by Topic
TeX芸には欠かせない説明不要の名著。日本語訳もあるが入手は困難。原著者のサイトで英文なら全部読める。
1TeXの実装
TeX芸の北極。文字「1」をアクティブ文字にすることで、文字通り「1」のみでTeXコンパイル可能な文書を作る。
xmltexの実装
XML文書をTeXでコンパイルするという、海外のTeX芸のひとつ。
Re:VIEWフォーマットのドキュメント
これ以外にもいろいろ隠しコマンドがあるらしい。

2015/09/24

『あなたの知らない超絶技巧プログラミングの世界』は誰が読むべきか

遠藤侑介さんといえば、Quineをはじめとする変態プログラムの世界的なタツジンとして有名ですが、そのむかし遠藤さんに向かって「Quineの本とか、売れないことが確実ですね」という趣旨の発言をしたことがあります。遠藤さんがブログやコンテストで発表していた変態プログラムには個人的にとても魅力を感じていて、翻訳書で一緒にお仕事をする前から楽しませてもらっていたのですが、さすがに書籍の企画ネタにするのは難しいなあ(売れるようにするのが難しいという意味で)と思っていたのです。それから数年後、まさか本当にQuineの書き方の解説が載っている本が出版されるなんて! それもQuineのみならず、遠藤さんのネタを徹底解説するような本がでるなんて! 企画を担当した編集者もずいぶんな変態に違いありません。というわけで、今月発売された遠藤侑介著『あなたの知らない超絶技巧プログラミングの世界』という本をさっそく読みました(下のリンクはアマゾンで、9/24現在ではまだ予約中だけど、なぜか都内の大型書店にはふつうに配本されている)。

読んだといっても、ざっと目を通したレベルであって、内容をきちんと咀嚼できるほどには読み込んでいません。というか、本書の内容をきちんと咀嚼できる日が自分の人生にやってくるのだろうか、というのが率直ないまの気持ちです。なにせ本書は、いうなればリストやパガニーニが懇切丁寧に自分の楽器演奏テクニックを言語化して解説してくれているようなものです(実際、本書のタイトルの「超絶技巧」はリストの同名の練習曲に由来するようです)。あるいは、シューマッハが自分のドライビングテクニックを教本としてまとめてくれているようなものです。そんなもの、本を読んだくらいで習得できるわけがないじゃないか! その意味では、この本、けっして「わかりやすい」とは言えないと思います。むしろ「わからない」ことをわざわざ楽しむための本なので、「わかりやすくない」のが必然なんでしょう。解説自体はとても丁寧に書かれているので、必要になったときに必要な箇所を真剣に読めば大丈夫そうだなと判断して順調に読み飛ばしました。にしても、この本の内容が「必要になるとき」なんて自分にあるんだろうか……。(という読者の葛藤を見越して「必要になるとき」を強制発動するための「練習問題」がついているところに著者の心意気を感じました。)

「この本が必要なのは誰だろう」という、おそらく書籍企画にとって根源的な問題は、著者の遠藤さんをだいぶ悩ませたんではないかと思います。本文を読んでいると「実益は期待しないで」といった趣旨の開き直りにちょくちょく出くわすし、「まえがき」に至っては「実用性という観点は雑念」とまで言い切られています。でも、「雑念」だと言った鼻の先が乾かないうちに「ある種の気づきを与えてくれる」とか言って実用性がほのめかされています。

じゃあ、この本、いったい誰が読むべきなんでしょうか? 独断ですが、本書の対象読者は大きく次の3つに設定できる気がします。

1. 超絶技巧なプログラムをでたい人
たぶんこの本のいちばんありがちな楽しみ方は「めでる」でしょう。実際、第1章は超絶技巧プログラムを眺めて楽しむという位置づけだし、後続の章も眺めているだけで楽しくなります。『Core Memory ― ヴィンテージコンピュータの美』なんかと同様に、計算機とその周辺にある種の美を感じる人はとりあえず購入して損はしないはずです。
2. 超絶ではないにせよプログラミングの技巧に興味がある人
この本は、Quineのようなプログラムを書きたい人だけでなく、ある種の技巧的なプログラムを書きたい人にとってはそこそこ実用的です。たとえば、CUIのアプリでアニメーションをする方法のような実用的で具体的な内容が丁寧に解説されている本は、ほかにあまりない気がします。また、zlibを使わずにPNGを作る例など、プログラミングに必要な潔さ(教科書には書いていない)を学べます。プログラミングコンテストとかで応用できたりできなかったりする気がします。出たことがないので憶測です。
3. 計算機科学とか数学基礎論が好物な人
数学基礎論や計算機科学の深めの話に踏み込んだコラムの数々が実に有益な読みどころです。Quineの存在証明をRubyで書き下してくれている本なんて、たぶん世界中でほかにはなかったし、これからもないと思います。デュードニーの『チューリングオムニバス』とか、まだ翻訳が出ていないけど『Good Math: A Geek's Guide to the Beauty of Numbers, Logic, and Computation (Pragmatic Programmers)』とかが大好きな人はコラムだけでも興奮できると思います。

無理やりまとめると、本書は(ほぼ)世界一の人がそのテクニックを披露し、伝授してくれて、さらに深堀するという貴重な本です。遠藤さんが書いたこの本を読みたい人は世界中に少なからずいるでしょう。いまのところ本書は日本語でしか楽しめないので、日本語ネイティブで本当によかった。9月28日にはジュンク堂池袋店でサイン会もあるそうなので、Quineなサインをもらいにいこうと思います。

なお、全体を通してRubyがメインで使われているので「Ruby限定の内輪テクニック集」に見えるかもしれませんが、それに終始する本ではないのはさすが遠藤さんだと思いました。唯一残念なのは索引がないところです(上記の2と3が対象読者なら必須だと思う)。あと細かい話ですが、Paul Grahamのカタカナ表記は「ポール・グレアム」のほうがいいと思いました。

2015/09/10

Wikipediaのエントリを束ねてEPUBを作れるようにしてみた

Wikipediaには好きなページを集めて本を作れる機能があります。左側のメニューにある[印刷/書き出し]から[ブックの新規作成]というメニューをクリックすると、それ以降に閲覧する各ページで「ブッククリエーター」というツールバーが以下のような感じで有効になって、そのツールバーで自分が本に収めたいページを追加していけるという機能です。追加したページを並べて自分だけのオリジナルの本が作れます、というサービスです。

で、何年か前はこのブッククリエーターの出力形式としてPDFのほかにEPUBを選べたのですが(参考)、いつの間にかPDFとプレーンテキストのみになってしまっていてEPUBを作れません。これは日本語版だけでなく英語版でも同様です。

べつにWikipediaをEPUBで読めないからといって困ることはないのですが、自分が開発して自分で使っているEPUB作成ツールのテスト用にWikipediaのページを使えたらいいなと思って、Wikipediaのエントリをいくつか指定してEPUBを生成できる仕組みを作ってみました(参考)。動機が動機なのでローカルでのみ使うつもりだったのですが、AWSでデモが動くようにしてみました(ただしエントリの上限を3つにしているので3章までの本しか作れません。ダウンしてたらごめんなさい。あと英語版Wikipediaのみに対応)。

以下のような感じにEPUBが生成されてダウンロードできるようになるはずですが、Mediawikiのパーズで力尽きたので、WebアプリとしてもEPUBジェネレータとしてもまだぐだぐだです。低品質の勧めに従って公開してみます。

2015/09/01

職務経歴書

いろいろあって職務経歴書を作成してみることにしました。お便りお待ちしています!

要約すると

理工系出版社の開発部という部署で約13年間半、主にコンピュータネットワークとプログラミングの本を企画し、制作してきました(企画制作に携わった主なコンテンツ」および「企画者として公式に社内に名前が出ている、かつ、制作でも中心だった書籍の一覧」を参照)。 特にTCP/IP関連書籍と、翻訳技術書は、たくさんの技術者の方に手に取ってもらえた(願わくば役に立てた)と思います。

読者が読んだことを後悔しない本を作るのは当然として、著者や訳者が出版したことを後悔することがないように、編集制作プロセスの透明化にも努めました。 通常、著者や訳者は、出版物に対する責任があるにもかかわらず、その最終的なデータを手にすることがありません。 著者による校正の終了後に編集者が内容のデグレにつながるような修正を勝手に加えてしまった、という話もよく聞きます。 そのような悲劇を駆逐するため、すべての制作データをSubversionやGitのリポジトリを介して著者と最後まで共有し、ありとあらゆる編集内容が全員にとって透明な制作フローを採用しました(バージョン管理システムを利用した制作システムの開発・運用」を参照)。

この制作フローにとって欠かせないのが、誰かが作業をリポジトリに反映するたびに最終的な本と同じ組版結果が自動的に生成される仕組みです。 書籍の構成や組版は毎回異なるので、そのような仕組みを実際の現場で運用していくために、自分でカスタマイズしやすい自動組版システムを開発しました(社外での活動」を参照)。 必然的に、プロジェクト単位ではありますが、夢のワンソース・マルチアウトプットも実現しました。 直近の書籍の多くでは、印刷用PDFとデータ販売用PDFに加え、EPUBも単一のソースからmake一発で生成しています。

さらに、TracのチケットやGitHubのissueおよびPull Requestを活用することで、編集に必要な意見のすり合わせにかかるコストを大幅に低減しました。

これらの取り組みにより、原稿の頻繁な見直しが可能になったことで、書籍の品質が大きく向上しました。 著者と編集者(組版者)との意思疎通に起因する書籍の不具合もほぼゼロにできました。 多人数が同時に並行して書籍制作に関与できることから、外部レビュアーによる協力も得やすくなり、書籍内容のさらなる改善にもつながりました。 書籍制作にかかる時間的および金銭的コストも大幅に削減できました。

制作に携わった書籍のプロモーションも積極的に行いました。 いまどき、どんなに自分が良い本を作ったつもりでも、潜在的な読者にその本の存在が伝わらなければ読んでもらえません。 書籍の内容を、必要な人に、できるだけ魅力的に伝えるべく、会社のブログや個人のツイッター/ブログ(これな)を使ってアピールしました。

もう一つ、自分の企画や制作とはまったく別の話として、他者の企画書籍に対するサポートにも貢献しました。 具体的には、著者あるいは原稿にとって適切な目次構成案を提案したり、より販売力のある書名を考案したり、カバーの選定に協力したりしました。 特にマンガを用いた技術書シリーズでは、コンセプトに対する提言やコンテンツの技術査読を担いました。

企画制作に携わった主なコンテンツ

以降、書籍などのリンク先は、無職につきすべてAmazonアソシエイトです。

バージョン管理システムを利用した制作システムの開発・運用

  • 原稿執筆段階から印刷所入稿に至るまで、すべての制作データをGit/Subversionを利用してバージョン管理
  • それを実現するため、原稿の多様なマークアップに対応可能なXML→LaTeX変換プログラム(後述するxml2tex)を利用した自動組版システムの構築
  • LaTeXを含む多彩なマークアップ原稿からのEPUB生成
  • LaTeX組版用の標準的なクラスファイル作成

geekなページのあきみちさん(『インターネットのカタチ―もろさが織り成す粘り強い世界―』の主著者)が、この制作フローについてのわかりやすい説明記事を書いてくださいました(「svn+TeXでcommitするとPDF - オーム社開発部の出版システムでの書籍執筆」)。ただし原稿の形式は(La)TeXとは限りません。また、ちょっと前の記事なのでSubversionベースとなっていますが、最終的にはGitHubベースのシステムを使っていました)。

社外での活動

  • XML風のデータ構造を、直感的なルールにより任意のマークアップへとシリアライズするためのプログラム xml2tex の開発
  • 野良XMLを束ねてEPUB化するためのプログラム qnda の開発
  • 2013年TeX User Group年次総会でのチュートリアル講演("Index makes your book perfect"

企画者として公式に社内に名前が出ている、かつ、制作でも中心だった書籍の一覧

2006年以降は、ほとんどの制作も自分でやっています(自動組版でな)。 このほか、企画に名前が出ているけど制作はほかの人がやった本、どこにも名前が出ていないけど全部制作した本、タイトルや目次構成を提供した本、技術査読をした本などが無数にあります。

  1. エクストリームプログラミングKent Beck, Cynthia Andres, 角 征典, 2015/6/25
  2. 基礎からわかるTCP/IP ネットワークコンピューティング入門 第3版 村山 公保, 2015/2/25
  3. 関数プログラミング 珠玉のアルゴリズムデザイン, 山下 伸夫, 2014/11/11
  4. 新装版 リファクタリング―既存のコードを安全に改善する― (OBJECT TECHNOLOGY SERIES) Martin Fowler, 児玉 公信, 友野 晶夫, 平澤 章, 梅澤 真史, 2014/7/25
  5. すごいErlangゆかいに学ぼう! Fred Hebert, 山口 能迪, 2014/7/3
  6. たのしいプログラミング Pythonではじめよう! Jason R.Briggs, 磯 蘭水, 藤永 奈保子, 鈴木 悠,2014/2/25
  7. マスタリングTCP/IP 情報セキュリティ編 齋藤 孝道 2013/8/30
  8. マスタリングTCP/IP OpenFlow編 あきみち, 宮永 直樹, 岩田 淳 2013/7/25
  9. マスタリングTCP/IP IPv6編 第2版 井上 博之, 黒木 秀和, 小林 直行, 志田 智, 鈴木 暢, 矢野 ミチル 2013/7/23
  10. 型システム入門 −プログラミング言語と型の理論− Benjamin C. Pierce, 住井 英二郎, 遠藤 侑介, 酒井 政裕, 今井 敬吾, 黒木 裕介, 今井 宜洋, 才川 隆文, 今井 健男, 2013/3/25
  11. ディジタル作法 −カーニハン先生の「情報」教室− Brian W. Kernighan, 久野 靖, 2013/2/25
  12. レジデント初期研修用資料 内科診療ヒントブック 改訂2版 medtoolz 2012/11/22
  13. 関数プログラミング入門 ―Haskellで学ぶ原理と技法― Richard Bird, 山下伸夫, 2012/10/25
  14. すごいHaskellたのしく学ぼう! Miran Lipovača, 田中 英行, 村主 崇行, 2012/5/22
  15. マスタリングTCP/IP 入門編 第5版 竹下 隆史, 村山 公保, 荒井 透, 苅田 幸雄 2012/2/24
  16. RailsによるアジャイルWebアプリケーション開発 第4版 Sam Ruby, Dave Thomas, David Heinemeier Hansson,前田 修吾, 2011/11/30
  17. 抽象によるソフトウェア設計−Alloyではじめる形式手法− Daniel Jackson中島 震, 今井 健男, 酒井 政裕, 遠藤 侑介, 片岡 欣夫,2011/7/14,
  18. インターネットのカタチ―もろさが織り成す粘り強い世界― あきみち, 空閑 洋平 2011/6/24
  19. Scheme修行 Daniel P. Friedman and Matthias Felleisen, 元吉 文男, 横山 晶一, 2011/6/14
  20. Coders at Work プログラミングの技をめぐる探求 Peter Seibel, 青木 靖, 2011/5/24
  21. レジデント初期研修用資料 医療とコミュニケーションについて medtoolz 2011/1/24
  22. Scheme手習い Daniel P. Friedman, Matthias Felleisen, 元吉 文男, 横山 晶一, 2010/10/22
  23. 関数プログラミングの楽しみ Jeremy Gibbons and Oege de Moor, 山下 伸夫, 2010/6/22
  24. レジデント初期研修用資料 内科診療ヒントブック medtoolz 2010/3/19
  25. 情熱プログラマー ソフトウェア開発者の幸せな生き方 Chad Fowler, でびあんぐる, 2010/2/25
  26. RailsによるアジャイルWebアプリケーション開発 第3版 Sam Ruby, David Heinemeier Hansson, Dave Thomas,前田 修吾,2009/11/30
  27. プログラミングHaskell Graham Hutton, 山本 和彦, 2009/11/10
  28. プログラミングのための確率統計 平岡 和幸, 堀 玄 2009/10/22
  29. 入門git Travis Swicegood , でびあんぐる, 2009/8/11
  30. Release It! 本番用ソフトウェア製品の設計とデプロイのために Michael T. Nygard, でびあんぐる, 2009/2/20
  31. Manage It! 現場開発者のための達人式プロジェクトマネジメント Johanna Rothman, でびあんぐる, 2008/10/17
  32. 実践Common Lisp Peter Seibel, 佐野匡俊, 水丸淳, 園城雅之, 金子祐介, 2008/7/25
  33. アートのための数学 牟田 淳 2008/5/20
  34. プログラミングErlang Joe Armstrong, 榊原一矢, 2008/2/22
  35. アジャイルプラクティス 達人プログラマに学ぶ現場開発者の習慣 Venkat Subramaniam, Andy Hunt, 木下 史彦, 角谷 信太郎, 2007/12/21,
  36. RailsによるアジャイルWebアプリケーション開発 第2版 Dave Thomas, David Heinemeier Hansson ,前田 修吾, 2007/10/25
  37. アジャイルレトロスペクティブズ 強いチームを育てる「ふりかえり」の手引き Esther Derby, Diana Larsen, 角 征典, 2007/9/25
  38. 基礎からわかるTCP/IP―ネットワークコンピューティング入門 第2版(村山 公保) 2007/8/23
  39. Subversion実践入門:達人プログラマに学ぶバージョン管理(第2版) Mike Mason, でびあんぐる, 2007/4/20
  40. マスタリングTCP/IP 入門編 第4版 竹下 隆史, 村山 公保, 荒井 透, 苅田 幸雄 2007/2/23
  41. マスタリングTCP/IP ルーティング編 山川 秀人, 水谷 昭博, 亀野 英孝, 森 明治 2007/2/23
  42. My Job Went To India オフショア時代のソフトウェア開発者サバイバルガイド Chad Fowler, でびあんぐる, 2006/9/25
  43. Ship It! ソフトウェアプロジェクト 成功のための達人式ガイドブック Jared Richardson, William Gwaltney Jr., でびあんぐる, 2006/8/24
  44. Building Secure Software―ソフトウェアセキュリティについて開発者が知っているべきこと John Viega, Gary McGraw, 齋藤 孝道, 2006/7/21
  45. マスタリングTCP/IP IPsec編 谷口 功, 水澤 紀子 2006/5/23
  46. RailsによるアジャイルWebアプリケーション開発前田 修吾, 2006/2/24
  47. Joel on Software Joel Spolsky, 青木 靖, 2005/12/20
  48. Excelで学ぶ株式投資―Excelで実践する、銘柄の選び方からテクニカル分析の基本、シミュレーション(バックテスト)まで 2005/10/18
  49. マスタリングTCP/IP SNMP編 緒方 亮, 矢野 ミチル, 鈴木 暢 2005/9/21
  50. ネットワークの考え方―ルータとスイッチは何が違う?戸根 勤2005/6/14
  51. ITRONプログラミング入門―H8マイコンとHOSで始める組み込み開発 濱原 和明 2005/4/22
  52. マスタリングTCP/IP IPv6編 IRIユビキタス研究所 2005/2/10
  53. プログラミングのための線形代数 平岡 和幸, 堀 玄 2004/10/25
  54. OpenSSL―暗号・PKI・SSL/TLSライブラリの詳細― John Viega, Matt Messier, Pravir Chandra, 齋藤 孝道,) 2004/8/20
  55. BGP―TCP/IPルーティングとオペレーションの実際 Iljitsch van Beijnum, 近藤 邦昭, 2004/7/23
  56. マスタリングTCP/IP RTP編 Colin Perkins, 小川 晃通, 2004/4/20
  57. スティーリング・ザ・ネットワーク―いかにしてネットワークは侵入されるか Ryan Russell, Dan "Effugas" Kaminsky, Joe Grand, Mark Burnett, Paul Craig, 増田 智一 2004/3/25
  58. 基礎からわかるTCP/IP SIPによるVoIPプログラミング―Linux対応 マッキーソフト 2004/3/19
  59. マスタリングTCP/IP SSL/TLS編 Eric Rescorla,齋藤 孝道, 古森 貞, 鬼頭 利之 2003/11/27
  60. 基礎から学ぶ Webデータベースプログラミング 2003/9/22
  61. マスタリングTCP/IP ネットワークデザイン編 Tony Kenyon, 苅田 幸雄 2003/9/19
  62. TCP/IPソケットプログラミング Java編 Kenneth L. Calvert, Michael J. Donahoo, 小高 知宏, 2003/5/23
  63. TCP/IPソケットプログラミング C言語編 Michael J. Donahoo, Kenneth L. Calvert, 小高 知宏, 2003/5/23
  64. 基礎から学ぶ PerlによるWebサイト管理 John Callender, 湊 規生, 森 弘之2003/5/22
  65. 基礎から学ぶ PerlによるWebプログラミング John Callender, 湊 規生, ソシオメディア 2003/4/24
  66. 基礎から学ぶ CGIプログラミング渡辺 恭成2003/2/24
  67. マスタリングTCP/IP SIP編 Henry Sinnreich, Alan B. Johnston , 株式会社ソフトフロント, 2002/10/23
  68. Excelで学ぶテキストマイニング入門林 俊克 2002/10/22
  69. Ruby Magic ― Rubyで極める正規表現竹内 仁2002/9/24

企画制作についてのふりかえり

前に勤めていた会社がなくなって、「マスタリングTCP/IPみたいな本を作ってる人がいる会社なら大丈夫だろう」くらいの感覚で応募書類を送ったのが2001年。 ちなみに当時のマスタリングTCP/IPシリーズは、「入門編 第2版」と「応用編」、それになぜか「マルチキャスト編」というラインナップでした。

入社試験で「本の企画を書け」と言われた気がした(のちに誤解だったと判明)ので、『マスタリングMPLS』という本の企画書をでっちあげて提出したところ、たまたま当時の開発部で『マスタリングTCP/IP MPLS編』の新刊制作が進行中というタイミングだったらしく、そんな縁もあって「マスタリングTCP/IP」の企画制作をやっていた「開発部」に配属されました。その後は、ずっと開発部で本を作ってきました。

入社後すぐに企画したのはSIPの解説書でした。 ちょうどVoIPとかIP QoS制御とかをキャリア網でも本気でやろうっていう機運があったころで、SIP解説書の企画とかぜったいあるだろうと思ってたのですが、社内の誰もSIPすら知らないという真空状態だったので、自分でやることになったのです。 いま思い返すと、この本(『マスタリングTCP/IP SIP編』)の企画制作をとおして、「需要がありそうな技術の解説書を計画し、適切な著者や監修者を探して、制作して売る」という商売の基本的な流れを学んだ気がします。 幸いにして、とてもたくさんの方に読んでもらいました。

最初の年は、平行して半持ち込み企画もいくつか担当しました。 なかでも『Excelで学ぶ テキストマイニング入門』と『Ruby Magic Rubyで極める正規表現』は、かなり手を入れた思い出があります。 特に後者は、自分がRubyを学ぶきっかけになりました(それまではPerlを使っていた)。

こうして振り返ると、「マスタリングTCP/IP」シリーズの担当者みたいな立ち位置が固まってきたのは入社2年目の2003年だったようです。 当時のシリーズは、自分の入社時にちょうど第3版が出版された「入門編」こそメンテが続いていたものの、おなじタイミングで出版された「MPLS編」のほうはあまり芳しくありませんでした。 そんな中で、「SIP編」の成功をきっかけに、なんとなく自分がテコ入れをはじめることになったのだと思います。

手始めに着手したのは、なぜか日本語の解説書がなかったプロトコルの「SSL/TLS編」と「RTP編」でした (『マスタリングTCP/IP RTP編』は、書籍そのもの以上に、あきみちさんとはじめて仕事できたという意味で自分にとっては大きな出来事でした)。 さらに、もうちょっと低レイヤの解説も欲しいよねということで「ネットワークデザイン編」を企画。 マスタリングTCP/IPという枠ではフォローできてなかったソケットプログラミングの入門書も企画しました。

余談ですが、このころは外部のプロダクションに依頼して普通にDTPで本を作ってもらっていました。 でも、著者校でどうしても入る修正による手戻りの絶望的な困難さを回避したくて、「SSL/TLS編」と「RTP編」では自分で原稿をHTML化してCSSでゼロ校を作り、それを最初の著者校にするという進行を導入していました。 このへんの経験は、後年、XML版管理+LaTeXによる自動組版で生きてきます。

この入社2年目には企画の失敗も経験しました。 Web周りの入門書も必要だよね、という素朴な発想で、CGIとかサイト管理の入門書も何冊か企画したのですが、どれもあまり成功しませんでした。 あまりほめられた話ではないかもだけど、これらを通して「技術書の企画に失敗する方法」を学べたと自覚しています(この年以降で赤字に終わった企画は1冊だけです。えへん)。

翌2004年は、いまになって思うと、このあと数年間の技術書企画制作者としての道を決定づける仕事ばかりだった一年でした。 なんといっても大きいのは『プログラミングのための線形代数』で、この本の企画制作では著者の二人から本当にたくさんのことを学びました。 「コンピュータ書のように読める数学の教科書が作りたい」という恥ずかしいほど素朴な思い付きだけで平岡さんに話を持ちこんだら鳥肌が立つような原稿が書きあがってきたのは、今思い返しても興奮する体験です。 LaTeXで本を作ったのも、轟木さんにカバーをお願いしたのも、原稿の版管理(CVSだけど)を始めたのも、この本が最初でした。

メイン企画者ではないのだけど、『マンガでわかる統計学』の企画立ち上げや技術レビューにかかわったのも2004年でした。

2005年は、引き続きマスタリングTCP/IPシリーズの拡充や、『Joel on Software』とか『ITRONプログラミング入門』といった自分にとって名刺代わりになるラインナップを少しずつ増やしていった年だったようです。

2006年は、XML原稿からのLaTeXによる自動組版で売り物になる本を作った最初の年でした。それが『RailsによるアジャイルWebアプリケーション開発』です。 この本の原著出版社であるPragProg社では、独自のXMLを原稿の形式にしていて、これを翻訳版でもそのまま最大限に使ってやろうと思って正月にGaucheでLaTeXへのコンバータを書いたのでした。 同じ年の『Ship It!』と『My Job Went To India』も、やはりPragProg社の本の翻訳だったので、このときの仕組みをそっくり流用して制作しました。

でも、この年でいちばん学ぶところが大きかった本は『Building Secure Software』でしょう。 自分の企画でもっとも大きな赤字を出した本です。 この本からは、内容の良さと利益はまったく相関しないんだという事実を思い知りました。

翌2007年あたりから、だんだん、作りたい本を作りたい形に作れるようになってきた気がします。 2008年の『実践Common Lisp』と『プログラミングErlang』のように、爆発的には売れないけど意義があったりブランドにつながったりする本(しかも着実に利益が出る本)を企画できるようになってきました。 2007年末のオブジェクト倶楽部のイベントで自分たちの本の作り方をプレゼンする機会があったり(登壇したのは同じチームの高尾さん。スライドは自分が作った)、 Gauche Night 2008で発表したり、アジャイル界隈の方々やLisp界隈の方々に少しずつ自分たちチームの存在を認知してもらい始めたころです。

2009年には、企画構想から長いことかかった『プログラミングのための確率統計』がついに形になったり、趣味で読んでた"Programming Haskell"が翻訳企画になったり、自分たちの制作環境でSubversionからの移行を始めていたGitの解説書を出せたり、いろいろタイミングが良かった年でした。 発行はこの翌年になる『内科診療ヒントブック』の話を、ブログの一読者として一方的に知っていたmedtoolzさんからいただいたのも、この年のことです。 『Scheme手習い』とか『関数プログラミングの楽しみ』とかを通して、価値があると信じる本だけで商売ができるし、そうすべきなんだなという実感を強めました。

2010年以降も、マスタリングTCP/IPシリーズのメンテと拡充を続けながら、"The Little Schemer"の翻訳とか、『インターネットのカタチ』、『すごいHaskell』、TAPLの翻訳、Bird先生の関数プログラミング本の翻訳、あのカーニハン先生の著書などなど、ものすごい経歴の著者訳者の方々と一緒に、内容も責任も重い、でも楽しい仕事をたくさんしてきました。 それまで手探り状態でがんばっていた自動組版化も、良い意味でルーチン化でき、効率よくチームで仕事を回せていたと思います。 最後の数年は、自分たちのチーム以外の企画も技術面でサポートできる余裕もでき、開発部全体でよい仕事ができていたと思います。

2015/06/28

Re:VIEWで売り物の本を作ってみた(InDesign抜き)

本を作って出版する仕事をしています。 今回、はじめてRe:VIEWを実際の仕事に使ってみたので、忘れないうちに感想とメモを殴り書きしておきます。 ちなみに、作ったのは『エクストリームプログラミング』という本です。

公式サイトのREADMEに「an easy-to-use digital publishing system for books and ebooks」とあるように、 Re:VIEWは日本語の技術書をできるだけ簡単に作るための仕組みです。 テキスト原稿に比較的簡便なマークアップをマニュアルどおりに施し、本全体の構造をYAMLに書けば、それなりに体裁が整った日本語の技術書PDFを編纂してくれます。 同じソースからepubも出せます。InDesignへネイティブに取り込めるような出力もはけるので、テキスト原稿をInDesignに流し込んでバッチ組版とかも可能です。 自分が今回使ったのは、主にpLaTeXを介したPDFの出力機能なので、以降はその話だけします。

「Re:VIEW、わりといいじゃん」と思ったところ

Re:VIEW以外にも、マークアップされたテキスト原稿から書籍PDFを編纂できる仕組みはいくつもあります。 実際、自分も普段はまったく別のツール群を使っています。 Re:VIEWでなければできないことは、特にありません。

Re:VIEWが他のツールに比べて勝っている点は、「それなりに体裁の整った日本語の技術書」がわりと気楽に作れることでしょう。 理由は主に2つあると思います。

とにかくデフォルトの設定だけで、それなりに本の形になる

本の執筆は、ある程度まとまった形になって人に見せられる段階になるまで、どうしても孤独な集中力が要求される作業です。 そんなときに進捗をあきらめないための方策として有効なのは、「自分が書いた文章が本っぽい形になってるようす」をときどき見てにやにやすることでしょう。

Re:VIEWと似た仕組みを提供するツールとしては、Sphinxもあります。 SphinxもRe:VIEWも、原稿を執筆するだけで継続的インテグレーションの開始まで一瞬でもっていけるという点について、優劣はありません。 ただし、そこから実際に本として作り込んでいくところで、かなり使い勝手が変わると思います。 作り込みには、それぞれPythonなりRubyなりを必然的に使うことになるので、そのへんの好みにもよるでしょう。

これは完全に主観ですが、日本語の技術書を書いてみたい、拡張とかいっさい興味ない、という場合、Re:VIEWはよい選択肢です。 まっさらなつるしの状態でツールを使って日本語の技術書らしい体裁を得るなら、いまのところRe:VIEWがいちばん簡単な手段に思えます。 技術書界のRuby on Railsと呼んでもいいかもしれません。

マークアップが妥当

エディタでテキストを編集しているときの見た目は、そのテキストから生成される本のレイアウトに期待するものだと助かります。 InDesignのようなWISIWYGは不要というか邪魔ですが、マークアップとその出力結果には、なるべく自然な対応がついていてほしい。 太字にするつもりだったところが数式として扱われるとか、意図しないところに空白が発生するとか、そういうのは困ります。 Re:VIEWのマークアップとその処理系には、好き嫌いは別にして、そのような問題はあまりありません。

また、どうしても視界にまぎれてくるタグやインデントは、なるべく気が散らない見た目で、なおかつ本文とは違う性質の要素であることが明確にわかるものであってほしい。 この要求をいちばんうまく実装しているマークアップは、たぶんMarkdownでしょう。 しかしMarkdownそのものにはマークアップを拡張するための標準的な仕組みがなく、拡張はすなわち新しい方言の創造を意味します。 これは地獄です。その点、Re:VIEWには、好き嫌いは別にして、標準的なマークアップ拡張の仕組みがあります。

テキスト原稿に対するマークアップに何を選択するかは、宗教化しているかもしれないので断言しにくいのですが、 日本語の技術書を執筆するという目的がはっきりしているならRe:VIEWが採用しているマークアップは妥当だと思いました。

Re:VIEWで商業出版の本を作る

ここから先は、デフォルトのRe:VIEWで作れるPDFでは気が済まない人向けの雑多な話です。 Re:VIEWのバージョンは1.5.0を想定しています。

本の全体構造をいじりたい

本の背骨となる構造はcatalog.ymlというYAMLファイルで与えることになっています。 部や章のような本の中身となるコンテンツは、前づけや本文や付録などのグループに分けてここに並べます。

ただし、目次や索引のような、自分で書くわけでもないしRe:VIEWで生成するわけでもないコンテンツはcatalog.ymlには並べられません。 これらはすべてデフォルトの位置に挿入されてしまいます。 この挙動を変えるには、テンプレート(layouts/layout.tex.erb)の修正が必要です。

局所的に必要になる独自の構造

書籍では、「序文」の末尾に執筆者の署名と日付を入れることがよくあります。 Re:VIEWには、「段落を右寄せにする環境」がデフォルトであるので、同人誌などではこれを使うことで署名をそれっぽい仕上がりにできるでしょう。 しかし商業出版だと、出版社ごとにハウスルールが決まっていたりするので、右寄せにすればいいというわけにもいきません (そもそも、文章の構造の一部になってる要素に対してレイアウトだけ指定して済ませるというのは、あまりお勧めできない)。

このような、局所的な独自構造が必要な場合、自分で新しいマークアップの構文とその挙動を出力形式ごとに定義できます。 新しいインライン要素やブロック要素と、それらのレンダリングの動作を定義するには、 トップディレクトリにreview-ext.rbというファイルを用意し、その中でReVIEWモジュールのLATEXBuilderクラスやHTMLBuilderクラスに追加のメソッドを定義します。

たとえば、署名のための構文をこんなふうに書けるようにしようと考えたとします。

@<signature>{2015年7月|鹿野桂一}

このインライン要素(意味的にはブロック要素にすべきなんだろうけど)に対する処理は、こんな感じに定義すればいいでしょう (LaTeXの\signatureコマンドやCSSのdiv.signatureの定義はそれぞれ別に必要です)。

ReVIEW::Compiler.definline :signature

...(中略)

module ReVIEW
  class LATEXBuilder
    def inline_signature(name_author)
      "\\signature{%s}{}{%s}{}" % name_author.split(/\|/)
    end
  end
  class HTMLBuilder
    def inline_signature(name_author)
      "<div class=\"signature\" sigdate=\"%s\">%s</div>" \
        % name_author.split(/\|/)
    end
  end
end

なお、Re:VIEWにはLaTeXを経由してPDFを作るときに標準的に使える索引のためのマークアップがありません(InDesign用ならあるようです)。 そのため、たとえばmendexを使って索引が作りたかったら、LaTeXの\indexコマンドにマッピングされるような独自のマークアップをreview-ext.rbで同じように定義し、 layouts/layout.tex.erbに手を入れて\printindexを読み込むようにする必要があります。

このへん、公式のドキュメントがほとんどないので辛いのですが、がんばろう。

メタ情報

ドキュメントに埋め込みたいメタ情報(タイトル、著者名など)は、YAMLファイルに記述しておいて、それをreview-pdfmakerの実行時に指定します。 このYAMLには、標準で用意されているキー・値のペア以外にも、好きなキーと好きな値のペアを記述してよいようです。 たとえば奥付に初刷の情報だけでなく最新刷の情報も出力したい場合には、

date:    平成27年6月25日 # これは標準で用意されているキーと値
...(中略)
latestd: 平成27年7月1日  # これらは標準にはない
latestp: 第1版第2刷

のようなキーと値のペアをYAMLに書いておいて、これらをlayouts/layout.tex.erbで使えばよいでしょう。

レイアウト

二倍長ダッシュのような記号が必要な場合、デフォルトではサポートされていないので、やはりreview-ext.rbに独自マークアップとして定義するしかなさそうです。 ただし、少なくともバージョン1.5.0にはインラインの要素を入れ子にできないという問題があるため、この方法だと他のマークアップの中で二倍長ダッシュを使うことはできません。 次期バージョンでは入れ子のインライン要素に対応するらしいので期待しましょう。

一般に、レイアウトに対する特別な要求はLaTeXやCSSの側で解決することになるはずです。 裏を返せば、Re:VIEWで簡単に本が作れるとはいっても、見た目をよりよくしようと思ったらLaTeXやCSSをがんばるしかないという話です。

デフォルトで生成されるLaTeXソースの問題

LaTeXのhyperrefパッケージをincludeしている場所が、ユーザの独自スタイルファイルがincludeされる場所より前にあるので、自分のスタイルファイルで定義した\chapterがうまく動作しない、といった可能性があります。 また、デフォルトでgeometryパッケージが使われています。 いずれもlayouts/layout.tex.erbを編集することで回避できます。

オーバーライドできないマークアップ

ほとんどの定義済みマークアップはreview-ext.rbでオーバーライドできるのですが、たとえば章見出しのための行頭「=」は再定義ができません。 そのため、章扉と目次や柱とで見出しを変更したい場合(つまり\chapter[foo]{bar}したい場合)、上記のような通常の拡張方法が使えません。 LATEXBuilderのheadlineメソッドを全面的に修正するくらいしか方法が思いつきませんでした。

Re:VIEWは商業出版のデファクトになるか

というわけでRe:VIEWで商業出版は、中の人が中にいる特別なプロダクションさんでなくても、ソースを見ながらLaTeXをがんばれば割と可能です。 とはいえ、「じゃあおまえこれからはRe:VIEWで売り物の本を毎回作るつもり?」と言われたら、たぶんそんなことはないです。

そもそも、書籍っていうのはわりと「一点もの」な性格の商品なので、「その本で独自に必要とされるセマンティクスのための構文と表現を考える」という作業は商業出版だとどうしてもくっついてくるものだと思っています(異論がある人はどこかでビールでも)。 で、その作業がRe:VIEWでやりやすいかといったら特別そういうわけではないし、そういうのはむしろXMLのお家芸だったりします。かといって山括弧を手書きしないと原稿が書けないような執筆環境はありえないし、痛し痒しですね。え、LaTeX?

手に入れた原稿(翻訳なら原書)のソース形式を最大限に生かす方向で今後もがんばります。

2015/04/01

昔のTeX環境をDockerのコンテナ化する

大きく進化した日本語TeX環境

新しいLinuxマシンで、とりあえず日本語TeXを使えるようにするまでの時間は、ここ数年で信じられないほど短くなりました。それもこれも、TeX Liveが2010で日本語に完全対応してくれたおかげです。

いまのように「TeX Liveをインストールするだけ」となる以前、Linuxで日本語TeX環境を整備するのは、ほとんど腫物に障るようなものでした。 ディストリビューションの各種パッケージから必要なものを適切な順番にインストール、フォントの実体ファイルへのシンボリックリンクをTEXMF以下に作成、mktexlsrを実行、otfパッケージを手動でインストール、mktexlsrを実行、dvipdfmxの設定ファイル群を編集、mktexlsrを実行。 なんとかインストールを終えてplatexを実行し、dvipdfmxにかけると、なぜかPDFのしおりが文字化けしてしまい、よくよく調べてみると上流で日本語EUC用のCMapファイルが勝手に消されている! あのころのdvipdfmxはいろいろとひどかったのですが、日本語でPDFを作るときの現実的な選択肢がほかにはなかったのです。

ところが2000年代後半になると、日本語TeX環境が思い出したように進化を再開します。具体的には、e拡張やUTF-8に対応したエンジンが登場してきました。 dvipdfmの亜種のような扱いを受けながら鬼子となっていたdvipdfmxも、XeTeXで見直されたおかげか、まっとうなDVIウェアとして主要パッケージでネイティブ対応されるようになりました。 おかげで不可解なバッドノウハウの数々がずいぶん不必要になったはずです。

過去の環境で作ったドキュメントが負債に

しかし前述したように、いったんうまく動くようになった日本語TeX環境に手を入れるのは、とくに業務で使っているとなかなか勇気がいることでした。 必然的に、更新をさぼります。その結果、古い環境で作られたドキュメントがどんどんたまっていきます。 さすがに、e拡張なしではtikzが満足に使えなかったり、UTF-8でない原稿をバージョン管理するのはつらかったりで、いまでは現代的な日本語TeX環境に移行したのですが、そうなると今度は過去のドキュメントが負債としてのしかかってきます。 過去のTeX環境で作ったドキュメントを当時と同じ見た目に再現しなければいけない場合、どうしても当時のマシン環境が必要です。 過去の環境を仮想マシンとしてそのまま残して凌いできたものの、ディスクイメージだけで100G近くあるので、管理コストがバカになりません。 作業としても、ドキュメントを編集するだけなのにOSをまるごとブートするというのは、どう考えても面倒くさい。

過去の環境をDockerコンテナ化

そこで、過去のマシンと同じ環境をDockerのコンテナとして作成することにしました。 古いドキュメントの編集が必要なときには、この古い日本語TeX環境を閉じ込めたコンテナ内でPDFを作るようにすればよかろう、というわけです。

いろいろなドキュメントに応じて必要となるパッケージはDockerfileを使ってそのつどインストールすることにすれば、コンテナ自体は最小の構成にしておけます。 コンテナ化したいのはあくまでもTeX環境だけなので、仮想マシンと違って実体フォントをインストールする必要がないっていうのも利点です。

Debian Lennyをベースとした日本語TeX環境コンテナ化の手順

Dockerのマニュアルによれば、ルートファイルシステムのtarアーカイブに対して docker import を実行すれば、コンテナ(の基になるイメージ)が生成できるとのことです。

自分が必要とする Debian Lenny のルートファイルシステムを、ふつうのディレクトリ(以下の例では ./lenny4debootstrap/)に取ってくるには、以下のように debootstrap コマンドを使います。ちなみに、この作業をしているのは jessie/sid 上です。

$ sudo debootstrap lenny ./lenny4debootstrap http://archive.debian.org/debian/

取ってきたルートファイルシステムを tar で固めて、docker import します。

$ sudo tar -C lenny4debootstrap -c . | sudo docker import - lenny

これで、lennyという名前のDockerイメージができました。 このイメージを docker run すれば、Dockerコンテナができて、その中で好きなことができます。 とりあえず、お約束のバージョン確認。

$ sudo docker run lenny cat /etc/debian_version
5.0.10

上記の cat /etc/debian_version の部分に /bin/bash とかを指定すれば、コンテナ内で好きなシェルが立ち上がります。 しかし仮想コンソールがない状態で起動してしまうので、これだけだとコンテナ内で起動してるシェルからコマンドを入力できません。 仮想コンソールを有効にするには、docker run-t オプションを付けます。

さらに、これだけではコンテナ内で実行したコマンドの結果が標準入力にリダイレクトされず、コンテナ内のシェルから対話的なことが何もできません。 これを有効にするためには -i オプションが必要です。

というわけで、コンテナ内でシェルを実行してコマンドを実行するには、こんなふうにします。

$ sudo docker run -i -t lenny /bin/bash
e606e97b3187:/# ls
bin  boot  dev  etc  home  lib  media  mnt  opt  proc  root  sbin  selinux  srv  sys  tmp  usr  var
e606e97b3187:/# exit
$ 

コンテナ内のシェルのプロンプト e606e97b3187:/# に表示されている12桁の16進数は、コンテナのIDです。 以下のコマンドで最近実行したコンテナのIDが表示できますが、確かに上記と同じ文字列になっているのが分かります。

$ sudo docker ps -l
ONTAINER ID   IMAGE  COMMAND      CREATED        STATUS        PORTS  NAMES
e606e97b3187  lenny  "/bin/bash"  2 minutes ago  Up 2 minutes         romantic_poincare

さて、これでコンテナ内のシェルから apt-get install ptex-base とかできれば話は簡単なんですが、archive.debian.org から取ってきた Lenny のルートファイルシステムには apt が入っていません。 /etc/apt/source.listこそありますが、無効なアドレスが入っています。 そこで、まずは apt が使えるようにがんばってください。 たぶん以下を個別にDebianのアーカイブから取ってきて、dpkg -i で入れればよいはずです。

apt_0.7.20.2+lenny2_i386.deb
coreutils_6.10-6_i386.deb
debian-archive-keyring_2010.08.28~lenny1_all.deb
gcc-4.3-base_4.3.2-1.1_i386.deb
gnupg_1.4.9-3+lenny1_i386.deb
gpgv_1.4.9-3+lenny1_i386.deb
libacl1_2.2.47-2_i386.deb
libattr1_2.4.43-2_i386.deb
libbz2-1.0_1.0.5-1+lenny1_i386.deb
libc-bin_2.11.3-4_i386.deb
libc6_2.11.3-4_i386.deb
libc6_2.7-18lenny7_i386.deb
libgcc1_4.3.2-1.1_i386.deb
liblocale-gettext-perl_1.05-4_i386.deb
libncurses5_5.7+20081213-1_i386.deb
libreadline5_5.2-3.1_i386.deb
libselinux1_2.0.65-5_i386.deb
libstdc++6_4.3.2-1.1_i386.deb
libusb-0.1-4_0.1.12-13_i386.deb
lzma_4.43-14_i386.deb
readline-common_5.2-3.1_all.deb
zlib1g_1.2.3.3.dfsg-12_i386.deb

もちろんコンテナ内には wget もないので、ホストOSで取ってきた .deb をルートファイルシステムに配置して docker import するか、以下のようにdocker run-v オプションを付けて .deb のあるディレクトリをマウントします。

$ sudo docker run -t -i -v /home/k16/temp/debs:/root/temp lenny /bin/bash
1be08b199276:/# cd root/temp
1be08b199276:/# dpkg -i ...

source.listはこれ。

1be08b199276:/# cat /etc/apt/sources.list
deb http://archive.debian.org/debian/ lenny main contrib non-free

無事に apt が入ったら、必要な日本語TeX環境を入れましょう。 当時の情報としては、このへんのリンクが参考になると思います。

2015/01/01

2015年賀状

年賀状、なんとか書いた。

%!
<< /PageSize [285 420] >> setpagedevice

/setrandcolor {% def
  /m exch def
  /r1 {m 10 7.8 exp mul rand div} def
  /r2 {m 10 7.3 exp mul rand div} def
  /r3 {m 10 7.2 exp mul rand div} def
  r1 r2 r3 setrgbcolor
} def

/randdirection {rand 8 mod 3 div} def

/f {% def
  /i exch def
  /Legrand findfont
  i 10 add scalefont setfont
  randdirection 105 add rotate
  -100 randdirection 200 mul moveto
  1 1 10 { (2015 ) false charpath pop} for
  gsave
  i 5 div setrandcolor fill
  grestore
  1 1 0.9 setrgbcolor stroke
} def

1 1 100 {% for
  /n exch def
  1.3 setlinewidth
  -100 100 translate
  0 0 moveto
  100 rotate
  20 2 70 {f} for
  showpage 
} for

ごらんのとおりの手抜きコードですが、文字の配置もランダムなので、都合300ページ分をfor分で生成して、見た目がいいのを20枚くらい選ぶという方法をとりました。 おかげで結果はわりとかっこいい。

2014/12/24

TeXの組版で1行ごとに色を変える

テキストからなるドキュメントのページというのは、行の集まりだと考えられます。 では、ページの行ごとに装飾を施すようなことは可能でしょうか? たとえば、本文を行ごとに色分けするようなことは可能でしょうか?

Webページでは、CSSを使って、表の各行の背景色をストライプにするような効果がよく使われています。 しかし、本文を行ごとに色分けするのは、CSSだけではかなり難しそうです。 ブラウザで本文の1行になるコンテンツをどう決めているのか知りませんが、それを制御しようと思ったら、ブラウザの描画処理に介入する方法が必要に思えます。

この事情は (La)TeX でも変わりません。 1行ごとに色を変えるといった処理を実現するには、行とページを組み立てる TeX の仕組みに介入する手立てが必要です。 TeXでは、その手立てが「出力ルーチン(アウトプットルーチン)」という形で提供されています。

ここでは、TeX & LaTeX Advent Calendar 2014 第24日のネタとして、行ストライプ問題を使って出力ルーチンで遊んでみます (第23日は tkz-fct パッケージがアレだった件、明日最終日はZRさんです)。

出力ルーチンとは

ものすごく端折って言うと、TeXは入力ソースを読み込んだら最適な改行位置を計算して各行を作ります。 その各行が溜まってきたら、そこから最適な改ページ位置を計算して1ページを作ります。 各行が溜まったものは「メイン垂直リスト」、そこからTeXが計算して作った1ページは「\box255」と呼ばれます。

しかし、\box255 がそのまま DVI ファイルや PDF ファイルの 1ページにはなるわけではありません。 \box255 を調理して DVI ファイルや PDF ファイルの 1ページにするのが「出力ルーチン」の仕事です。 ページノンブルを振ったり、柱を作ったりする仕事も、実は出力ルーチンで行われています。

この出力ルーチンにおける処理の内容は、ユーザが好きなように定義できます。 その定義では、\box255 をそのまま律儀に使う必要もありません。 たとえば、出力するページに残したい行だけを取り出して残りはメイン垂直リストに戻すことも可能です(改めて \box255 が組み立てられるので、戻した行は次ページ以降の材料として使われる)。 残したい行だけを取り出すときには、\vsplit というプリミティブが使えます。 「\vsplit ボックス to 高さ」のように実行すれば、指定したボックスから指定した高さぶんの行を取り出してきたボックスが手に入ります。

本文をクリスマスっぽいストライプにする

ここまでくれば、本文の行をストライプにする方法が見えてきましたね。 \box255 から \vsplit で1行ずつ取り出して交互に色を付け、それを集めたボックスを作り、そのボックスを出力ページとして吐き出せばよさそうです。

\documentclass[12pt]{article}

\usepackage{lipsum}
\usepackage[usenames,dvipsnames]{xcolor}

\fboxsep=0pt
\newcount\RGF
\RGF=0
\def\XmasStripe#1{
  \ifnum\RGF=0
    \colorbox{red}{\color{ForestGreen}#1}
    \global\RGF=1
  \else
    \colorbox{ForestGreen}{\color{Red}#1}
    \global\RGF=0
  \fi}

\output={ \loop \setbox1=\vsplit255 to\baselineskip \setbox0=\vbox{\copy0\XmasStripe{\copy1}\vskip-\dp1} \ifdim\ht255>0pt \repeat \shipout\box0}
\begin{document} \color{ForestGreen} % 最初の行のため。colorパッケージがおかしい? \lipsum[1-10] \end{document}
\output というのが、ストライプ柄のために定義した出力ルーチンです。 \box255 から \box1 へと1行ずつ取り出して交互に色を付け(\XmasStripe)、それらを次々に連結していった \box0 を作り(各行を連結するときにボックスの深さをつぶすために \vskip-\dp1 している)、最後にその \box0 をページとして吐き出しています。 ページとして吐き出すためのプリミティブは \shipout です。

実行結果はこんな感じ。もちろんドキュメントオプションでフォントサイズを変えても行ごとに色付けされます。スクリーンショットも貼っておきます。

注意

ここに載せたのはおもちゃのプログラムなので、ノンブル付けといった他の処理はすべて無効になってしまいます。 「Underfull/Overfull \vbox」もてんこ盛りです。

解説のほうも、いかにも出力ルーチンが簡単なものっぽい書き方をしてますが、正直なところ、書いている本人もそれほどちゃんとは理解していません。 なにせ、TeX が \box255 としてページを組み立てる処理と非同期に深く連動している処理です。 少なくとも TeX ブックの第14章、第15章を完全に理解している必要があります。 なので、本来はなるべくいじらないほうがいいでしょう。

参考文献

David Salomon "Output Routines: Examples and Techniques. Part I: Introduction and Examples."

2014/12/08

「版管理+自動組版」イベントの雑感

2014年12月6日、「版管理+自動組版」と題した勉強会というかイベントいうか集まりを開きました。 「同じようなことをバラバラにやってる人たちの横のつながりのきっかけが欲しいな」という程度の軽い気持ちで声を上げてみたら、予想以上に興味を持ってくれる人が膨らんで、様々な背景の方から発表に手を上げていただき、当日も会場から次々と質問が飛び交うという、実に活発で刺激的ですごく楽しい集まりになりました。ありがとうございました!

発表内容や概要は、公開されている各スライドや、武藤さんによる素晴らしいまとめを見ていただくとして、ここには個人的な感想文を晒しておこうと思います。参加してないと文脈が分かりづらい内容なのはご了承ください。

発表では、自分のゆるい話のあと、 @amedama こと宮川さんに Grifletという書籍のビルドシステムを紹介していただきました。 出版に継続的インテグレーションを適用するというのは、自分たちでも割と前から取り組んでいたのですが、この間ずっと未解決になっていた課題として、自動組版の環境をプロジェクトごとに固定化したりチーム間で共有したりしたいという要望がありました。 VM を使うとこまでは過去の本の重刷対応なんかでやっているのですが、Dockerのような仮想コンテナが使えることには気づけてませんでした。 それに気づいたのが、実は宮川さんの PyCon 2014 のスライドで、まさかその話をこうして直接聞ける機会がくるとは想像もしていませんでした。 今回の宮川さんの発表では、これを商品として提供するサービスの可能性にまで突っ込まれていて、商用フォント会社とうまい具合にライセンス契約ができれば同人誌の制作をしたいような人にとっても現実的な価格で再販できるのではとか、商業出版をやっている身としてもサービスを享受するという方向で夢が広がる話が伺えました。

商業出版という観点では、清水川さんによるかなり具体的な書籍制作フローの事例紹介がありました。 清水川さんは、執筆者としてドキュメント制作フローを語ったと思うのですが、それは自分たち出版社の人間から見てもなんら特別なものではなく、本作りのフローで必要なことは執筆者にとっても編集者にとっても共通する部分が多いという至極当たり前の事実を追認しました(ただ、スプレッドシートでSIer風にコメントを管理するのはつらいかもw)。

もう一つ追認したのは、上流でうまく回っているソースの版管理と最終的な本との間にギャップというかブラックボックスがあると、改訂版などへの再利用性は極端に低下するという事実です。 最後の最後まで版管理っていうのは、技術的なだけでなく政治的に難しい面もあるので、せめて、内容の編集までは出版社側の人間も reST ソースで完全に終わらせて、あとはレイアウト的な問題しか絶対に直さない、くらいの割り切りが必要かもしれません(レイアウト制作時に見つかった致命的な内容の問題が見つかったら必ずソースにも反映するようにする、といった抜け道は用意しておくとして)。

一方で、再利用性っていうのが「版管理+自動組版」をやりたい人にとって大前提の金科玉条になってもいけないと思いました。 そもそも何をどの程度に再利用可能にしたいのかは最終成果物によって大きく変わるはずで、必然的に、版管理する対象とか粒度、さらには制作システムのフローもまちまちにならざるを得ないでしょう。 で、そういう「共通化しにくさ」っていうのの具体例が、 taison さんの発表に出てきた 3つの事例かもなあと勝手に解釈していました。 taison さんの発表は、「どれも似たようなことをしているのに担保したいことが違って標準化できてない」という話をはじめ、あるある感で胸が痛くいっぱいになりました。

ところで、 taison さんのシステムで XML アプリケーションを固定していないのは、自分の経験としては正解だと感じてます。 DTD や Schema を用意するということは、梯子の下の表現レイヤを限定するということです。 もし、表現レイヤは決め打ちでいいというなら、わざわざ山かっこなんか使わず、人間にやさしい(⊃入力しやすい)マークアップを用意したほうがハッピーでしょう。 しかし、 XML という仕組みそのものには、文法的な一貫性を提供しつつ、ユーザが都合に合わせてマークアップを拡張できるという特徴があります。 表現レイヤを制限せず、なおかつ文法的に破たんしてないマークアップを提供したかったら、整形式であることだけを要求した XML を使うというのは割と理に適っているはずです。

マークアップを拡張することについては、小宮さんからも、拡張によるマークアップの方言化の是非という視点での発表がありました。 たとえば Sphinx でも、ベースとなるマークアップの reST を機能的に拡張するための API があって、それはすごく強力(なにぜPythonのフル機能がマークアップとして利用できるようになる!)なんだけど、それらの拡張が使える環境と使えない環境が生まれてしまう、さてどうしよう、という話だったと思います。 自分の知ってる TeX 界隈も、CTAN というオンラインのライブラリのおかげでマクロやパッケージの管理では比較的楽ができてますが、そもそもエンジンや PDF 生成機能がユーザから透過的とは言えない現状があります。 実際、 宮川さんの発表でも、LaTeX で Noto Sans を使いたかったけど TeX Live のエッジ(にしか入ってない dvipdfmx ですね)が必要で、システム全体を更新するわけにもいかないから、必要な Debian パッケージを入れた Docker コンテナを使ったという話がありました。 そんな風に環境ごとシステムの中の人が管理するという手はあるとはいえ、どうしたってユーザの利便性とか表現レイヤの自由度は下がるわけで、痛し痒しな気もします。

ひょっとすると、表現レイヤの自由度をあまり捨てずにマークアップの拡張による方言化を吸収できるかもしれない、そんな自動組版の最終兵器が、村上さんのプレゼンで紹介された CSS 組版なのかもしれません。 そこまで期待していいのかっていう内省もないではないんですが、技術的には夢の最終兵器としての可能性は間違いなく持ってるし、末端のユーザが実用できる日も遠くはない気がしています(実際、アンテナハウスの実装をはじめ、ちゃんと動いているものはあるわけで)。 むしろ心配なのは、 Web の世界では直接必要とされていない技術なので、ブラウザというプラットフォームで継続的に仕様と実装の開発が進むかどうかです。 TeX ユーザの集い2014 でも川端さんによるルビの標準化の話がありましたが、あれもお金がネックになって次の一手が出ないようだし、Web という巨大産業はどうやらそういう世界のようです。 そういう意味で、必要なのは銀の弾丸よりも金の弾丸なのでしょう……。 自動組版界隈、あんまりお金なさそうだし、どんな形で自分たちが利用できるようになるのかを含めて CSS 組版を盛り上げていくのに協力できればなと感じました。

最後の発表では、ここまで自動組版っぽい話題が多かったなかで、「同一性とは何か」まで考えさせられる版管理系のネタ を力武さんにぶつけていただきました。 図表の差分とれないのつらい、みたいな感想しか持ってなかったので、そもそも図表みたいなものの差分を取りたいのかという問題提起に付いてくだけで精一杯でしたが、 「差分を取るだけでなく、差分に意味を与えて差分をメンテナンスしてくのが編集という営みだろう(意訳)」という話が個人的には刺さりました。 git rebase -i に相当することができない版管理ツールを使うのはやめようと思いました(小並感)。

図表の差分の話もさることながら、 MS Word の原稿をどう比較するかという話への会場からの食いつきがよかったのが意外でした。 あんまり実体をしらないので、表面的な差分をとるだけならツールもけっこうあるし難しくない気がしてたんですが、そうでもないんですね……。 正直なところ、Word に限らず、閉じた世界でならものすごい利便性を提供するツールって、そこに身を投げれば版管理+自動組版が完全に解決するような錯覚に陥ることがあります。 図表の版管理にしても、閉じた世界で便利な解決策を提供しているツールがありそうなものなので、この辺りは寡聞にして知らない系の話というだけかも。

会の終了後は、主催者が参加できないことから公式の懇親会は企画しなかったのですが、一部の野良懇親会で濃い話が続いたりもしたようで、横のつながりの一助としても多少は機能できたっぽくてよかったです。 こういう特殊な軸で人が集まるのはとても面白いということがわかったので、同じ形になるかどうかはわかりませんが、また何かできればと思っています。

2014/12/02

LaTeX で git のメタ情報を使うパッケージ

2014年現在、「自動組版のためのPDF生成器である」と豪語できるツールは、どうやらまだまだ (La)TeX だけという状況っぽいです(異論は認める宗教戦争前夜)。 しかし、自動組版に使えると豪語するからには、 git のメタデータくらいは気軽に出力できないと困ります。にもかかわらず、どうも CATN にはこれといった便利パッケージが見当たらない†1。その愚痴を TeX & LaTeX Advent Calendar 2014 の2日目の記事としてぶつけます。(1日は ZR さん、明日3日は doraTeX さんです。大物に挟まれてつらい)

ところで、今週末の12/6(土)は、自動組版とバージョン管理の可能性を模索しようという「版管理+自動組版」という集まりがあります。 ものすごく楽しみです。 閑話休題。

さっそくですが、 git のメタ情報を (La)TeX のドキュメント中で利用するためのパッケージとしては、 gitinfo2vc といったものがあるようです。 いずれも、たとえば自分のドキュメントに git のコミットハッシュの文字列を含めたかったら、\gitHash(gitinfo2) とか \GITHash(vc)といった引数なしのコマンドを自分のドキュメントの中で指定して使う仕組みです。分かりやすいですね。

しかし、ここで厄介なのが、これらのパッケージのインストールと設定です。 いずれも TeX Live 2014 に入っているので、プリアンブルで \usepackage するだけで使えると実にうれしいのですが、残念なことにそんな安直な使い方をさせてくれません。事前に外部のスクリプトを自分で設定する必要があります。

vc パッケージの場合は、毎回ドキュメントをコンパイルする前に vc-git.awk というスクリプトを実行し、vc.tex というメタ情報が入ったファイルを生成して、このファイルをドキュメントから \include するという仕組みになっています。 なので、このスクリプトを手動で実行したり、 Makefile に記述しておいたり、 \write18 を使って vc-git.awk をドキュメントのコンパイル時に実行したりする必要があります。公式のドキュメントで説明されているのは \write18 を使う方法です。

gitinfo2 のほうは、 git に特化しているだけあって少しだけ先進的で、 git のフックスクリプトの機能を利用する仕組みになっています。 具体的には、

  • 特定のファイルに git log HEAD を出力するだけのコマンドシェルスクリプトを、ユーザが自分の .git/hooks ディレクトリに設置する
  • その特定のファイルをドキュメント中で \input で読み込んでおく
という具合です。 でもこれだと、GitHub をポーリングして CI を回している環境ではちょっと使いにくい(コミットフックで出力される特定のファイルをバージョン管理化におけばいいのですが、なんかいやだ)。

仕方がないので、自分ではこれらのパッケージを使っていません。 代わりに、 git のコミットハッシュを \write18 で取得するだけという、超低機能な自前コマンドを使っています。 これをプリアンブルに仕込んでおけば、 git の短縮版コミットハッシュの文字列が \gitRevision という引数なしのコマンドで得られます。

\immediate\write18{git show HEAD --pretty="\@percentchar h" -s > revision.tmp}
\def\gitRevision{\input{revision.tmp}}

さらに、みようみまねで buildinfo.sty という LaTeX2e 用のパッケージにしてみました。

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{buildinfo}[2014/12/06 provides git hash as a command]
\RequirePackage{etoolbox}
\RequirePackage{kvoptions}
\SetupKeyvalOptions{family=buildinfo, prefix=buildinfo@}
\DeclareBoolOption{long}
\ProcessKeyvalOptions*
\immediate\write18{date +\@percentchar c  > build.tmp}
\ifbool{buildinfo@long}
  {\immediate\write18{git show HEAD --pretty="\@percentchar H" -s > revision.tmp}}
  {\immediate\write18{git show HEAD --pretty="\@percentchar h" -s > revision.tmp}}
\newcommand{\buildDate}{\input{build.tmp}}
\newcommand{\gitRevision}{\input{revision.tmp}}

\usepackage{buildinfo} すれば、 短縮版のコミットハッシュ文字列に展開される \gitRevision コマンド(\usepackage[long]{buildinfo} とすれば40文字になる)と、 コマンド実行時の日時の文字列に展開される \buildDate コマンドが使えるようになります。


†1 思い返せば、Subversionを使っていたころにも、 svninfo というパッケージでファイル単位でしかメタ情報を扱えないことに苦慮していたことがありました。(いまや完全に git に移行したので、この問題は個人的には原理的になくなりましたが。)