April 30, 2008 Pivotal Labs

This is the second article on idiomatic Rubyisms that I like. Today’s snippet is also from ActiveRecord.

The following method takes :conditions arrays of the form ['foo_id = ?',] and turns them into safely quoted SQL strings:

    def replace_bind_variables(statement, values)
      bound = values.dup
      statement.gsub('?') { quote_bound_value(bound.shift) }

The calling gsub with a block and shifting off of the bound values inside the block is so cute that I want to give it a hug. You know, I cut my teeth doing functional programming and I usually have this aversion to such a side-effect-heavy style. But treating gsub as an iterator — and using shift as a kind of index into the iteration — is so elegant you have to love it. It makes you remember that sometimes things are beautiful because they are imperative, not despite.

Of course, you could write this purely:

statement.gsub('?', '%%s') % { |v| quote_bound_value(v) }

(I’m showing off here a bit with the % (percent) operator on String.) So this latter code is pure and it’s clear. It may even be more terse than the imperative version since it lacks the duping of the values array. But I don’t know about you but I don’t want to give this functional code a hug. The imperative version is like a baby panda bear:


Don’t you want to hug that? Whereas the Functional Version is like kind of like a Japanese carp.

If there’s any lesson from this it’s: know which standard library methods take a block.

Here is some code I hacked up recently somewhat in the spirit of the gsub-with-block approach above:

  [relation1[attribute], relation2[attribute]].select { |a| a =~ attribute }.min do |a1, a2|
    attribute % a1 <=> attribute % a2

Don’t ask what this code does, it’s not what you think (this is operator overloading taken to its psychedelic conclusion). But note the use of min taking a block. This is the same as providing a custom ordering relation to sort, a pretty common idiom in many languages. But here I’m not interested in sorting attributes based on their intrinsic hashrocketness; rather, i need to sort them based on a comparison to some other object. min takes a block gsub takes a block sort takes a block… you’d be surprised at what takes a block. Look it up.

Now, I know some of you are going to say, “I did look it up, and that’s
not true.” That’s ’cause you looked it up in a book. Next time, look it
up in your gut.
— Stephen Colbert

About the Author


use photobooth to exchange ideas quickly
use photobooth to exchange ideas quickly

Draw something on an index card Run photobooth Edit => Auto Flip New Photos Take a photo of your index card...

Ruby Pearls vol. 1 – The Splat
Ruby Pearls vol. 1 – The Splat

Over the next week or so I'll be sharing Ruby idioms and flourishes that I quite like. Today I'd I'll show ...

SpringOne 2021

Register Now