Code Safari: Almost Sinatra, Almost Readable

Sinatra is a minimal web framework for creating web applications in Ruby with minimal effort. Almost Sinatra is the same thing, but in only eight lines of code. Surely some trickery is afoot? Let’s have a look at those lines.

# almost-sinatra/almost_sinatra.rb
%w.rack tilt backports INT TERM..map{|l|trap(l){$r.stop}rescue require l}
$n=Sinatra=Module.new{extend Rack;a,D,S,$p,q,Application=Builder.new,Object.method(:define_method),/@@ *([^n]+)n(((?!@@)[^n]*n)*)/m,4567,a
%w[get post put delete].map{|m|D.(m){|u,&b|a.map(u){run->(e){[200,{"Content-Type"=>"text/html"},[a.instance_eval(&b)]]}}}}
Tilt.mappings.map{|k,v|D.(k){|n,*o|$t||=(h={};File.read(caller[0][/^[^:]+/]).scan(S){|a,b|h[a]=b};h);v.new(*o){n.to_s==n ?n:$t[n.to_s]}.render(a,o[0].try(:[],:locals)||{})}}
%w[set enable disable configure helpers use register].map{|m|D.(m){|*_,&b|b.try :[]}};END{Handler.get("webrick").run(a,Port:$p){|s|$r=s}}
%w[params session].map{|m|D.(m){q.send m}};a.use Session::Cookie;a.use Lock
D.(:before){|&b|a.use Rack::Config,&b};before{|e|q=Request.new e;q.params.dup.map{|k,v|params[k.to_sym]=v}}}
puts "== almost #$n/No Version has taken the stage on #$p for development with backup from Webrick"

That’s the lot of it. Sure is dense! There are some gems in here, so let’s start picking it apart, line by line. Reading obfuscated code is a great way to jump in the deep end and really get personal with a language’s syntax, and by the end of this article you’ll be ready to move in and leave dirty dishes on the couch.

Line One

I have taken the first line and reformatted it across multiple to make it easier to read. This is always my first step when dealing with obfuscated code. Often renaming variables to something meaningful can also be helpful too, though I haven’t done that in this article.

%w.rack tilt backports INT TERM..map{|l|
  trap(l) {
    $r.stop
  } rescue require l
}

What is that initial syntax? It looks like a list given the #map call trailing it, but it’s like no list I’ve seen. This type of code is hard to find information on, since googling for punctuation is rarely useful. Given it looks like an array, I took a punt and searched for ‘ruby array syntax’ which revealed the arrays section in the ruby programming wikibook:

%w is in essence shorthand for the String method split when the substrings are separated by whitespace only.

The example given uses ' as a delimiter, and using irb we can confirm that we can use any punctuation after the %w. The choice of which to use is solely a matter of style.

%w'rack tilt' # => ["rack", "tilt"]
%w.rack tilt. # => ["rack", "tilt"]
%w(rack tilt) # => ["rack", "tilt"]
%w!rack tilt! # => ["rack", "tilt"]

Now turn our attention to the contents of the list – it seems to contain both files to require and signals to rescue. Since rack, tilt, and backports are all invalid signal names, the #trap call will raise an exception. Normally in ruby exceptions are rescued explicitly:

begin
  trap("bogus signal name") {}
rescue ArgumentError => e
  puts "Invalid signal name"
end

Ruby also allows a trailing form though, in the same way that you can do with if statements.

puts "Small enough" if line_count <= 10
trap("bogus") {} rescue puts ":("

This will rescue all exceptions though, which isn’t the sort of cowboy behaviour you want to spread liberally through your code base. Not to mention using exceptions for flow control, but when lines are at a premium everything is fair game.

Line Two

With the requires and other preamble out of the way, let’s dive into the framework proper.

