Cowell Computer Consulting

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.

Tags: (none)