views:

97

answers:

3

I'm currently reading Agile Web Development With Rails, 3rd edition. On page 672, I came across this method:

def capitalize_words(string)
  string.gsub(/\b\w/) { $&.upcase }
end

What is the code in the block doing? I have never seen that syntax. Is it similar to the array.map(&:some_method) syntax?

+4  A: 

It's Title Casing The Input. inside the block, $& is a built-in representing the current match (\b\w i.e. the first letter of each word) which is then uppercased.

Jimmy
+2  A: 

gsub replaces everything that matched in the regex with the result of the block. so yes, in this case you're matching the first letter of words, then replacing it with the upcased version.

as to the slightly bizarre syntax inside the block, this is equivalent (and perhaps easier to understand):

def capitalize_words(string)
  string.gsub(/\b\w/) {|x| x.upcase}
end

or even slicker:

def capitalize_words(string)
  string.gsub /\b\w/, &:upcase
end

as to the regex (courtesy the pickaxe book), \b matches a word boundary, and \w any 'word character' (alphanumerics and underscore). so \b\w matches the first character of the word.

Peter
+2  A: 

You've touched on one of the few things I don't like about Ruby :)

The magic variable $& contains the matched string from the previous successful pattern match. So in this case, it'll be the first character of each word.

This is mentioned in the RDoc for String.gsub:

http://ruby-doc.org/core/classes/String.html#M000817

Paul Osman
Oh dear. I thought I'd escaped this type of syntax when I left Perl behind ...
Duncan Bayne
it's optional syntax only, and discouraged...
Peter
As I said, one of the few things I don't like about Ruby. Wish Matz left magic variables with Perl.
Paul Osman
Peter's answer (below) shows two more readable versions, neither of which uses the global variable. (Or, more accurately, any use of that global is bound up in the way `String#gsub` passes variables to a block -- how it does so is left up to the Ruby implementation.)
James A. Rosen