$n = Sinatra = Module.new {
  extend Rack;
  a,D,S,$p,q,Application = 
    Builder.new,
    Object.method(:define_method),
    /@@ *([^n]+)n(((?!@@)[^n]*n)*)/m,
    4567,
    a

There are a few interesting techniques here. The first is dynamically defining a Module. In ruby everything is an object, even modules and classes, so where you would normally use the module keyword to define a module, you can do so on the fly by calling Module.new. The only difference is that the keyword form will have an explicit name and constant defined, whereas the latter will be anonymous.

module Test
end
 
Test.name       # => 'Test'
Module.new.name # => nil

Variable names prefixed with $ are not seen often, so they may be unfamiliar to you. Searching for ‘ruby variable types’ found an article with a handy table summarizing the different prefixes, and in this case we find that a variable beginning with $ is a global variable. That would be why you don’t see them so often…

There are two forms of variable assignment used here. The one used on the first line relies on the fact that everything in ruby implicitly returns a value. You can see this in irb – every statement executed has a value shown after it, even it is often nil.

# puts returns the value 'nil'
irb> puts "hello"
hello
 => nil

Assignment returns the value being assigned, meaning that you can chain them together. In the snippet above, this means that $n and Sinatra will be assigned the same Module.

irb> $n = Sinatara = Module.new {}
irb> $n == Sinatra 
 => true

The other assignment trick being used is called multiple or parallel assignment, which allows you to assign different values to different variables all on the one line. What is interesting about this usage is that one of the variables on the left hand side a is reused on the right hand side to assign to the Application constant. I was very confused by this for a while, but after playing around in irb confirmed it is actually a bug in the code!

a,Application=1,a # => [1, nil]
a=1;Application=a

Line Three

This line sets up methods for the different HTTP verbs, and to comprehend it we would first need to first be familiar with the Rack::Builder API, since an instance of this class is assigned to the D variable. That’s a bit of a tangent, so I am going to leave that for a future article, and instead focus on the two interesting syntax features this snippet uses, both related to lambdas and introduced in ruby 1.9.

%w[get post put delete].map{|m|
  D.(m){|u,&amp;b|
    a.map(u){
      run->(e){
        [200,{"Content-Type"=>"text/html"},[a.instance_eval(&amp;b)]]
      }
    }
  }
}

The first is a new way of calling lambas and procs, .(), which is an alias for #call. This brings the total number of ways to call a lambda in ruby to three:

add_two = lambda {|x| x + 2 }
add_two.call(1) # => 3
add_two.(1)     # => 3
add_two[1]      # => 3

There are subtle differences: .() will always delegate to #call whereas [] can be overridden separately, but for the most part they are equivalent.

The other interesting syntax is run->(e){}. This is affectionately known as the “stabby” syntax, and is a new way of defining lambdas that was introduced to allow default argument values to be specified. This would be impossible for the ruby parser to deal with using the old run(lambda {|e| }) syntax (more details if you are keen).

add_two       = lambda {|x| x + 2}
add_two       = ->(x) { x + 2 }       # The same!
double_or_add = ->(a,b=a|2) { a + b } # Just try that with the old syntax...

The old syntax is going to be around forever, but the new way gives you a less verbose, more flexible option.

And the rest

Told you it was dense! A whole article and we are only three lines in. On the other hand, it’s half way through a framework! We covered a lot of interesting syntax in a short amount of time:

  • %w array syntax
  • Trailing rescue syntax
  • Anonymous modules using Module.new
  • Chaining assignment (a = b = 1)
  • Multiple assignment (a,b = 1,2)
  • .() syntax for calling code blocks
  • ->() “stabby” syntax for writing lambdas

The remaining lines are mostly more of the same, but there a couple of curve balls. For practice, I recommend you continue to work through them. Other projects to sharpen your knife on:

  • Camping, the 4k pocket full-of-gags web microframework. This is an old-school framework that has been around for years. It includes an unabridged version and as such is a relatively gentle introduction to obsfucated code.
  • It’s old, but entries to the 2005 International Obfuscated Ruby Code Contest, helpfully mirrored in this blog post.

Let us know how you go in the comments. Tune in next week for more exciting adventures in the code jungle.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://www.thepursuitofquality.com Gavin Miller

    Xavier – Great article. As someone who is still learning ruby, it’s refreshing to get a post like this to stretch my knowledge.

    One thing that I couldn’t figure out was the parallel assignment. In the code you’ve provided there are 6 variables: a,D,S,$p,q,Application
    However, there are only 5 assignments on the right hand side of the equation: Builder.new, Object.method(:define_method), the regex, 4567, a

    You mention later that D = Builder.new, so what gets assigned to a?

    • http://xaviershay.com/ Xavier Shay

      Thanks Gavin. In this case, the last variable on the LHS is assigned `nil`. You can confirm this in `irb`.

      > a,b,c=1,2
      => [1, 2]
      > c
      => nil

  • JeffMo

    I believe there is a typo in one of your examples for Line Two. (“Sinatara”)

    Nice post. People interested in this sort of stuff might also enjoy doing a web search for the phrase “Ruby golf” (or “code golf” for the more general idea).

  • Robert Speicher

    There’s some problems with the line two and line three sections.

    “This line sets up methods for the different HTTP verbs, and to comprehend it we would first need to first be familiar with the Rack::Builder API, since an instance of this class is assigned to the D variable.”

    D is assigned as a shortcut to “define_method”. It’s ‘a’ that’s assigned to Builder.new, and by my count, “Application” isn’t actually assigned to anything in the code you’ve shown (there are 6 variables and only 5 assignments).

    • Robert Speicher

      Disregard the variable assignment part, I’m a dumb-dumb.

  • http://7fff.com John

    I think you touch on (not necessarily explain) the $r in the first line, and how it doesn’t even exist as a variable until line 6 (if I read the code correctly) . . .

  • https://github.com/rkh Konstantin Haase

    How did I miss this article? Awesome!

  • http://www.tomsquest.com Tom

    Thanks for this article.
    The code safari serie is really interesting.

    Good job !

    Tom