How to preserve $~ when extending Regexp#match

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 :: [email protected]

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

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 H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

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

$~ # => #MatchData:0xa7d26fd4
$~.regexp # => /myregexp/
$~.pre_match # => "test "

Sorry if this doesn’t really help.

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 F. 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 :expressionless:

$~ # => #MatchData:0xa7d26fd4
$~.regexp # => /myregexp/
$~.pre_match # => "test "

Sorry if this doesn’t really help.

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

On Wed, 19 Jul 2006 17:16:51 +0200, Brendan Baldwin
[email protected] 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

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs