Why does Ruby define Object#=~? - ruby

After reading a comment to an answer in another question and doing a little research, I see that =~ is defined on Object and then overridden by String and Regexp. The implementations for String and Regexp appear to assume the other class:
"123" =~ "123" # => TypeError: type mismatch: String given
/123/ =~ /123/ # => TypeError: can't convert Regexp to String
Although =~ is defined for Object, + is not:
Object.new =~ 1 # => nil
Object.new + 1 # => undefined method `+' for #<Object:0x556d38>
Why has Object#=~ been defined, rather than restricting =~ to to String and Regexp?

Because it allows any object to be used in a match expression:
Object.new =~ /abc/
=> nil
I guess this makes sense in the way that Object.new does not match the regexp /abc/ and the code would blow up if the left argument wasn't a String object. So it generally simplifies the code because you can have any object on the left side of the =~ operator.

Well, I suppose that's actually nicely answered in String =~ documentation:
Match — If obj is a Regexp, use it as a pattern to match against str,and
returns the position the match starts, or nil if there is no match.
Otherwise, invokes obj.=~, passing str as an argument. The default =~
in Object returns nil.
The point is, you can write your own implementation of Object =~ - and it will be used in String =~ Not Regexp statement.

From your comments, your actual question is why is =~ defined on Object while + isn't.
The reason is that Object#=~ can return nil for random objects (since they don't match), but Object#+ can not return a meaningful result.
It is not necessarily super useful, but it can not be said to be false (you would have to show a match to prove that a nil result is a contradiction). See the mathematical concept of vacuous truth. On the other hand, any result for Object.new + 1 could lead to contradictions.
This is similar to <=> that can return nil (and is thus also defined on Object) while <, >, ..., can not return true nor false while being completely consistent. Note that for Class#> it was decided to return nil in those cases.

Related

Ruby =~ vs === Operators

I had mostly been using === for matching values to patterns in Ruby. Recently, I discovered that the language also supports the =~ operator for regular expressions.
The Ruby Documentation defines === as "case equality" and =~ as "pattern match".
Case Equality – For class Object, effectively the same as calling #==, but typically overridden by descendants to provide meaningful semantics in case statements.
Pattern Match—Overridden by descendants (notably Regexp and String) to provide meaningful pattern-match semantics.
By experimentation, I find that === works for regular expressions, class names, literal values, and even ranges, while =~ only seems to return useful values for regular expressions. My question is: why would I ever use =~? It seems like === supports everything =~ does and then some. Is there something I'm missing here that =~ is intended to do differently?
Firstly, =~ is symmetric:
'string' =~ /regex/
And
/regex/ =~ 'string'
Both work.
Secondly as you noted, === works with other classes. If you want to match strings, you should be using the operator for... matching. It is called case operator for a reason - case uses it internally.
case foo
when bar then x
when baz then y
else z
end
Is the same as:
if bar === foo
x
elsif baz === foo
y
else
z
end
Explicitly using === is considered unidiomatic.
str = "Something is amiss."
r = /me/
r === str #=> true
str =~ r #=> 2
What if you want to know if there's a match and if so, where it begins?

Ruby: =~ symbol - what does it mean [duplicate]

I saw this on a screencast and couldn't figure out what it was. Reference sheets just pile it in with other operators as a general pattern match operator.
It matches string to a regular expression.
'hello' =~ /^h/ # => 0
If there is no match, it will return nil. If you pass it invalid arguments (ie, left or right-hand sides are not correct), it will either throw a TypeError or return false.
From ruby-doc :
str =~ obj => fixnum or nil
Match—If obj is a Regexp, use it as a pattern to match against str, and returns the offset position the match starts, or nil if there is no match. Otherwise, invokes obj.=~, passing str as an argument. The default =~ in Object returns false.
"cat o' 9 tails" =~ /\d/ #=> 7
"cat o' 9 tails" =~ 9 #=> false
Well, the reference is correct, it is the "matches this regex" operator.
if var =~ /myregex/ then something end
As the other answers already stated, =~ is the regular expression vs string match operator.
Note: The =~ operator is not commutative
Please consider the note below from the ruby doc site, as I have seen yet only the first form
str =~ regexp
used in the other answers:
Note: str =~ regexp is not the same as regexp =~ str. Strings captured
from named capture groups are assigned to local variables only in the
second case.
Here is the documentation for the second form: link
Regular expression string matching. Here's a detailed list of operators: http://phrogz.net/programmingruby/tut_expressions.html#table_7.1
Regular expression string matching:
puts true if url =~ /google.com/
You can read '=~' as 'is matching'.
I believe this is a pattern matching operator used with regex.

