* [ruby-core:119572] [Ruby master Bug#20807] String#gsub fails when called from string subclass with a block passed
@ 2024-10-21 11:07 koilanetroc (Oleg Tolmashov) via ruby-core
2024-10-23 3:03 ` [ruby-core:119594] " Dan0042 (Daniel DeLorme) via ruby-core
0 siblings, 1 reply; 2+ messages in thread
From: koilanetroc (Oleg Tolmashov) via ruby-core @ 2024-10-21 11:07 UTC (permalink / raw)
To: ruby-core; +Cc: koilanetroc (Oleg Tolmashov)
Issue #20807 has been reported by koilanetroc (Oleg Tolmashov).
----------------------------------------
Bug #20807: String#gsub fails when called from string subclass with a block passed
https://bugs.ruby-lang.org/issues/20807
* Author: koilanetroc (Oleg Tolmashov)
* Status: Open
* ruby -v: ruby 3.3.4 (2024-07-09 revision be1089c8ec) [arm64-darwin23]
* Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
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:
```ruby
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!
--
https://bugs.ruby-lang.org/
______________________________________________
ruby-core mailing list -- ruby-core@ml.ruby-lang.org
To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/
^ permalink raw reply [flat|nested] 2+ messages in thread
* [ruby-core:119594] [Ruby master Bug#20807] String#gsub fails when called from string subclass with a block passed
2024-10-21 11:07 [ruby-core:119572] [Ruby master Bug#20807] String#gsub fails when called from string subclass with a block passed koilanetroc (Oleg Tolmashov) via ruby-core
@ 2024-10-23 3:03 ` Dan0042 (Daniel DeLorme) via ruby-core
0 siblings, 0 replies; 2+ messages in thread
From: Dan0042 (Daniel DeLorme) via ruby-core @ 2024-10-23 3:03 UTC (permalink / raw)
To: ruby-core; +Cc: Dan0042 (Daniel DeLorme)
Issue #20807 has been updated by Dan0042 (Daniel DeLorme).
Regexp.last_match and other regexp-related pseudo globals do not work across more than one stack frame. Since you override #gsub, they are set only inside MyString#gsub
You can confirm with this:
```ruby
def test(klass)
p klass
klass.new("test").gsub(/s/,'x')
p result: $~
end
class MyString1 < String
end
test(MyString1)
#prints:
#{:result=>#<MatchData "s">}
class MyString2 < String
def gsub(...)
super
ensure
p ensure: $~
end
end
test(MyString2)
#prints:
#{:ensure=>#<MatchData "s">}
#{:result=>nil}
```
It would be possible to fix this by propagating Regexp.last_match up every "super" stack frame until we reach the originating non-super frame. It would allow some interesting use cases (like logging the time spent in every Regexp#match). But it's a lot of work for a very niche use.
----------------------------------------
Bug #20807: String#gsub fails when called from string subclass with a block passed
https://bugs.ruby-lang.org/issues/20807#change-110216
* Author: koilanetroc (Oleg Tolmashov)
* Status: Open
* ruby -v: ruby 3.3.4 (2024-07-09 revision be1089c8ec) [arm64-darwin23]
* Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN
----------------------------------------
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:
```ruby
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!
--
https://bugs.ruby-lang.org/
______________________________________________
ruby-core mailing list -- ruby-core@ml.ruby-lang.org
To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org
ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2024-10-23 3:03 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-21 11:07 [ruby-core:119572] [Ruby master Bug#20807] String#gsub fails when called from string subclass with a block passed koilanetroc (Oleg Tolmashov) via ruby-core
2024-10-23 3:03 ` [ruby-core:119594] " Dan0042 (Daniel DeLorme) via ruby-core
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).