From: Ken Bloom Date: 2008-03-08T02:49:56+09:00 Subject: Re: [SUMMARY] Hello, world? (#158) On Fri, 07 Mar 2008 10:47:13 -0500, James Gray wrote: > On Mar 7, 2008, at 9:00 AM, Matthew Moss wrote: > >> There are even a few solutions I still haven't figured out yet. I need >> to break down the dense code from _why to get a handle on what's going >> on. > > I assume we're talking about this: > > require 'rbconfig' > bui = /^bui(.{2})$/ > $stdout << "#{{}.class}"[0,1] << > ("#{{}.methods}"[/c(\w{4})c/] && $1.reverse) << > (([0]*2).inspect[2,2]) << > Config::CONFIG.keys.grep(bui).first.gsub(bui, > "#{Kernel.methods.grep(/^th/)[0][2,3].reverse}\\1") << > ObjectSpace._id2ref(338) > > Yeah, that's crazy. Let's see if we can figure it out. > > require 'rbconfig' > > Require Ruby's configuration details. That gives us a bunch of fresh > Strings to work with. > > bui = /^bui(.{2})$/ > > Define a regular expression that matches words like "build." > > $stdout << "#{{}.class}"[0,1] << > > From here on out, it's all output. This creates a Hash, and pulls > the first character off of that class name. > > ("#{{}.methods}"[/c(\w{4})c/] && $1.reverse) << > > Now it starts to get tricky. This code pulls the methods for a Hash, > joins them into a giant String, uses a Regexp to find "collec" from the > collect() method, and reverses and prints the "olle" portion. That gets > us the rest of "Hello." > > (([0]*2).inspect[2,2]) << > > This makes an Array, grabs the code for it from Ruby's inspect(), and > indexes into that String to pull out the comma and space. > > Config::CONFIG.keys.grep(bui).first.gsub(bui, > "#{Kernel.methods.grep(/^th/)[0][2,3].reverse}\\1") << > > This uses the Regexp built a while back to match the "build" key out of > Ruby's configuration Hash. It then replaces the letters "bui." To get > the replacement, the code hunts for the throw() method on Kernel, pulls > the last three letters and reverses them. That gives us "wor" + "ld" or > "world." > > ObjectSpace._id2ref(338) > > I have no idea how reliable this is, but in _why's build of Ruby, and my > own, the object with the ID 338 is the Symbol :"!", the last character > needed. > > Clever code as always from _why. > >> And I'm somewhat frightened to even contemplate the mind of Rub��n >> Medell��n, whose solution is some bizarre, palindromic mirror image of >> Ruby insanity. > > It was freaking awesome. I'll leave it to someone else too spoil that > one��� ;) > > James Edward Gray II def method_missing(a = p, *c); return ; nruter ;(c* p = a);gnissim_dohtem fed end ; dne These first two lines define method_missing (in Object context) to do nothing. The code returns immediately (at return), so none of the addional reversed names are executed. The dne after the end of method_missing calls method_missing, since no method named dne is defined. We can now delete most mangled names that we don't understand. The equivalent code for this is: def method_missing (a=p, *c); return; end The p is never evaluated (it would point to nowhere, or cause infinite recursion), because method_missing is always called with the name of an argument alias m method_missing ; gnissim_dohtem m; saila class NilClass ; ssalCliN ssalc alias inspect to_s ; s_ot tcepsni ;saila end ; dne NilClass.inspect now returns an empty string. Everything to the right of the semicolons is a call to method_missing. This can be safely removed since it's never called anyway. class Integer ; regetnI ssalc def method_missing(a=chr,*b);print chr;return a.to_s[0] ; [0];s_ot.a nruter;rhc tnirp;(b*rhc=a);gnissim_dohtem fed end ; dne Supposing we call 63.method_missing directly. Then a will be ascii character 63 ('?'), and the function will print '?' and return 63. Supposing we call 72.e. Then a will be the letter 'e'. The function will print ascii character 72 ('h') and return the ascii code for 'e' (101). We can now call (for example) puts 72.e.l.l.o.chr and get the output 'Hello' def d! ; return(d.e and puts) ; (stup dna; e.d);nruter ; !d fed dne ; end ; dne ; end Still operating on the integer context, this prints the previous letter, then a 'd' (through two missing methods) and uses puts to place a blank line after the d. The 2 end calls close the method p, and close the Integer class. def p(p = a, *b) ; begin ; nigeb ; (b* a = p); p fed rescue ; print p.to_s ; return ; nruter ; s_ot.p tnirp ; eucser dne ; end ; dne ; end Sorting out some of the method_missing calls: def p(p=nil, *b) begin a=p #evalutes p as a variable p fed #evaluates p as a function, causing a SystemStackError rescue #catches the SystemStackError #this is caught at the innermost level of the stack overflow print p.to_s #evaluates p as a variable, which at the inner level is nil, so this prints nothing return end end The whole function definition can be safely removed, as called, it does the same thing as method_missing anyway. dne def a b = c ; return nil ; lin nruter ; c = b a; fed end Defines a method a which returns nil. dne calls method_missing with a nil argument. Since "def" to define a method is an expression that returns nil, its return value can be passed to a function. This line can be safely removed since it defines a method that does the same thing as method_missing. a = a def fed a = a return nruter a = p end ; fed ; def dne p = a p a ; a p end ; dne He breaks palindrome with a single semicolon here. Sets the variable a to nil, (because the second a is a method call), and defines the method fed to return the return value of nruter (which at this moment is a method_missing call, and stays that way for the rest of the program) The line a = p end is acutally two statements: an a=p, followed by an end. He then goes to immediately define dne to call the p function we saw before, which prints nothing, and the a function which returns nil. So dne is now defined, but does nothing. These 5 lines can actually all be safely removed, since they define methods which do the same thing as method_missing anyway. def h ax0=0xa;return 0xa unless ax0;dne;y=x p;fed = def p x=y;end; 0xa;sselnu ax0;nruter ax0=0xa;h fed bx0, dx0 = 0xd, 0xb bx0 + dx0 + 0xb + bx0 + 0xd + 0xb end ; dne def h ax0=10 return 10 unless ax0 y=nil fed = nil def p x=y end bx0=13 dx0=11 bx0 + dx0 + 11 + bx0 + 13 + 11 # equals 13 + 11 + 11 + 13 + 13 + 11 which is 72 end In short, if nil is explicitly passed to h, it returns 10. If anything else (or nothing) is passed to h, it defines p (in the global context) to do nothing, then returns 72 (ascii for 'H'). def Object.const_missing a ; a gnissim_tsnoc.tcejbO; fed return send(a.to_s.downcase) ; (esacnwod.s_ot.a);dnes nruter end ; dne All the stuff on the right side of the semicolons does nothing. The const_missing is intended to convert the H constant reference on the next line to a call to the h method we just defined. (This will return the ascii code for 'H', which is what we need to start the sequence of Integer.method_missing calls on the next line. H.e.l.l.o._.w.o.r.l.d! ; !d.l.r.o.w._.o.l.l.e.H The left side prints out the string "Hello_world" using the integer method_missing chaining that I mentioned above. (The last call to d! prints out the letter "d", as mentioned above.) The right side calls the global method_missing repeatedly, which does nothing. In other words, all of this code actually translates to: (Everything else is calls method_missing which returns nil, or calls a method which is functionally equivalent to method_missing.) class Integer def method_missing a, *b print chr return a.to_s[0] end def d! return (d.e and puts) end end def h return 72 end def Object.const_missing a return send(a.to_s.downcase) end H.e.l.l.o._.w.o.r.l.d! -- Ken (Chanoch) Bloom. PhD candidate. Linguistic Cognition Laboratory. Department of Computer Science. Illinois Institute of Technology. http://www.iit.edu/~kbloom1/