[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Behavior of $* in String subclasses

Jamis Buck

6/11/2005 7:29:00 PM

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


4 Answers

Nikolai Weibull

6/11/2005 7:40:00 PM

0

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:/...!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}


nobu.nokada

6/12/2005 2:22:00 AM

0

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


Jamis Buck

6/12/2005 4:09:00 AM

0

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
>>

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-...,
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


nobu.nokada

6/12/2005 4:54:00 AM

0

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