Close
Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

LABS
Block/fu

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 = ?', 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) }
    end

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') % values.map { |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:

Panda

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
  end

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

Comments
  1. Dr Nic says:

    Oooh, I didn’t know gsub took a block. *rubs hands together*

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *