On-the-floor

On the Floor

Going To The Source Of Open Source

One of the the best ways to improve your programming skills is to study other people's code.  When your work revolves around open-source technology, you can study the code you use every day.

This has several advantages: you get to study code written by the very best programmers out there, you have an excellent idea of the problem it solves, and you gain a deeper understanding of your tools.

One of those tools is Rack, the interface, or middleware, between web servers and many popular Ruby frameworks, including our two favourites, Rails and Sinatra.  Rack is an incredible piece of software that has brought an enviable consistency to Ruby web development.

Last night I was watching Olympic speed skating while sitting on the couch.  I took advantage of the interminable delays between races caused by technical issues, damaged ice, and so on, to browse Rack's source code, in particular the code for Rack::Request.

It wasn't my intention to gain an understanding of the entire file, rather, I was just interested in seeing what I could learn from bits and pieces.  This method caught my eye:

This looked like an interesting way of turning text like "text/plain;charset=utf-8" into a hash.  Problems like this arise pretty frequently when you're doing development, so I decided to hack this apart.  The easiest way to do this, I think, is to turn this bit into a stand-alone file, separate the method chains into new lines, and add a debugger line:

This allows us to step through the code line-by-line to see how content_type is transformed throughout the method.  If you're interested, give it a try (just download the file and run it from the command line).

What I think is especially interesting is line 9:

This use of inject provides a simple and effective way of creating a hash from a pair of other values, in the process transforming them.

Today as I worked on a project, I found some code I wrote recently that looked like this:

Given a hash (representing an interval) like { :weeks => 4 }, this will return { :weeks => -4 }.

The similarity between this and the code from Rack was pretty self-evident.  In both cases, we are creating a new collection containing transformed values from a previous collection.  New version of this:

For me, this was a compelling example of the utility of reading open-source code: immediate applicability to one's own work, with the reward of better code - and better understanding.

Comments

On February 16 2010 at 4:30PM Chris said:

I think you typo'd your new inject method:

interval.inject({}) { |interval,(k,v)| interval[k] = v.abs * -1; interval }

On February 16 2010 at 4:40PM ozzloy said:

consider using Hash#update instead:

interval.inject({}){|interval,(k,v)| interval.update({k=>v.abs*-1})}

and line 9 from your debug example becomes:

inject({}) { |hash,(k,v)| hash.update({k.downcase => v })}

On February 16 2010 at 9:41PM Adrian said:

Chris, it's not a typo - inject returns the memo, which is the value I am looking for.

ozzloy, thanks for the interesting suggestion.

On February 17 2010 at 11:29AM Ben Marini said:

Chris is right, the block for inject needs to return the hash, currently in your example it returns a Fixnum.

Too bad hash doesn't have a smarter #map... http://gist.github.com/306771

On February 17 2010 at 1:27PM Adrian said:

I just ran into the issue that Chris pointed out and went here to recant my last comment - he's right. Thanks Chris and Ben, making the correction.

Add a Comment

Your Comment:

Your Name:

Your Email Address: (Won't be published)

Your Website: (If you've got one)