Redefining Regexp#===

P

Pit Capitain

Hi,

what's wrong with this code:

class Regexp
alias :case_eq :===
def ===( other )
case_eq( other )
end
end

p( /x/ === "abxy" ) # => true
p( Regexp.last_match ) # => nil
p( /x/.case_eq( "abxy" ) ) # => true
p( Regexp.last_match ) # => #<MatchData:0x2a67460>

Why is Regexp.last_match not set when calling the redefined method?
This is ruby 1.8.2 (2004-12-25) [i386-mswin32] on Windows 2000.

Regards,
Pit
 
D

daz

Pit Capitain said:
Hi,

what's wrong with this code:

class Regexp
alias :case_eq :===
def ===( other )
case_eq( other )
end
end

p( /x/ === "abxy" ) # => true
p( Regexp.last_match ) # => nil
p( /x/.case_eq( "abxy" ) ) # => true
p( Regexp.last_match ) # => #<MatchData:0x2a67460>

Why is Regexp.last_match not set when calling the redefined method?
This is ruby 1.8.2 (2004-12-25) [i386-mswin32] on Windows 2000.


Hi Pit,

Regexp#=== is an alias for =~ , therefore need to alias both, I think:

class Regexp
alias :case_eq :=~
alias :case_eq :===
def =~( other )
case_eq( other )
end
end

p( /x/ === "abxy" ) # => true
p( Regexp.last_match ) # => #<MatchData:0x264a588>
p( /x/.case_eq( "abxy" ) ) # => true
p( Regexp.last_match ) # => #<MatchData:0x264a4f8>


You'll know what to do :)

Regards,

daz
 
D

daz

I said:
Regexp#=== is an alias for =~ , therefore need to alias both, I think:


Sorry folks. I fooled myself with a plausible-looking test :-(

Pit's question is still open.


daz
 
M

Mauricio Fernández

Sorry folks. I fooled myself with a plausible-looking test :-(

Pit's question is still open.

batsman@tux-chan:/tmp$ cat wrapre.rb

require 'binding_of_caller'

class Regexp
alias_method :case_eq, :===

def ===(other)
Binding.of_caller do |b|
case_eq(other)
eval("lambda{|x| $~ = x}", b).call($~)
nil != $~
end
end
end

# former results...
p(/x/ === "abxy") # => true
p(Regexp.last_match) # => nil
p(/x/.case_eq("abxy")) # => true
p(Regexp.last_match) # => #<MatchData:0x2a67460>

batsman@tux-chan:/tmp$ ruby wrapre.rb
true
#<MatchData:0x401d05b8>
true
#<MatchData:0x401d0450>
 
M

Mauricio Fernández

/tmp$ cat wrapre.rb
=20
require 'binding_of_caller' [...]
# former results...
p(/x/ =3D=3D=3D "abxy") # =3D> true
p(Regexp.last_match) # =3D> nil
p(/x/.case_eq("abxy")) # =3D> true
p(Regexp.last_match) # =3D> #<MatchData:0x2a67460>
=20
batsman@tux-chan:/tmp$ ruby wrapre.rb
true
#<MatchData:0x401d05b8>
true
#<MatchData:0x401d0450>

I forgot to add that you can probably rewrite Regexp.last_match (using
thread-local vars) if you don't really care about $~ itself; the obvious
implementation requires several other redefinitions though
({Kernel,String}#gsub(!?), String#scan, etc.).

--=20
Mauricio Fernandez
 
C

Caleb Clausen

Hi,
=20
what's wrong with this code:
=20
class Regexp
alias :case_eq :=3D=3D=3D
def =3D=3D=3D( other )
case_eq( other )
end
end
=20
p( /x/ =3D=3D=3D "abxy" ) # =3D> true
p( Regexp.last_match ) # =3D> nil
p( /x/.case_eq( "abxy" ) ) # =3D> true
p( Regexp.last_match ) # =3D> #<MatchData:0x2a67460>
=20
Why is Regexp.last_match not set when calling the redefined method?
This is ruby 1.8.2 (2004-12-25) [i386-mswin32] on Windows 2000.

I have discovered that $1 and the like and Regexp.last_match behave
differently than I expected. These all behave like local variables in
the method that calls the Regexp matching method, even tho they look
like global variables and a class method.

Your =3D=3D=3D doesn't work the expected way because it's no longer the
magical built-in version, which exports the local variables $1 and
friends and Regexp.last_match to it's immediate caller.

I don't think there's a way to workaround this behaviour. This is bad
actually; it means there's no safe way to override Regexp#=3D=3D=3D,
Regexp#match, etc safely, so that the callers still have all the same
old behaviour.

Regexp#last_match cannot be usefully overridden because you can't call
the original method in the override to retrieve the MatchData... it
ends up always nil.

I really hope the current behavior can be changed..... I need to be
able to override =3D=3D=3D and match safely. Can't these variables be made
thread globals instead of locals? Or at least provide a way to
re-export the matching local vars to your own caller? Or actually be
able to overrride Regexp.last_match?

Ps: why do you want this?
 
P

Pit Capitain

Caleb said:
I have discovered that $1 and the like and Regexp.last_match behave
differently than I expected. These all behave like local variables in
the method that calls the Regexp matching method, even tho they look
like global variables and a class method.
...

Thank you and Mauricio for your answers.
Ps: why do you want this?

See [ruby-talk:150244], where Garance wanted to be able to define
regular expressions together with code to process the matches in one
place. I liked the idea and was experimenting with overriding Regexp
methods, when I noticed this unexpected behaviour.

Regards,
Pit
 

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

Staff online

Members online

Forum statistics

Threads
474,176
Messages
2,570,950
Members
47,501
Latest member
log5Sshell/alfa5

Latest Threads

Top