おはようございます。昨日(?)は3時過ぎまで飲んでたから眠い…。
Bento Sponsor
Ruby Kaigiでは、3日ともお弁当が出ます。スゴイ!
お弁当にはスポンサーが付いていまして、1日目は株式会社Aimingさま、2日目は永和システムマネジメント アジャイル事業部様でした。ありがとうございます。
(公式サイトにはbento sponsorは2社しか書いてないけど3日目はどうなんだろう?)
2日目のお弁当のアレ
で、2日目。お弁当にこんな広告が付いていました。
http://agile.esm.co.jp/news/2016-09-09-rubykaigi2016-bento-wrapping-paper.html
eval(
%w( put
s(([ 2*7,
2*31 ,1,3
*3*5 ,2*2
*2*2 *3].
map{ |c|c
.to_ s(5*7
).gs ub("1 ","
\s") .upca se}.
zip( [2*5* 61*1
801, 2*5*3 931,
811* 1871, 2*11
*350 27,7* 11*1
259* 20389 *764
171].map{|c|c.to_s(2*2*3*3)}))*""))*"")
なんとこのまま実行できて、英語のメッセージが出力されます。しゃれとんしゃー!
何が出るかは実行してみてください。
せっかくなので解説してみよう
よく出来ているので、何が起こっているのか感謝を込めて解説してみようと思います。
Array#*
まず、一番外側はeval
なので、その中身はRubyのコードの文字列になるのは想像できます。でも、よく見ると puts
が途中で改行されていたり、to_ s
とメソッドの途中にスペースが入っていたりと、パット見、おや?となります。
それを解決している第一のミソが、Array#*
です。これ、Array#join
と同じです。
なので、%w()
でスペースや改行で区切られた各文字列が結合されて一つの文字列になります。
つまり、evalの中身はこうなります。
puts(([2*7,2*31,1,3*3*5,2*2*2*2*3].map{|c|c.to_s(5*7).gsub("1","\s").upcase}.zip([2*5*61*1801,2*5*3931,811*1871,2*11*35027,7*11*1259*20389*764171].map{|c|c.to_s(2*2*3*3)}))*"")
Fixnum#to_s
次に、一見文字列がないのになぜ文字列が出力されるのか問題です。
そこで登場するのが第二のミソ、Fixnum#to_s
です。このメソッドに引数として数値を渡してやると、何進数として表示するかが指定できます。36を渡すと、0,1,...,9,a,...,z
が使われる36進数に!これで任意のアルファベットが出力されます。
[2*7,2*31,1,3*3*5,2*2*2*2*3].map{|c|c.to_s(5*7).gsub("1","\s").upcase}
#=> ["E", " R", " ", " A", " D"]
36進数でもスペースは出せないので、gsub("1","\s")
で"1"
をスペース("\s"
)に変換していますね。
[2*5*61*1801,2*5*3931,811*1871,2*11*35027,7*11*1259*20389*764171].map{|c|c.to_s(2*2*3*3)}
#=> ["njoy", "uby", "with", "gile", "evelopment"]
ラストスパート
ここまでを展開すると、
puts(["E", " R", " ", " A", " D"].zip(["njoy", "uby", "with", "gile", "evelopment"])*"")
あとは順当に、
puts([["E", "njoy"], [" R", "uby"], [" ", "with"], [" A", "gile"], [" D", "evelopment"]]*"")
で、またjoinして…というわけでめでたくメッセージがでてきます。
まとめ
おいしく楽しいお弁当でした!
ごちそうさまでした