STORES Product Blog

こだわりを持ったお商売を支える「STORES」のテクノロジー部門のメンバーによるブログです。

Ruby "Quine" Paper Craftの解説

STORESでフルタイムRubyコミッタをやっている遠藤(@mametter)です。

昨日は RubyKaigi 2024 の STORES ブースで開催していた企画 Ruby "enbugging" quiz の解説をしましたが、ブースでは Ruby Paper Craft というのも配布していました。今日はこちらを解説します。

これは何

組み上げたらRubyっぽい形になるペーパークラフトです。

Ruby Paper Craftを組み上げた様子

遠藤が展開図を生成するプログラムを書きました。もちろんRubyで。そのスクリプトは、ここにあります。

Ruby Paper Craftの中にあるRubyスクリプト

Rubyの下半分にevalから始まるRubyコードが配置されているのがわかるでしょうか。Rubyのまわりをぐるぐる回る 螺旋状になっていて、Rubyの一番下まで続いています。つまりこれは、とても長いワンライナーです。

これを実行すると、

$ ruby ruby-paper-craft.rb > ruby-paper-craft.pdf

PDFが出力されます。このPDFを開くと、展開図が出てきます。

出力されたPDFを開いたところ

つまりこれは、RubyKaigi 2024初日のtompngさんのキーノートでも言われていたQuine、自分自身のソースコードを出力するコードです。より正確に言うと、自分自身の展開図を出力するコードを持つペーパークラフトになってます。

rubykaigi.org

gistにコードを置いてあるので、手元で動かしてみたい人はご参照ください。

ruby-paper-craft.pdf · GitHub

実装クイック解説

PDF生成

PDFってそんなに簡単に生成できるの? と思うかも知れませんが、基本的には行指向のテキストフォーマットなので、実はそこまでむずかしくありません。

たとえばこれは簡単なPDFの例です。

%PDF-1.7
1 0 obj
<</Type/Catalog /Pages 2 0 R>>
2 0 obj
<</Type/Pages /Kids[3 0 R] /Count 1 /Parent 1 0 R>>
3 0 obj
<</Type/Page /MediaBox[0 0 842 595] /Resources<<>> /Contents 4 0 R /Parent 2 0 R>>
4 0 obj
<</Length XXX>>
stream
421 498 m
539 136 l
231 359 l
611 359 l
303 136 l
421 498 l
S
endstream
xref 0 5 0 65535 f
9 0 n
48 0 n
108 0 n
119 0 n
trailer
<</Size 4 /Root 1 0 R>>
startxref 302
%%

これを star.pdf と保存して開くと、星が出てきます。

星の手書きPDF

少しおまじないが長いですが、streamとendstreamの間にあるのが絵を描くコードです。mコマンドでカーソル移動、lコマンドで新しい点まで線を描く準備をし、Sコマンドで実際に線を描きます。SVG Pathみたいなものですね。

なお、"startxref 302"の302は、"xref"がある位置のファイル先頭からのバイトオフセットを表しているので、絵を描くコードの長さが変えたら適切に更新する必要があります。なので手書きではちょっとつらい。

PDFについて詳しくは、公開されている仕様書を読むとよいです。

https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/pdfreference1.7old.pdf

展開図の描画

展開図はいくつかパターンを作って、なるべく作りやすく、A4の紙にいい感じにおさまるものを探しました。

試作物たち

描くべき展開図が決まれば、あとはふつうに描くだけです。

2Dの点を表現するには複素数を使ってます。これもtompngさんのキーノートで言われていたテクニックですね。

ちなみにRubyの形状は、irbのイースターエッグで使われているモデルをベースにしています。

github.com

ソースコードの描画

あとは、展開図にソースコードを書き込むだけです。なのですが、文字を描くためにはフォントが必要です。PDFには組み込みのフォントがなくもないのですが、環境によって表示が異なる可能性があって再現性に自信がもてなかったので、フォントを自作しました。

テキストエディタで2次ベジエ曲線の制御点を書いたら、レンダリング結果をhotreloadで表示してくれる仕組みをつくり、適当にフォントをつくりました。

簡易フォントエディタの様子

このようにして自作したフォントを、コード中に埋め込んであります。

コードゴルフ

最後に、少しだけコードゴルフをしました。ちょっとおもしろポイントとしては、大文字アルファベットを使わないようにしたところです。たとえば"Box"と書きたかったら、"#{66.chr}ox"などという風に書きます。長くなってるんですが、こうすることによってBの文字のフォントデータを埋め込む必要がなくなるので、トータルではサイズ削減になります。

このあたりのノウハウは自分が過去に作った monumental-quine(自分自身の生成スクリプトを彫り込んだ柱型の物体)で培いました。こういうプログラムに興味があったら、ぜひ拙著『あなたの知らない超絶技巧プログラミングの世界』をご覧ください。

まとめ

RubyKaigi 2024 の STORES ブースで配布した Ruby "Quine" Paper Craft の解説を紹介しました。

今回 esa さんがペーパークラフトを配布して、まさかのペーパークラフトかぶりが発生したのはちょっとおもしろかったです。

あちらは手軽に作れるのに対し、こっちはノリやハサミが必要です!作りがいがありますね。

RubyKaigi 会場で紙をもらい損ねた人のために、gistにPDFも置いておきます。暇があったらぜひ遊んでみてください。

gist.github.com