Here's an interesting snafu I ran into today:
class Substring < String
def sub!(pat, r=nil, &b)
super(pat, r, &b)
# --------------------
p $1 # -> "ll"
# --------------------
end
end
s = Substring.new("hello")
s.sub!(/(ll)/, "r")
# --------------------
p $1 # -> nil!!!
# --------------------
The captured subgroup in the regexp is correctly assigned to $1 when examined inside the overridden #sub! method, but when checked after the invocation of the overridden method, the value of $1 is nil.
Why?
- Jamis
Jamis Buck wrote:
The captured subgroup in the regexp is correctly assigned to $1 when
examined inside the overridden #sub! method, but when checked after
the invocation of the overridden method, the value of $1 is nil.
A related example of something resembling something I was trying once:
def a
/abc/.match("abc")
end
def b
p $~[0]
end
a; b
=> NoMethodError: undefined method `[]' for nil:NilClass
My conclusion was that $~ and its relatives weren’t as global as their
insignia might suggest.
Why?
I was wondering the same thing but figured that it was desired behavior
as I found no previous discussion of it on the mailing list,
nikolai
···
--
Nikolai Weibull: now available free of charge at http://bitwi.se/!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}
Hi,
At Sun, 12 Jun 2005 04:29:27 +0900,
Jamis Buck wrote in [ruby-talk:145177]:
class Substring < String
def sub!(pat, r=nil, &b)
super(pat, r, &b)
m = eval("proc{$~}", b).call # get caller's MatchData
# --------------------
p $1 # -> "ll"
# --------------------
p m[1] # -> "ll"
···
end
end
--
Nobu Nakada
Hmmm. Either I'm misunderstanding you, or you misunderstood me.
This still doesn't allow the caller of Substring#sub! to access the captured subgroups via the $digit variables.
However, further hunting has uncovered (among other information) http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/79303, which seems to indicate that there is no way to do this in Ruby. Thus, I've changed my approach. I was basically trying to discover whether a String has been modified and was inserting code to capture the self-modifying methods and set a flag. Instead, I've changed it to do the following:
class Substring < String
def initialize(str="")
super(str)
reset_dirty!
end
def dirty?
@original_contents != self
end
def reset_dirty!
@original_contents = dup
end
end
I don't like having to do #dup, but it's not that big of a deal because Ruby does copy-on-write anyway and the string's contents won't be copied until the string is actually modified (right?). Anyway, this seems to work, and still allows sub! to work right with captured subgroups. Calling #dirty? is more expensive than I would like, but it won't be called very frequently.
- Jamis
···
On Jun 11, 2005, at 8:22 PM, nobu.nokada@softhome.net wrote:
Hi,
At Sun, 12 Jun 2005 04:29:27 +0900,
Jamis Buck wrote in [ruby-talk:145177]:
class Substring < String
def sub!(pat, r=nil, &b)
super(pat, r, &b)
m = eval("proc{$~}", b).call # get caller's MatchData
# --------------------
p $1 # -> "ll"
# --------------------
p m[1] # -> "ll"
end
end
Hi,
At Sun, 12 Jun 2005 13:09:28 +0900,
Jamis Buck wrote in [ruby-talk:145191]:
>> class Substring < String
>> def sub!(pat, r=nil, &b)
>> super(pat, r, &b)
>>
$~ = eval("proc{$~}", b).call
>
>> # --------------------
>> p $1 # -> "ll"
>> # --------------------
>>
>> end
>> end
>>
Hmmm. Either I'm misunderstanding you, or you misunderstood me. 
This still doesn't allow the caller of Substring#sub! to access the
captured subgroups via the $digit variables.
$digit variables are just wrappers of $~.
···
--
Nobu Nakada