Test if a regexp does not match the beginning of a string without using .nil?

I'm testing some strings to make sure they start with a letter:
name =~ /\A[a-zA-Z].*/
but since in Ruby this evaluates to either nil or 0 and both cast to false, I need to put an additional .nil? test:
if(name =~ /\A[a-zA-Z].*/).nil? ...
Is this the proper way or am I missing something?
EDIT:
Thanks for the replies, in my ignorance I made wrong assumptions, oversimplified the example. It should read (note the negation):
name !=~ /\A[a-zA-Z].*/
irb(main):001:0> a = "abc"
=> "abc"
irb(main):006:0> (a !=~/\Aabc/)
=> true
irb(main):007:0> (a !=~/\Ab/)
=> true
but since in Ruby this evaluates to either nil or 0 and both cast to false
wrong, only nil (and false, to be precise) are treated as false in conditionals. 0 is treated as true. So
if name =~ /\A[a-zA-Z].*/
is perfectly ok.
About your edited question, you're not allowed to add exclamation sign (!) to any operator to make it negated operator. There's no such operator (BTW, these 'operators' are actually methods) as !=~, so to achieve your goal. you should do:
if !(name =~ /\A[a-zA-Z].*/)
or you can use unless instead:
unless name =~ /\A[a-zA-Z].*/

/ell/ === 'Hello' true in Ruby. Why?

This code:
/ell/ === 'Hello'
evalutes to 'true' in IRB.
I don't understand why this makes sense logically. Integer === 30 makes sense because 30 is a PART OF the Integer class, but in what way is the string 'Hello' a PART OF /ell/? I don't get it.
Semantically you're saying does the regular expression 'ell' match the string 'Hello'. Since 'Hello' contains the substring 'ell', it is true.
The '===' method is described here:
http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-i-3D-3D-3D
You should not use === for anything in ruby except case equality, find the documentation on Regex#===
Following a regular expression literal with the === operator allows you to compare against a String.
/^[a-z]$/ === "HELLO" #=> false
/^[A-Z]$/ === "HELLO" #=> true
The === the case operator, it is primarily used in case statements and should not really be seen by its own.
case my_string
when /ll/ then puts 'the string migth be hello'
when /x/ then puts 'all i know is that the sting contain x'
else puts 'I have no idea'
end
It can also be used in some other functions such as grep:
array = ['ll', 'aa', 'hello']
p array.grep(/ll/){|x| x.upcase} #=> ["LL", "HELLO"]
Any other use is discouraged and it really does not need to make any sense.
A regular expression describes a language, i.e. a set of strings. The === checks whether the string is a member of that set.
See my answer to a similar question for details.

What is the "=~" operator in Ruby?

I saw this on a screencast and couldn't figure out what it was. Reference sheets just pile it in with other operators as a general pattern match operator.
It matches string to a regular expression.
'hello' =~ /^h/ # => 0
If there is no match, it will return nil. If you pass it invalid arguments (ie, left or right-hand sides are not correct), it will either throw a TypeError or return false.
From ruby-doc :
str =~ obj => fixnum or nil
Match—If obj is a Regexp, use it as a pattern to match against str, and returns the offset position the match starts, or nil if there is no match. Otherwise, invokes obj.=~, passing str as an argument. The default =~ in Object returns false.
"cat o' 9 tails" =~ /\d/ #=> 7
"cat o' 9 tails" =~ 9 #=> false
Well, the reference is correct, it is the "matches this regex" operator.
if var =~ /myregex/ then something end
As the other answers already stated, =~ is the regular expression vs string match operator.
Note: The =~ operator is not commutative
Please consider the note below from the ruby doc site, as I have seen yet only the first form
str =~ regexp
used in the other answers:
Note: str =~ regexp is not the same as regexp =~ str. Strings captured
from named capture groups are assigned to local variables only in the
second case.
Here is the documentation for the second form: link
Regular expression string matching. Here's a detailed list of operators: http://phrogz.net/programmingruby/tut_expressions.html#table_7.1
Regular expression string matching:
puts true if url =~ /google.com/
You can read '=~' as 'is matching'.
I believe this is a pattern matching operator used with regex.

Resources