How to preserve $~ when extending Regexp#match

B

Brendan Baldwin

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 :eek:riginal_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 :: (e-mail address removed)
 
E

Eric Hodel

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

Mauricio Fernandez

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 :eek:riginal_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.
 
B

Brendan Baldwin

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 said:
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.
 
P

Pit Capitain

Brendan said:
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
 
D

Dominik Bathon

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,119
Latest member
IrmaNorcro
Top