Extrange String#=~ behaviour


#1

Hi, I can’t understand it:

class String
def =~ obj
puts “Sorry, I don’t compare”
end
end

a) OK
irb> “string” =~ 1234
Sorry, I don’t compare
nil

b) ¿?
irb> “string” =~ /string/
0

c) OK
irb> “string”.send(:"=~", 1234)
Sorry, I don’t compare
nil

d) OK
irb> “string”.send(:"=~", /string/)
Sorry, I don’t compare
nil

Could I know why case “b” perform the normal regexp comparission instead
of
invoking the re-defined String#=~ method??

Thanks.


#2

Sorry, the subject must be “Strange” :slight_smile:


#3

Iñaki Baz C. wrote:

Hi, I can’t understand it:

class String
def =~ obj
puts “Sorry, I don’t compare”
end
end

b) ¿?
irb> “string” =~ /string/
0

Could I know why case “b” perform the normal regexp comparission instead
of
invoking the re-defined String#=~ method??

To me that suggests that String#=~ calls Regexp#=~. However, I am
having no luck proving that. I can’t even override Regexp#=~:

class Regexp
def =~(obj)
puts “goodbye”
end
end

puts /string/ =~ “string” #0


#4

On Wed, Feb 25, 2009 at 8:05 AM, 7stud – removed_email_address@domain.invalid
wrote:

irb> “string” =~ /string/
0

Turns out using Regexp.new behaves as expected:

07> “string” =~ Regexp.new(‘string’)
Sorry, I don’t compare
–> nil

class Regexp
def =~(obj)
puts “goodbye”
end
end

puts /string/ =~ “string” #0

In this case too:

08> Regexp.new(‘string’) =~ “string”
goodbye
–> nil

Ruby 1.9 rdoc for Regexp#=~ hints at special treatment for regexp
literals [1]:
“This assignment is implemented in the Ruby parser. So a regexp
literal is required for the assignment. The assignment is not occur if
the regexp is not a literal.”
But that is in the context of assigning to ? type named captures
within a regexp on the LHS, so i don’t know if it’s relevant.

Hope someone who knows the implementation can shed more light.

Cheers,
lasitha.

[1] http://ruby-doc.org/core-1.9/classes/Regexp.html#M001214


#5

2009/2/25 Brian C. removed_email_address@domain.invalid:

You can see that your case (b) is parsed differently as a :match3,
bypassing the normal method dispatch (:call)

Interesting, thanks a lot.


#6

Iñaki Baz C. wrote:

Could I know why case “b” perform the normal regexp comparission instead
of
invoking the re-defined String#=~ method??

ParseTree gem may help you.

$ cat strange.rb
class String
def =~ obj
puts “Sorry, I don’t compare”
end
end

r1 = “string” =~ 1234
r2 = “string” =~ /string/
r3 = “string”.send(:"=~", 1234)
r4 = “string”.send(:"=~", /string/)

$ parse_tree_show strange.rb
s(:block,
s(:class,
:String,
nil,
s(:scope,
s(:defn,
:=~,
s(:scope,
s(:block,
s(:args, :obj),
s(:fcall, :puts, s(:array, s(:str, “Sorry, I don’t
compare”)))))))),
s(:lasgn, :r1, s(:call, s(:str, “string”), :=~, s(:array, s(:lit,
1234)))),
s(:lasgn, :r2, s(:match3, s(:lit, /string/), s(:str, “string”))),
s(:lasgn,
:r3,
s(:call, s(:str, “string”), :send, s(:array, s(:lit, :=~), s(:lit,
1234)))),
s(:lasgn,
:r4,
s(:call,
s(:str, “string”),
:send,
s(:array, s(:lit, :=~), s(:lit, /string/)))))
$

You can see that your case (b) is parsed differently as a :match3,
bypassing the normal method dispatch (:call)