Ruby Quiz #187
Posted by Luke Cowell on December 22, 2008 at 11:57 AM
I saw this solution on Ruby Quiz and I thought it was brilliant. I thought I'd explain how the original author came up with this beautiful looking tree to generate some code.
### M E R R Y M A T Z M A S ###
"/|"\
"/wl)e";eval(\
"A | A"\
"A | A"\
\
"InHhL"\
",Z,%w{-"\
",Y&/LH,L*"\
"cCnd,Hh&/d,"\
"YCB/Hh,Y&YHh,"\
"L&xHh,L*v*nHh,*"\
"&ghHh,n&nHh,H*nHh"\
",*q*v*nHh,Hw*qv*Hh}"\
"Iq&n*L,Z,[,n&qK,n&qK,"\
"@TwC,LH/&ng,gLBbL@K,@Th"\
"/**,YC/k*d,Hh/*QdL@K,@FCB"\
"/,cQqq&ng,=/CcL@K,@F&v*,RBb"\
"y,g*mL!@K,@S&x,mQ/LhQqL,dBm=&"\
"ng@K,@S*v*n,dBckL,Q-Hy=&ng@K,@E"\
"&ghH,d&/L,Q-gqCbb&ng@K,@N&n*,/Qng"\
"*L,LH*==&ng@K,@T*n,H/yL,Q-cQHch&ng@"\
"K,@Eq*v*n,&CL,=&=&ng@K,@Tw*qv*,mCnk*y"\
"L,=QHch&ng@,]IDAJJA2)J*Qch,dC,U&UI=/&nH"\
",@\nOn,Hh*,#{nHhL[&]},dQy,CY,MQHzmQL,my,"\
"H/B*,qCv*,gQv*,HC,m*:\n@I&JdCwnHCD2),dC,UjU"\
"I=/&nH,@,,,#{q&n*L[j]}\n@I*ndI=/&nHDD&,ZZ,A)"\
"?,@,,"\
",G@,:"\
",@,,,"\
"Gnd,Q"\
"@)I=/"\
"&nH,@,n*w,v*/L&Cn,CY,RBby!\n@I*nd"\
"I".tr(' ID/VHLYGBqCA&|*UQJ=Z@K,',
'+;(r/tsfAulo1i8e|a.p=", '))
Here's the original code: http://pastie.org/344030.txt
What it outputs is something like this:
On the first day of Matzmas my true love gave to me: A new version of Ruby! -snip- On the twelveth day of Matzmas my true love gave to me: Twelve monkeys patching Eleven ios piping Ten trys a-catching Nine ranges stepping Eight dirs a-globbing Seven ducks a-typing Six marshals dumping Five Ruby gems! Four calling procs Three forked threads Two string gsubs And a new version of Ruby!
Well everything up to the 'eval' is fluf, so we can ignore that. If we paste everything inside the eval without calling the eval into irb, we get:
"1+8+11++8++1;nths = %w{- first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelveth};lines = [ nil, nil, \"Two string gsubs\", \"Three forked threads\", \"Four calling procs\", \"Five Ruby gems!\", \"Six marshals dumping\", \"Seven ducks a-typing\", \"Eight dirs a-globbing\", \"Nine ranges stepping\", \"Ten trys a-catching\", \"Eleven ios piping\", \"Twelve monkeys patching\" ];(1..12).each do |i|;print \"\nOn the #{nths[i]} day of Matzmas my true love gave to me:\n\";i.downto(2) do |j|;print \" #{lines[j]}\n\";end;print((i == 1)? \" A\" : \" And a\");print \" new version of Ruby!\n\";end;"
So we see that the tr function generates the above code and turns it into some ruby code that can be passed to eval. We can also ignore everything up to nths.
tr(' ID/VHLYGBqCA&|*UQJ=Z@K,',
'+;(r/tsfAulo1i8e|a.p=", ')
The code roughly cleans up to this:
nths = %w{- first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelveth};
lines = [ nil, nil, "Two string gsubs", "Three forked threads", "Four calling procs", "Five Ruby gems!", "Six marshals dumping", "Seven ducks a-typing", "Eight dirs a-globbing", "Nine ranges stepping", "Ten trys a-catching", "Eleven ios piping", "Twelve monkeys patching" ];
(1..12).each do |i|;
print "\nOn the \#{nths[i]} day of Matzmas my true love gave to me:\n";
i.downto(2) do |j|;
print " \#{lines[j]}\n";
end;
print((i == 1)? " A" : " And a");
print " new version of Ruby!\n";
end;
So, if we reverse the 'tr' command we can encode similar blocks of code. Here's an example:
"asdasd"
eval("DAJJA0)"\
"J*Qch,dC,UnUI,=/"\
"&nH,@I,cQn,cCBnH,H"\
"C,Hh*,nBmb*/,\#{n}\n@"\
"I*ndI"\
.tr(' ID/VHLYGBqCA&|*UQJ=Z@K,'\
,'+;(r/tsfAulo1i8e|a.p=", '))
Ta-da! It's a lumpier, uglier version of the tree that outputs some pretty unimpressive code.