[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

How to preserve $~ when extending Regexp#match

Brendan Baldwin

7/18/2006 10:13:00 PM

Consider the following Regexp/MatchData extension, which pops a copy of
the original Regexp into the MatchData object resulting from
Regexp#match. Forget for a minute *why* anyone might want to do this:

class Regexp
alias_method :original_match, :match
def match(str)
m=self.original_match(str)
m.regexp=self unless m.nil?
m
end
end
class MatchData
attr_accessor :regexp
end

Because of the magical nature of the $~ global variable and its
derivatives $&,$+,$`,$',$1-9, we wind up losing it from scope with this
extension to the Regexp class:

/myregexp/.match("test my regexp")
$~ # <= nil

Is anyone out there aware of any way to set $~ in the "caller's" binding
from within Regexp#match *without* requiring a manual call_stack to be
implemented via set_trace_func?

Thanks!

--Brendan Baldwin :: ruby-forum@brendanbaldwin.com

--
Posted via http://www.ruby-....

5 Answers

Eric Hodel

7/18/2006 11:28:00 PM

0

On Jul 18, 2006, at 3:13 PM, Brendan Baldwin wrote:

> Because of the magical nature of the $~ global variable and its
> derivatives $&,$+,$`,$',$1-9, we wind up losing it from scope with
> this
> extension to the Regexp class:
>
> /myregexp/.match("test my regexp")
> $~ # <= nil
>
> Is anyone out there aware of any way to set $~ in the "caller's"
> binding
> from within Regexp#match *without* requiring a manual call_stack to be
> implemented via set_trace_func?

I played around with this for MetaRuby and couldn't find a way to
implement it. I believe it is impossible outside of set_trace_func/
evil.rb level hackery.

--
Eric Hodel - drbrain@segment7.net - http://blog.se...
This implementation is HODEL-HASH-9600 compliant

http://trackmap.rob...



Mauricio Fernández

7/18/2006 11:50:00 PM

0

On Wed, Jul 19, 2006 at 07:13:10AM +0900, Brendan Baldwin wrote:
> Consider the following Regexp/MatchData extension, which pops a copy of
> the original Regexp into the MatchData object resulting from
> Regexp#match. Forget for a minute *why* anyone might want to do this:
>
> class Regexp
> alias_method :original_match, :match
> def match(str)
> m=self.original_match(str)
> m.regexp=self unless m.nil?
> m
> end
> end
> class MatchData
> attr_accessor :regexp
> end
>
> Because of the magical nature of the $~ global variable and its
> derivatives $&,$+,$`,$',$1-9, we wind up losing it from scope with this
> extension to the Regexp class:
>
> /myregexp/.match("test my regexp")
> $~ # <= nil
>
> Is anyone out there aware of any way to set $~ in the "caller's" binding
> from within Regexp#match *without* requiring a manual call_stack to be
> implemented via set_trace_func?

hmm the only general way I'm aware of does use Binding.of_caller (and
therefore set_trace_func), see for instance [150292]. However, if your method
took a block, it'd be easily doable.

Silly example:

class Regexp
alias_method :_original_match, :match
def match(*str, &block)
if block_given?
md = _original_match(yield)
eval("lambda{|x| $~ = x}", block).call($~)
else
md = _original_match(*str)
end
md.regexp = self if md
md
end
end

class MatchData
attr_accessor :regexp
end

/myregexp/.match{"test myregexp"}
# note the syntax change; you might find this unacceptable :-|
$~ # => #<MatchData:0xa7d26fd4>
$~.regexp # => /myregexp/
$~.pre_match # => "test "


Sorry if this doesn't really help.

--
Mauricio Fernandez - http://eige... - singular Ruby

Brendan Baldwin

7/19/2006 3:17:00 PM

0

Mauricio --

The block implentation is pretty cool -- My problem is I was trying to
modify Regexp#match for use with a production application at my current
employer, which also uses the REXML library, that unfortunately uses $~
vars all over and doesn't use blocks to get at them, so it breaks.

And I'm constrained in not using set_trace_func here, so that's
unfortunatlely out of the picture too.

*Sigh*

Darn little esoteric PERLy $~ !! Oh well. Spent more time than I
should have on this already... Perhaps Ruby 1.9 or 2.0 will give us
caller bindings for free some day.

--Brendan

Mauricio Fernandez wrote:
> On Wed, Jul 19, 2006 at 07:13:10AM +0900, Brendan Baldwin wrote:
>> end
>> $~ # <= nil
>>
>> Is anyone out there aware of any way to set $~ in the "caller's" binding
>> from within Regexp#match *without* requiring a manual call_stack to be
>> implemented via set_trace_func?
>
> hmm the only general way I'm aware of does use Binding.of_caller (and
> therefore set_trace_func), see for instance [150292]. However, if your
> method
> took a block, it'd be easily doable.
>
> Silly example:
>
> class Regexp
> alias_method :_original_match, :match
> def match(*str, &block)
> if block_given?
> md = _original_match(yield)
> eval("lambda{|x| $~ = x}", block).call($~)
> else
> md = _original_match(*str)
> end
> md.regexp = self if md
> md
> end
> end
>
> class MatchData
> attr_accessor :regexp
> end
>
> /myregexp/.match{"test myregexp"}
> # note the syntax change; you might find this unacceptable :-|
> $~ # => #<MatchData:0xa7d26fd4>
> $~.regexp # => /myregexp/
> $~.pre_match # => "test "
>
>
> Sorry if this doesn't really help.


--
Posted via http://www.ruby-....

Pit Capitain

7/19/2006 5:01:00 PM

0

Brendan Baldwin schrieb:
> And I'm constrained in not using set_trace_func here, so that's
> unfortunatlely out of the picture too.

Brendan, can you tell us why you're not allowed to use set_trace_func?

Regards,
Pit

Dominik Bathon

7/19/2006 5:57:00 PM

0

On Wed, 19 Jul 2006 17:16:51 +0200, Brendan Baldwin
<ruby-forum@brendanbaldwin.com> wrote:

> Mauricio --
>
> The block implentation is pretty cool -- My problem is I was trying to
> modify Regexp#match for use with a production application at my current
> employer, which also uses the REXML library, that unfortunately uses $~
> vars all over and doesn't use blocks to get at them, so it breaks.
>
> And I'm constrained in not using set_trace_func here, so that's
> unfortunatlely out of the picture too.

Are C extension okay?

In that case you could use rb_backref_set() to achieve what you want.


Dominik