How is `Proc#==` evaluated? - ruby

How is Proc#== evaluated? RDoc says:
prc == other_proc → true or false
Returns true if prc is the same object as other_proc, or if they are both procs with the same body.
But it is not clear what counts as having "the same body". One condition seems to be that the arity must be the same:
->{} == ->{} # => true
->{} == ->x{} # => false
->x{} == ->x{} # => true
->x{} == ->y{} # => true
->x{} == ->y,z{} # => false
But there is more than that. As RDoc says, the body matters:
->{nil} == ->{nil} # => true
->{nil} == ->{false} # => false
->{false} == ->{false} # => true
But at the same time, it looks like the proc is not fully evaluated:
->{} == ->{nil} # => false
->{false} == ->{1 == 2} # => false
To what extent is the body evaluated?

This has changed in Ruby 2.0, so you should not try to compare Procs. They won't be == unless they are exactly the same object.
The discussion can be found here.
If you really need to compare the code of two blocks and are using MRI, you can play around with RubyVM::InstructionSequence.disassemble(block), or even better in Ruby 2.0 RubyVM::InstructionSequence.of(block).

To answer that question lets look at the proc comparison code
static VALUE
proc_eq(VALUE self, VALUE other)
{
if (self == other) {
return Qtrue;
}
else {
if (rb_obj_is_proc(other)) {
rb_proc_t *p1, *p2;
GetProcPtr(self, p1);
GetProcPtr(other, p2);
if (p1->envval == p2->envval &&
p1->block.iseq->iseq_size == p2->block.iseq->iseq_size &&
p1->block.iseq->local_size == p2->block.iseq->local_size &&
MEMCMP(p1->block.iseq->iseq, p2->block.iseq->iseq, VALUE,
p1->block.iseq->iseq_size) == 0) {
return Qtrue;
}
}
}
return Qfalse;
}
The first if branch is quite simple - compare it two procs are the same object.
The second is little bit more tricky. It checks that both of the procs have same envval, size of the iseq(proc implementation), local variables size and compares that the both implementations are identical. That means that proc equality is checked on a syntax level, not on proc result.
Lets take https://gist.github.com/4611935
First sample works just fine because number of local variables are the same and the sequence of operations are the same. Assign 123 to local variable. The second sample treated as not same because operation sequence differs - you assign 123 to different variables.
But yes, proc comparison is pretty confusing and has been removed form ruby 2.0 I presume. Now procs are compared as a regular object by its id.

Related

Why does an empty String returns false when comparing to boolean in ruby?

