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 :: ruby-forum@brendanbaldwin.com

···

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

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.

···

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?

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

http://trackmap.robotcoop.com

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.

···

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?

--
Mauricio Fernandez - http://eigenclass.org - singular Ruby

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 :expressionless:
$~ # => #<MatchData:0xa7d26fd4>
$~.regexp # => /myregexp/
$~.pre_match # => "test "

Sorry if this doesn't really help.

--
Posted via http://www.ruby-forum.com/\.

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

Are C extension okay?

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

Dominik

···

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.