A while back I stumbled across a page of JAPHs, or Just Another Perl Hacker scripts. This was an ongoing competition Perl users had years ago to print the phrase “Just Another Perl Hacker” in the most convoluted way possible, utilizing little-known tricks of the language. They usually stuffed these mini-scripts into their Usenet signatures. I had always admired JAPHs, and decided to try my hand at a Ruby version. But I needed a forum, and I hadn’t been on Usenet in years.
So what’s the modern version? Why, Twitter, of course! The 140-character limit would provide an extra level of challenge, enough so that I didn’t feel a need restrict myself to printing “Just Another Ruby Hacker”.
I started simple, printing a wave to STDOUT.
ruby -e "i=0;loop{puts ' '*(29*(Math.sin(i)/2+1))+'|'*(29*(Math.cos(i)/2+1)); i+=0.1}"
#ruby
Copy-paste that to a terminal, and hit Enter. (If you copy from Twitter, there’s no need to worry about line breaks or the Favorite star; the browser strips them.) You get something like this:
||||||||||||||||||||||||||||||||||||||||||| |||||||||||||||||||||||||||||||||||||||||| |||||||||||||||||||||||||||||||||||||||| |||||||||||||||||||||||||||||||||||||| |||||||||||||||||||||||||||||||||| |||||||||||||||||||||||||||||| ||||||||||||||||||||||||| ||||||||||||||||||||| |||||||||||||||||| ||||||||||||||| |||||||||||||| |||||||||||||| ||||||||||||||| |||||||||||||||||| ||||||||||||||||||||| ||||||||||||||||||||||||| |||||||||||||||||||||||||||||| |||||||||||||||||||||||||||||||||| |||||||||||||||||||||||||||||||||||||| ||||||||||||||||||||||||||||||||||||||||| |||||||||||||||||||||||||||||||||||||||||| ||||||||||||||||||||||||||||||||||||||||||| |||||||||||||||||||||||||||||||||||||||||| |||||||||||||||||||||||||||||||||||||||| ||||||||||||||||||||||||||||||||||||| |||||||||||||||||||||||||||||||||| ||||||||||||||||||||||||||||| ||||||||||||||||||||||||| ||||||||||||||||||||| ...
Here’s a more-readable version:
That’s still among my favorites. But anybody can use puts(). The next was more ambitious…
ruby -rtk -e "w=TkCanvas.new(TkRoot.new{title:paint});w.pack.bind('B1-Motion',proc{|x,y|TkcOval.new(w,x,y,x+4,y+4)},'%x %y').mainloop"
#ruby
That’s my entry for world’s smallest paint program.
Again, let’s unpack that:
I did a bunch of other Tk snippets, too. Then I switched to Curses (which lets you present GUI-like environments in the shell) to change it up. This one draws a Lissajous curve:
ruby -rcurses -e"include Curses;i=0;loop{setpos 12*(Math.sin(i)+1),40*(Math.cos(i*0.2)+1);addstr'.';i+=0.01;refresh}"
#ruby
Once more with legibility:
That was enough for graphical stuff. I moved on to playing with the Ruby language itself…
#ruby
-e'def f(o);o.methods.each{|n|m = o.method(n);puts %Q/#{m}:#{m[*[o]*m.arity.abs]}/ rescue 1};end;f 1;f "r";f [1]*9;f({:a=>1});f 1..9'
#ruby That prior one-liner calls every method it can on an integer, string, array, hash, and range. Use with caution on other objects!
@jamesbritt If Ruby is a sharp knife, then I just spent the afternoon waving it around. :)
via web in reply to jamesbritt
Expanded code:
I don’t blame you if you don’t want to run this yourself; I did it in a VM the first time. But it seems you can’t do much harm with Integers and Hashes. I got output like this:
... #<Method: String#to_sym>:rr #<Method: String#capitalize>:Rr #<Method: String(Enumerable)#max>:rr #<Method: Array#inspect>:[1, 1, 1, 1, 1, 1, 1, 1, 1] #<Method: Array#compact>:111111111 #<Method: Array#<<>:111111111[...] #<Method: Array(Kernel)#clone>:111111111111111111[...] #<Method: Array#empty?>:false ...
Like the others, this one was meant for pasting into a shell (within a Rails project’s root), but it didn’t take immediate effect… The echo x >> config/environments/development.rb
appended the Ruby snippet to the development configuration file. Then, you just wait for your victim to start a server…
echo ";class <<STDOUT;def write(*a);super(*a.map{|o|o.reverse});end;end#pair+=crazy">>config/environments/development.rb
That last one’s for the #rails people. :)
@logan_barnett it creates an object-specific class for STDOUT (an IO object) and overrides write() (which all output passes through).
Here’s a plain Ruby script with the same effect…
That outputs:
"yzarc=+riap" 100 !dlrow ,olleH
So of course, when your poor pair programmer goes to look at the Rails log in the console, you can stifle your laughter as they puzzle over output like this:
$ ruby script/server => Booting Mongrel => Rails 2.3.3 application starting on http://0.0.0.0:3000 hcated ot d- htiw llaC >= revres nwodtuhs ot C-lrtC >= )dnuof_ton( tuoyal/seucser gniredneR :)}teg:>=dohtem:{ htiw "raboof/" sehctam etuor oN( rorrEgnituoR::rellortnoCnoitcA ]TEG[ )24:20:02 81-40-0102 ta 1.0.0.721 rof( xedni#rellortnoCnoitacilppA gnissecorP
I did another version that piped everything through the “banner” command. :) I’ll let your twisted little minds think up other possibilities.
Squeezing all this logic into 140 characters is pretty demanding. I wondered if I could use dynamic method calls to do shorthand…
`ruby -e “def method_missing(*m);s=m.shift;method(methods.find{ n n=~/^#{s}/})[*m];end;p ‘XXzAzTTzq’.rev.sp(/z/).map{ l l.sq.suc}.jo.sw”
Which is the most convoluted way imaginable to output:
"Ruby"
So it looks like you can do shorthand, but unfortunately my implementation costs more characters than it saves. I may revisit that someday and use the extra space to write a fully-functional webserver in a tweet. :)
For the finale, let’s go back to Tk…
ruby -rtk -e"include Math;c=TkCanvas.new.pack;r=99;0.step(r,0.03){|a|TkcArc.new(c,x=r*sin(a)+r,y=r*cos(a)*sin(0.9*a)+r,x+4,y+4)};c.mainloop"
That’s adapted from Creative Graphics on the BBC Microcomputer, John Cownie, 1982. Shaving those last 3 characters off was REALLY hard. :P
You know most of my techniques by now, so I’ll leave that tweet for you to decipher. That tiny bit of code generates a surprisingly-complex Lissajous yarn ball:
So there you have it: the arguably useless art of Ruby Tweets. I did a search with Google’s Twitter tool and learned that I’m not the only one attempting stuff like this, although others’ tweets are much less, um, frivolous. But there’s not a ton of material out there. I think this is a fun challenge, and I’d be curious to see what others can come up with!
If you’d like to see more, be sure to follow me on Twitter. And if you do anything cool, drop me a line so I can retweet it!