Project

General

Profile

Actions

Bug #20807

open

String#gsub fails when called from string subclass with a block passed

Added by koilanetroc (Oleg Tolmashov) 15 days ago. Updated 13 days ago.

Status:
Open
Assignee:
-
Target version:
-
ruby -v:
ruby 3.3.4 (2024-07-09 revision be1089c8ec) [arm64-darwin23]
[ruby-core:119572]

Description

When String#gsub is called from a string subclass with a block, Regexp.last_match is nil, but passed block is executed. Here is example code:

def call_gsub(str)
  str.gsub(/%/) do
    puts "checking #{str.class}"
    puts "Special variable value: #{$&}"
    puts "Regexp.last_match = #{Regexp.last_match.inspect}\n\n"

    raise "Special variable $& is not assigned, but block is called" if $&.nil?
  end
end

class MyString < String
  def gsub(*args, &block)
    super(*args, &block) # just forward everything
  end
end

text = 'test%text_with_special_character'

call_gsub(String.new(text)) # original string
call_gsub(MyString.new(text)) # string subclass

Result:

checking String
Special variable value: %
Regexp.last_match = #<MatchData "%">

checking MyString
Special variable value:
Regexp.last_match = nil

gsub_bug.rb:7:in `block in call_gsub': Special variable $& is not assigned, but block is called (RuntimeError)
	from gsub_bug.rb:13:in `gsub'
	from gsub_bug.rb:13:in `gsub'
	from gsub_bug.rb:2:in `call_gsub'
	from gsub_bug.rb:20:in `<main>'

I expect result to be the same for both classes since MyString just wraps the same method:

checking String
Special variable value: %
Regexp.last_match = #<MatchData "%">

checking MyString
Special variable value: %
Regexp.last_match = #<MatchData "%">

Maybe there is something off with with control frame when params are forwarded?

Thanks in advance!

Actions

Also available in: Atom PDF

Like0
Like0