Kernel#gsub not working properly with a block

Skip to first unread message

Josep M. Bach

Mar 20, 2011, 2:22:21 PM3/20/11
Hi there!

The following spec does not pass on rbx (in spec/ruby/core/kernel/gsub_spec.rb#78):
  describe "Kernel#gsub with pattern and block" do
    it "acts similarly to using $_.gsub" do
      $_ = "olleh dlrow"
      gsub(/(\w+)/){ $1.reverse }
      $_.should == "hello world"
Trying to fix this one, I found that there is a comparison of replacement (in this case it is nil, because gsub is passed a block instead of a replacement string) with undefined, which always evaluates to false (even if it is nil). Since I don't know really well what `undefined` is, I've first tried comparing replacement to nil, which seems to work (in kernel/common/string.rb#902):

  def gsub(pattern, replacement=undefined)
    # ...
    if replacement.nil? # was if replacement == undefined
Now the problem is that, when evaling the block { $1.reverse }, $1 is nil. Upon further inspection, This happens just before evaling the block, where Regexp's last match is (unsuccessfully) set to the intended match data (same file, #939):
      if use_yield
        # Although `match` contains actual match data,
        Regexp.last_match = match
        # Here Regexp.last_match is nil.
        # So this block evaluation will fail when trying to do nil.reverse
        val = yield(match.to_s)
I've tried it in the rbx console, so it seems Regexp.last_match=(matchdata) (although it returns the passed matchdata) does nothing to Regexp.last_match (it keeps previous matched data, or nil if it was nil).

I've checked the regexp.cpp file but I'm no expert there, so I can't tell what's wrong....

Any thoughts?
Reply all
Reply to author
0 new messages