Ruby puzzler: gsub, blocks, and procs

  • Posted By Stuart Halloway on February 13, 2008

See if you can guess what this code will do before you run it in ruby.

upc = Proc.new {|m| $1.upcase}

puts "hello world".gsub(/([aeiou])/, &upc)
puts "hello world".gsub(/(\w)/, &upc)

def doit(str, re, blk)
  puts str.gsub(re, &blk)
end

doit "hello world", /([aeiou])/, upc
doit "hello world", /(\w)/, upc

Now try running it in JRuby. Whoa.

Comments
  1. Aaron BlohowiakFebruary 14, 2008 @ 01:57 AM

    D? huh?

  2. Aaron BlohowiakFebruary 14, 2008 @ 01:58 AM

    Oh, right. Scope binding. Yay.

  3. szeryfFebruary 14, 2008 @ 08:11 AM

    out of curiosity, what does it do in JRuby? works “correctly”? :)

  4. edbondFebruary 14, 2008 @ 12:43 PM

    rubinius passed the test ;)

  5. Michael NiessnerFebruary 14, 2008 @ 03:49 PM

    I really liked this post. Thanks.

  6. Andrew AvenosoFebruary 14, 2008 @ 08:32 PM

    Looks like another good reason to not use perl style global variables changing upc = Proc.new {|m| $1.upcase} to upc = Proc.new {|m| m.upcase} works as expected

  7. David AltenburgFebruary 21, 2008 @ 02:01 AM

    Yargh, I was bitten by this about a year ago…it’s still the nastiest thing I’ve found in Ruby. When researching it, I found this Ruby-talk thread useful:

    http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/79283

    Note that Matz advices that you avoid the perl-style variables.

    When I ran into this, I was trying (ill-advisedly) to wrap all the methods of String class in something in Rails, and Rails uses (or at least did use) those globals, blowing everything to pieces.