1年以上前に出題された問題なのですが、当時 kinaba さんの解答を見て、すげーと思って、今でも一番好きな Ruby のコードではないかと思っています。ので思い出したように少し書いてみます。
http://www.kmonos.net/wlog/71.html#_2014070301
問題は、 (a-b)*c というような中置記法の式を、 ab-c* というような後置記法になおせというもの。 flagitious さんと kinaba さんは eval で ruby に中置記法のパースを丸投げして、 method_missing に飛んできた順で出力する、という豪快な手法で当時最短だった 61B になったのでした。こんなの
undef:p def method_missing s,*;$><<s end loop{eval(gets)<<$/}
あまりにも美しいコードなんですが、3ヶ月程前に、 flagitious さんが 59B を叩き出して更新しました。で kinaba さんも追いついたのですが、どうも flagitious さんとの雑談によると、 2人のコードは違う気がしています(ほとんど alnum だと言ってた気がするので、後述する goruby の alnum 解に近いのではないかなぁと思うけどよくわからない)。 kinaba さんの方はおそらく
undef p def method_missing s,*;$><<s end eval [*$<]*'puts;'
という感じなのではないかと思います。思いついてしまえばなるほどまぁ普通かもという感じです。この解が出る前にずいぶん悩んだんですが、実は 60B を一度思いついていました。これはなかなか豪快な方法で、いつか使ってやると思っていた「def文は実は nil をかえしている」という事実を使いました。
undef p eval(gets)<<$/until def method_missing s,*;$><<s end
次に goruby なんですが、 goruby は Kernel#h が定義されていて、これが Hello, world! を出してくれるんですが、この問題では余計なことを…! という感しかわいてきません。でかつ method_missing を定義して解くこの問題では、 method_missing でメソッド名が短くなる goruby の効能が消えてしまいます。だからこの問題は goruby 向いてない…と思っていたのですが、色々やってみると 40B とかいう驚異的なことになっていたのでした。
O.u:p,:h O.a_ _,:print eval [*$<]*'say;'
何してるかさっぱりわからんですが、
- O.u は Object.undef_method
- O.a_ は Object.alias_method
- 第一引数の _ は奇跡的な事情により :method_missing になっている
- Kernel#_ が存在しないので method_missing が呼ばれる
- method_missing 内で _ に最初にマッチする関数である __callee__ が呼ばれる
- この時 __callee__ は :method_missing
- 第二引数の alias 先は print だけど、これは ruby 1.8 では使えない
- あとは puts の変わりに say を使えば終わり
_ が :method_missing になっているのを最初に偶然発見した時は、しばし理由がわかりませんでした。
あとは flagitious さんが最初に投稿した、ほぼ alnum のバージョンもなかなか良いです。
undef p undef h alias method_missing print say until eval gets