STORESでフルタイムRubyコミッタをやっている遠藤(@mametter)です。
昨日は RubyKaigi 2024 の STORES ブースで開催していた企画 Ruby "enbugging" quiz の解説をしましたが、ブースでは Ruby Paper Craft というのも配布していました。今日はこちらを解説します。
STORES ブースで配布しているもの🎁
— STORES Tech (@storesinc_tech) 2024年5月15日
Ruby Paper Craft made by @mametter #rubykaigi pic.twitter.com/7tc62pZmkJ
これは何
組み上げたらRubyっぽい形になるペーパークラフトです。
遠藤が展開図を生成するプログラムを書きました。もちろんRubyで。そのスクリプトは、ここにあります。
Rubyの下半分にeval
から始まるRubyコードが配置されているのがわかるでしょうか。Rubyのまわりをぐるぐる回る
螺旋状になっていて、Rubyの一番下まで続いています。つまりこれは、とても長いワンライナーです。
これを実行すると、
$ ruby ruby-paper-craft.rb > ruby-paper-craft.pdf
PDFが出力されます。このPDFを開くと、展開図が出てきます。
つまりこれは、RubyKaigi 2024初日のtompngさんのキーノートでも言われていたQuine、自分自身のソースコードを出力するコードです。より正確に言うと、自分自身の展開図を出力するコードを持つペーパークラフトになってます。
gistにコードを置いてあるので、手元で動かしてみたい人はご参照ください。
実装クイック解説
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 と保存して開くと、星が出てきます。
少しおまじないが長いですが、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のイースターエッグで使われているモデルをベースにしています。
emscripten irb でイースターエッグが安定的に動くようになってきたhttps://t.co/ubentOzj7p pic.twitter.com/wkRb2DxYeF
— Yusuke Endoh (@mametter) 2024年1月31日
ソースコードの描画
あとは、展開図にソースコードを書き込むだけです。なのですが、文字を描くためにはフォントが必要です。PDFには組み込みのフォントがなくもないのですが、環境によって表示が異なる可能性があって再現性に自信がもてなかったので、フォントを自作しました。
テキストエディタで2次ベジエ曲線の制御点を書いたら、レンダリング結果をhotreloadで表示してくれる仕組みをつくり、適当にフォントをつくりました。
このようにして自作したフォントを、コード中に埋め込んであります。
コードゴルフ
最後に、少しだけコードゴルフをしました。ちょっとおもしろポイントとしては、大文字アルファベットを使わないようにしたところです。たとえば"Box"
と書きたかったら、"#{66.chr}ox"
などという風に書きます。長くなってるんですが、こうすることによってB
の文字のフォントデータを埋め込む必要がなくなるので、トータルではサイズ削減になります。
このあたりのノウハウは自分が過去に作った monumental-quine(自分自身の生成スクリプトを彫り込んだ柱型の物体)で培いました。こういうプログラムに興味があったら、ぜひ拙著『あなたの知らない超絶技巧プログラミングの世界』をご覧ください。
まとめ
RubyKaigi 2024 の STORES ブースで配布した Ruby "Quine" Paper Craft の解説を紹介しました。
今回 esa さんがペーパークラフトを配布して、まさかのペーパークラフトかぶりが発生したのはちょっとおもしろかったです。
esa は RubyKaigi 2024 のスポンサーですhttps://t.co/ymgTdECu1v
— esa_io (@esa_io) 2024年5月9日
📢ノベルティグッズ紹介1️⃣
▼ペーパークラフト▼ #esacraft
A4サイズの紙を切り取って組み立てると手乗りサイズのペーパークラフトになります。
糊なしハサミなしで組み立てることができます。
作成デモをどうぞ✨📺 #トノコト pic.twitter.com/SjNouEYb1f
あちらは手軽に作れるのに対し、こっちはノリやハサミが必要です!作りがいがありますね。
RubyKaigi 会場で紙をもらい損ねた人のために、gistにPDFも置いておきます。暇があったらぜひ遊んでみてください。