It might be a dumb question, but can someone please explain this:
if ""
true
else
false
end
=> true (OK)
!!("")
=> true (OK)
"" === true
=> false (OK)
"" == true
=> false (But why?)
Have a nice day!
The basic concept of this question is a deep misunderstanding of Ruby operators. Here's the short of it - there's no such thing as operators in Ruby! All this !, =, == and === that you throw around - these are not operators.
So what's going on?
Ruby is an object oriented language (a real one, not like that fake Java and JavaScript things) and all these fancy character sequences you think of as operators are actually method calls on the object in their left:
== method usually checks for equality - is the object on the right equal in content.
=== method is not used for "strict equality" or "identity" like it is often in other languages - some Ruby objects that implement it use it for "membership" tests, like in ranges ((1..3) === 2 ==> true) or regular expressions (/el/ === "hello" ==> true you can think of regular expressions as the group of all strings that would match), others implement it as equals.
So - how is the if working? Well, if and other "forced boolean contexts" check for "falsehood". In Ruby we recognize two false values - false and nil, everything else will run the truth branch of an if. This is actually the method ! that you also used in your second example. This method is implemented in BasicObject to return true for all objects, except if the object's type is the type of false - FalseClass or the type for nil - NilClass, in which case it returns true.
So your examples actually mean:
Check for the truthiness of "". Because that value's type is neither FalseClass or NilClass, it is always true.
For the value "", call the method ! - which will return false because the object is neither a FalseClass or a NilClass - then call ! on the result, which will return true because false is a FalseClass instance.
For the value "" call the method === with the argument true, but since it is an alias for == - call that instead (see 4).
For the value "" call the method == with the argument true. String's implementation of == will never return true for an argument that isn't a String type.
The only falsy values in Ruby are false and nil. Everything else is "truthy," but not necessarily equal to true. This includes empty objects like a String, Hash, or Array.
Pragmatically, it might help to think of == as "comparably equivalent to" rather than "equals." For example:
1 == 1.0 #=> true
This is true even though one is an Integer and one is a Float because they are comparably equivalent in value, even if they aren't the same object or of the same type.
In the same way, "" is truthy because it is not comparably equivalent to false or nil. However, it's also not the same object type as true, nor comparably equivalent to true. An empty String is simply "not falsy," which makes it truthy but not actually true.
Remember, only false and nil are falsy. Everything else, and I mean everything, is truthy even if it isn't strictly speaking true.
In Ruby, the only "falsey types" are FalseClass and NilClass, which have the instances false and nil respectively. All other values are considered "truthy". This is possibly different to what you'd expect coming from other C-like values, in which we do things like this pretty freely:
int x = get_value();
if (x) { /* implied x != 0 }
So, if you had something like this in Ruby:
puts 0 if 0 # => "0"
puts 1 if "" # => "1"
puts 2 if [] # => "2"
puts 3 if false # => nil
puts 4 if true # => "4"
puts 5 if nil # => "5"
So, if "" acts truthy, why isn't it equal to true? If that were how we defined ==, then this would also need to resolve to true then, since both values are truthy:
"1" == "2"
The difference here is that == is asking if two things are the same, which "" and true are most certainly not. Further, Ruby does not automatically convert types for you (like other languages like JavaScript do), so "" does not automatically get converted to a boolean during its comparison.

Inject double ampersand operator

I have an inject call
[2,4,6].inject(true) { |res, val| res && val % 2 == 0 }
and want to send the && operator to inject as in inject(0, :+). How can I do that?
You can't because && and ||, unlike other operators, are not syntacic sugar for methods (i.e. there is no method called && or ||), so you can't reference them using a symbol.
However you can avoid using inject to compute the logical conjunction or disjunction of an array of boolean values, replacing it with all? or any? respectively, because for any array the following conditions hold:
ary.inject(true) { |res, b| res && b } == ary.all?
ary.inject(false) { |res, b| res || b } == ary.any?
So, for example, the code you posted could be rewritten as:
[2,4,6].map(&:even?).all?
# => true
Update: obviously my latter example is not the right way to express this computation, falsetru's answer is much faster:
require 'fruity'
compare(
-> { (0..1000).map(&:even?).all? },
-> { (0..1000).all?(&:even?) }
)
Running each test 1024 times. Test will take about 2 seconds.
Code 2 is faster than Code 1 by 111x ± 10.0
How about using Enumerable#all?
[2,4,6].all? &:even?
# => true
[2,4,6,5].all? &:even?
# => false
If you want to use inject, you need to define an instance method.
class Object
def is_even(val)
self && val % 2 == 0
end
end
[2,4,6].inject(true, :is_even) # => true
[1,2,4,6,5].inject(true, :is_even) # => false
'&&' is not a method, hence you can't inject it. However you can inject & method.
[2,4,6,5].map(&:even?).inject(true, :&)
Which will do the same
NOTE: This however should not be done, as it is extremely risky and might cause unexpected consequences (if run on collection containing at least one non-boolean (true, false, nil) value). You should always use any? or all? methods instead.
inject(0, :+) would add all the elements of the array, regardless of what the content of the elements are (odd, even, etc).
If you want to inject(true, &:&&) (I know this doesn't work), your array should be an array of boolean values for your question to make sense, which would be the same as: [true, false].all?
important:
you can't pass both block arg and actual block which means you can't check if it's even inject an && at the same time.
If you insist, try this out:
[2,4,6].inject(true, & lambda { |x,y| x && y })
=> 6
This is the equivalent of what you're asking for (which I still don't totally understand)

Why can procs be invoked with === in ruby 1.9?

This article mentions 4 ways to invoke procs in ruby 1.9, and === is one of them. I don't understand why this would be done this way at all. Does it have any relationship to the normal meaning of === (asking if the two objects are the same object)?
irb(main):010:0> f =-> n {[:hello, n]}
=> #
irb(main):011:0> f.call(:hello)
=> [:hello, :hello]
irb(main):012:0> f === :hello
=> [:hello, :hello]
irb(main):013:0> Object.new === Object.new
=> false
irb(main):014:0> f === f
=> [:hello, #]
Note that === in Ruby is NOT about equality, unlike JavaScript. It is specifically used for case expressions:
case cats.length
when 42 # Uses 42 === cats.length
puts :uh
when /cool/i # Uses /cool/i === cats.length
puts :oh
when ->(n){ n.odd? || n/3==6 } # Passes cats.length to the proc
puts :my
end
This is what the docs have to say:
It is to allow a proc object to be a target of when clause in the
case statement.
This is a, perhaps contrived, example:
even = proc { |x| x % 2 == 0 }
n = 3
case n
when even
puts "even!"
else
puts "odd!"
end
It works because the case/when is basically executed like this:
if even === n
puts "even!"
else
puts "odd!"
end
The case/when checks which branch to execute by calling === on the arguments to when clauses, picking the first that returns a truthy value.
Despite its similarity to the equality operator (==) it not a stronger or weaker form of it. I try to think of the === operator as the "belongs to" operator. Class defines it so that you can check if an object belongs to the class (i.e. is an instance of the class or a subclass of the class), Range defines it as to check if the argument belongs to the range (i.e. is included in the range), and so on. This doesn't really make the Proc case make more sense, but think of it as a tool for making your own belongs to operators, like my example above; I defined an object that can determine if something belongs to the set of even numbers.
This feature is useful in case construction, when you need to calculate something at the comparing.
is_odd =-> n { n%2 != 0 }
is_even =-> n { n%2 == 0 }
case 5
when is_even
puts "the number is even"
when is_odd
puts "the number is odd"
end
=> the number is odd
Does it have any relationship to the normal meaning of === (asking if the two objects are the same object)?
Actually, that's a common misconception about === in Ruby. It's actually not strictly for Object#object_id comparison (although that is its behavior in many common invocations). In Ruby, === is case subsumption.
Here's the description of === from Object: "Case Equality -- For class Object, effectively the same
as calling #==, but typically overridden by descendants
to provide meaningful semantics in case statements."
Sadly, even though it is comprised of three =, it doesn't have anything even remotely to do with equality :-D

What's the difference between equal?, eql?, ===, and ==?

I am trying to understand the difference between these four methods. I know by default that == calls the method equal? which returns true when both operands refer to exactly the same object.
=== by default also calls == which calls equal?... okay, so if all these three methods are not overridden, then I guess
===, == and equal? do exactly the same thing?
Now comes eql?. What does this do (by default)? Does it make a call to the operand's hash/id?
Why does Ruby have so many equality signs? Are they supposed to differ in semantics?
I'm going to heavily quote the Object documentation here, because I think it has some great explanations. I encourage you to read it, and also the documentation for these methods as they're overridden in other classes, like String.
Side note: if you want to try these out for yourself on different objects, use something like this:
class Object
def all_equals(o)
ops = [:==, :===, :eql?, :equal?]
Hash[ops.map(&:to_s).zip(ops.map {|s| send(s, o) })]
end
end
"a".all_equals "a" # => {"=="=>true, "==="=>true, "eql?"=>true, "equal?"=>false}
== — generic "equality"
At the Object level, == returns true only if obj and other are the same object. Typically, this method is overridden in descendant classes to provide class-specific meaning.
This is the most common comparison, and thus the most fundamental place where you (as the author of a class) get to decide if two objects are "equal" or not.
=== — case equality
For class Object, effectively the same as calling #==, but typically overridden by descendants to provide meaningful semantics in case statements.
This is incredibly useful. Examples of things which have interesting === implementations:
Range
Regex
Proc (in Ruby 1.9)
So you can do things like:
case some_object
when /a regex/
# The regex matches
when 2..4
# some_object is in the range 2..4
when lambda {|x| some_crazy_custom_predicate }
# the lambda returned true
end
See my answer here for a neat example of how case+Regex can make code a lot cleaner. And of course, by providing your own === implementation, you can get custom case semantics.
eql? — Hash equality
The eql? method returns true if obj and other refer to the same hash key. This is used by Hash to test members for equality. For objects of class Object, eql? is synonymous with ==. Subclasses normally continue this tradition by aliasing eql? to their overridden == method, but there are exceptions. Numeric types, for example, perform type conversion across ==, but not across eql?, so:
1 == 1.0 #=> true
1.eql? 1.0 #=> false
So you're free to override this for your own uses, or you can override == and use alias :eql? :== so the two methods behave the same way.
equal? — identity comparison
Unlike ==, the equal? method should never be overridden by subclasses: it is used to determine object identity (that is, a.equal?(b) iff a is the same object as b).
This is effectively pointer comparison.
I love jtbandes answer, but since it is pretty long, I will add my own compact answer:
==, ===, eql?, equal?
are 4 comparators, ie. 4 ways to compare 2 objects, in Ruby.
As, in Ruby, all comparators (and most operators) are actually method-calls, you can change, overwrite, and define the semantics of these comparing methods yourself. However, it is important to understand, when Ruby's internal language constructs use which comparator:
== (value comparison)
Ruby uses :== everywhere to compare the values of 2 objects, eg. Hash-values:
{a: 'z'} == {a: 'Z'} # => false
{a: 1} == {a: 1.0} # => true
=== (case comparison)
Ruby uses :=== in case/when constructs. The following code snippets are logically identical:
case foo
when bar; p 'do something'
end
if bar === foo
p 'do something'
end
eql? (Hash-key comparison)
Ruby uses :eql? (in combination with the method hash) to compare Hash-keys. In most classes :eql? is identical with :==.
Knowledge about :eql? is only important, when you want to create your own special classes:
class Equ
attr_accessor :val
alias_method :initialize, :val=
def hash() self.val % 2 end
def eql?(other) self.hash == other.hash end
end
h = {Equ.new(3) => 3, Equ.new(8) => 8, Equ.new(15) => 15} #3 entries, but 2 are :eql?
h.size # => 2
h[Equ.new(27)] # => 15
Note: The commonly used Ruby-class Set also relies on Hash-key-comparison.
equal? (object identity comparison)
Ruby uses :equal? to check if two objects are identical. This method (of class BasicObject) is not supposed to be overwritten.
obj = obj2 = 'a'
obj.equal? obj2 # => true
obj.equal? obj.dup # => false
Equality operators: == and !=
The == operator, also known as equality or double equal, will return true if both objects are equal and false if they are not.
"koan" == "koan" # Output: => true
The != operator, also known as inequality, is the opposite of ==. It will return true if both objects are not equal and false if they are equal.
"koan" != "discursive thought" # Output: => true
Note that two arrays with the same elements in a different order are not equal, uppercase and lowercase versions of the same letter are not equal and so on.
When comparing numbers of different types (e.g., integer and float), if their numeric value is the same, == will return true.
2 == 2.0 # Output: => true
equal?
Unlike the == operator which tests if both operands are equal, the equal method checks if the two operands refer to the same object. This is the strictest form of equality in Ruby.
Example:
a = "zen"
b = "zen"
a.object_id # Output: => 20139460
b.object_id # Output :=> 19972120
a.equal? b # Output: => false
In the example above, we have two strings with the same value. However, they are two distinct objects, with different object IDs. Hence, the equal? method will return false.
Let's try again, only this time b will be a reference to a. Notice that the object ID is the same for both variables, as they point to the same object.
a = "zen"
b = a
a.object_id # Output: => 18637360
b.object_id # Output: => 18637360
a.equal? b # Output: => true
eql?
In the Hash class, the eql? method it is used to test keys for equality. Some background is required to explain this. In the general context of computing, a hash function takes a string (or a file) of any size and generates a string or integer of fixed size called hashcode, commonly referred to as only hash. Some commonly used hashcode types are MD5, SHA-1, and CRC. They are used in encryption algorithms, database indexing, file integrity checking, etc. Some programming languages, such as Ruby, provide a collection type called hash table. Hash tables are dictionary-like collections which store data in pairs, consisting of unique keys and their corresponding values. Under the hood, those keys are stored as hashcodes. Hash tables are commonly referred to as just hashes. Notice how the word hashcan refer to a hashcode or to a hash table. In the context of Ruby programming, the word hash almost always refers to the dictionary-like collection.
Ruby provides a built-in method called hash for generating hashcodes. In the example below, it takes a string and returns a hashcode. Notice how strings with the same value always have the same hashcode, even though they are distinct objects (with different object IDs).
"meditation".hash # Output: => 1396080688894079547
"meditation".hash # Output: => 1396080688894079547
"meditation".hash # Output: => 1396080688894079547
The hash method is implemented in the Kernel module, included in the Object class, which is the default root of all Ruby objects. Some classes such as Symbol and Integer use the default implementation, others like String and Hash provide their own implementations.
Symbol.instance_method(:hash).owner # Output: => Kernel
Integer.instance_method(:hash).owner # Output: => Kernel
String.instance_method(:hash).owner # Output: => String
Hash.instance_method(:hash).owner # Output: => Hash
In Ruby, when we store something in a hash (collection), the object provided as a key (e.g., string or symbol) is converted into and stored as a hashcode. Later, when retrieving an element from the hash (collection), we provide an object as a key, which is converted into a hashcode and compared to the existing keys. If there is a match, the value of the corresponding item is returned. The comparison is made using the eql? method under the hood.
"zen".eql? "zen" # Output: => true
# is the same as
"zen".hash == "zen".hash # Output: => true
In most cases, the eql? method behaves similarly to the == method. However, there are a few exceptions. For instance, eql? does not perform implicit type conversion when comparing an integer to a float.
2 == 2.0 # Output: => true
2.eql? 2.0 # Output: => false
2.hash == 2.0.hash # Output: => false
Case equality operator: ===
Many of Ruby's built-in classes, such as String, Range, and Regexp, provide their own implementations of the === operator, also known as case-equality, triple equals or threequals. Because it's implemented differently in each class, it will behave differently depending on the type of object it was called on. Generally, it returns true if the object on the right "belongs to" or "is a member of" the object on the left. For instance, it can be used to test if an object is an instance of a class (or one of its subclasses).
String === "zen" # Output: => true
Range === (1..2) # Output: => true
Array === [1,2,3] # Output: => true
Integer === 2 # Output: => true
The same result can be achieved with other methods which are probably best suited for the job. It's usually better to write code that is easy to read by being as explicit as possible, without sacrificing efficiency and conciseness.
2.is_a? Integer # Output: => true
2.kind_of? Integer # Output: => true
2.instance_of? Integer # Output: => false
Notice the last example returned false because integers such as 2 are instances of the Fixnum class, which is a subclass of the Integer class. The ===, is_a? and instance_of? methods return true if the object is an instance of the given class or any subclasses. The instance_of method is stricter and only returns true if the object is an instance of that exact class, not a subclass.
The is_a? and kind_of? methods are implemented in the Kernel module, which is mixed in by the Object class. Both are aliases to the same method. Let's verify:
Kernel.instance_method(:kind_of?) == Kernel.instance_method(:is_a?) # Output: => true
Range Implementation of ===
When the === operator is called on a range object, it returns true if the value on the right falls within the range on the left.
(1..4) === 3 # Output: => true
(1..4) === 2.345 # Output: => true
(1..4) === 6 # Output: => false
("a".."d") === "c" # Output: => true
("a".."d") === "e" # Output: => false
Remember that the === operator invokes the === method of the left-hand object. So (1..4) === 3 is equivalent to (1..4).=== 3. In other words, the class of the left-hand operand will define which implementation of the === method will be called, so the operand positions are not interchangeable.
Regexp Implementation of ===
Returns true if the string on the right matches the regular expression on the left.
/zen/ === "practice zazen today" # Output: => true
# is the same as
"practice zazen today"=~ /zen/
Implicit usage of the === operator on case/when statements
This operator is also used under the hood on case/when statements. That is its most common use.
minutes = 15
case minutes
when 10..20
puts "match"
else
puts "no match"
end
# Output: match
In the example above, if Ruby had implicitly used the double equal operator (==), the range 10..20 would not be considered equal to an integer such as 15. They match because the triple equal operator (===) is implicitly used in all case/when statements. The code in the example above is equivalent to:
if (10..20) === minutes
puts "match"
else
puts "no match"
end
Pattern matching operators: =~ and !~
The =~ (equal-tilde) and !~ (bang-tilde) operators are used to match strings and symbols against regex patterns.
The implementation of the =~ method in the String and Symbol classes expects a regular expression (an instance of the Regexp class) as an argument.
"practice zazen" =~ /zen/ # Output: => 11
"practice zazen" =~ /discursive thought/ # Output: => nil
:zazen =~ /zen/ # Output: => 2
:zazen =~ /discursive thought/ # Output: => nil
The implementation in the Regexp class expects a string or a symbol as an argument.
/zen/ =~ "practice zazen" # Output: => 11
/zen/ =~ "discursive thought" # Output: => nil
In all implementations, when the string or symbol matches the Regexp pattern, it returns an integer which is the position (index) of the match. If there is no match, it returns nil. Remember that, in Ruby, any integer value is "truthy" and nil is "falsy", so the =~ operator can be used in if statements and ternary operators.
puts "yes" if "zazen" =~ /zen/ # Output: => yes
"zazen" =~ /zen/?"yes":"no" # Output: => yes
Pattern-matching operators are also useful for writing shorter if statements. Example:
if meditation_type == "zazen" || meditation_type == "shikantaza" || meditation_type == "kinhin"
true
end
Can be rewritten as:
if meditation_type =~ /^(zazen|shikantaza|kinhin)$/
true
end
The !~ operator is the opposite of =~, it returns true when there is no match and false if there is a match.
More info is available at this blog post.
I would like to expand on the === operator.
=== is not an equality operator!
Not.
Let's get that point really across.
You might be familiar with === as an equality operator in Javascript and PHP, but this just not an equality operator in Ruby and has fundamentally different semantics.
So what does === do?
=== is the pattern matching operator!
=== matches regular expressions
=== checks range membership
=== checks being instance of a class
=== calls lambda expressions
=== sometimes checks equality, but mostly it does not
So how does this madness make sense?
Enumerable#grep uses === internally
case when statements use === internally
Fun fact, rescue uses === internally
That is why you can use regular expressions and classes and ranges and even lambda expressions in a case when statement.
Some examples
case value
when /regexp/
# value matches this regexp
when 4..10
# value is in range
when MyClass
# value is an instance of class
when ->(value) { ... }
# lambda expression returns true
when a, b, c, d
# value matches one of a through d with `===`
when *array
# value matches an element in array with `===`
when x
# values is equal to x unless x is one of the above
end
All these example work with pattern === value too, as well as with grep method.
arr = ['the', 'quick', 'brown', 'fox', 1, 1, 2, 3, 5, 8, 13]
arr.grep(/[qx]/)
# => ["quick", "fox"]
arr.grep(4..10)
# => [5, 8]
arr.grep(String)
# => ["the", "quick", "brown", "fox"]
arr.grep(1)
# => [1, 1]
Ruby exposes several different methods for handling equality:
a.equal?(b) # object identity - a and b refer to the same object
a.eql?(b) # object equivalence - a and b have the same value
a == b # object equivalence - a and b have the same value with type conversion.
Continue reading by clicking the link below, it gave me a clear summarized understanding.
https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/equality-matchers
Hope it helps others.
=== #---case equality
== #--- generic equality
both works similar but "===" even do case statements
"test" == "test" #=> true
"test" === "test" #=> true
here the difference
String === "test" #=> true
String == "test" #=> false
.eql? - This operator returns true if the receiver and argument have both the same type and equal values.
for example - 10.eql?(10.0) is false.
=== - it will test equality in case statement.
for example - (1...10) === 1 is true
== - This operator checks whether the two given operands are equal or not. If equals, it returns TRUE, Otherwise it returns FALSE.
for example - (1...10) == 1 is false
for more example click here
I wrote a simple test for all the above.
def eq(a, b)
puts "#{[a, '==', b]} : #{a == b}"
puts "#{[a, '===', b]} : #{a === b}"
puts "#{[a, '.eql?', b]} : #{a.eql?(b)}"
puts "#{[a, '.equal?', b]} : #{a.equal?(b)}"
end
eq("all", "all")
eq(:all, :all)
eq(Object.new, Object.new)
eq(3, 3)
eq(1, 1.0)

What's the difference between == and === when comparing 2 object [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
=== vs. == in Ruby
Fixnum == 2.class
#=> true
Fixnum === 2.class
#=> false
why === doesn't work? and how can I know the method .=== belong to(right now I guess it invoke the Object#==, or Object#===), but how can I make sure of that?
Duplicates:
=== vs. == in Ruby
What does the "===" operator do in Ruby?
=== vs. == in Ruby
Ruby compare objects
Case equality. See the documentation for Object#===. This method is usually overridden in subclasses of Object. For example, Module#===:
Case Equality--Returns true if anObject is an instance of mod or one of mod’s descendants. Of limited use for modules, but can be used in case statements to classify objects by class.
>> Module.new === Module
=> false
>> Module === Module.new
=> true
Regexp#=== is another one, in which case it's a synonym of =~:
a = "HELLO"
case a
when /^[a-z]*$/; print "Lower case\n"
when /^[A-Z]*$/; print "Upper case\n"
else; print "Mixed case\n"
end
An example in IRB:
>> "a" === /a/
=> false
>> /a/ === "a"
=> true
Remember, the first one returns false because you're doing === on String which isn't the same thing. In the second example we're doing === on Regexp
And finally, Range is quite a good one it calls include? on the Range object and passes your value in:
>> (1..100) === 3
=> true
>> (1..100) === 300
=> false
For a list of these, check out RubyDoc.info core documentation and search for === in the methods area in the left side frame
The == usually only checkes the values of both arguments, when ==== checks the types, too.

Resources