Claude Codeに手伝ってもらって作りました。
RubyKaigi Counterを書きながら、ふと2年前のRubyKaigiを思い出して、Quineを作ってみました。Quineは、実行すると自分自身のソースコードをそのまま出力するプログラムのことです。自分のファイルを読み込んで表示するのはズルなので無し、というのがお約束です。
eval$s=%w(t="eval$s=%w("+$s+
")*"+?"*2;i=0;13.times{|k|a=2*(k
-3).abs;b=40-2*a;puts(32.chr*a+t[i,b
]);i+=b}#RubyKaigi_2027_DAY1=2027-04-14_
#RubyKaigi_2027_DAY1=2027-04-14_#Rub
yKaigi_2027_DAY1=2027-04-14_#Rub
yKaigi_2027_DAY1=2027-04-14_
#RubyKaigi_2027_DAY1=202
7-04-14_#RubyKaigi_2
027_DAY1=2027-04
-14_#RubyKai
gi_2027_
)*""
上のコードをgem.rbという名前で保存して実行すると、同じ宝石がそのまま出てきます。
$ ruby gem.rb
本当に同じかどうかはdiffで確かめられます。何も表示されなければ成功です。
$ ruby gem.rb | diff - gem.rb
出力もまたQuineなので、何回つないでも宝石のままです。
$ ruby gem.rb | ruby | ruby | ruby
%w(...)は空白や改行で区切った文字列の配列になるので、*""でつなぐと改行やインデントが消えた1行のコードに戻ります。これを$sに入れてevalしています。"eval$s=%w("+$s+")*""と自分自身の全文を組み立て直し、宝石の形に1行ずつ切り分けて出力します。2*(k-3).abs、幅は40-2*字下げです。上の4行で広がり、残りの行ですぼまっていきます。#から始まるコメント(#RubyKaigi_2027_DAY1=2027-04-14_の繰り返し)で埋めています。コードの中に空白を書けないので、スペースは32.chr、ダブルクォートは?"で作っています。ほとんどコメントで埋められてて、超絶技巧!という感じではないなというのと、同じQuineを見ても、沖縄のキーノートの時のような鳥肌の立つ感動はないな…。というのが率直なところ。マラソンは人間の足で42kmを完走するから感動するのであって、原付バイクで同じ距離を走っても大した感慨は残らないのと同じことなのかもしれません。ただ、より遠くに行けるようになった!ということは事実であって、もっとワクワクできることに使う方法を考えるのは、人間の仕事なのかもしれません。