Ruby has 3 methods for testing equality: ==, eql? and equal? that are implemented on the Object class. You would think that they are just aliases for doing the same as in Ruby and the Ruby on Rails framework method aliases are common. So, are they?

Checking the doc for Ruby's Object class throws this:

obj == other → true or false
equal?(other) → true or false
eql?(other) → true or false

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.

Unlike ==, the equal? method should never be overridden by subclasses as it is used to determine object identity (that is, a.equal?(b) if and only if a is the same object as b):

Looking at the doc for Object looks like all 3 methods are the same, as ==, eql? and equal? test for object equality (i.e. the same memory reference).

However a quick test shows the following:

2.2.3 :001 > 'test' == 'test'  
 => true 
2.2.3 :003 > 'test'.eql? 'test'  
 => true 
2.2.3 :004 > 'test'.equal? 'test'  
 => false
2.2.3 :005 > 5 == 5.0  
 => true 
2.2.3 :007 > 5.eql? 5.0  
 => false 
2.2.3 :008 > 5.equal? 5.0  
 => false 

If we pay attention the doc says that ==, === and eql? methods should be overriden to provide class specific meaning.

Convention

Of course it would be madness if each class implemented each method in a different way. Lucky for us there is a convention.

== — Value comparison

True when two objects have the same value

2.2.3 :011 > 5 == 5.0  
 => true 
2.2.3 :012 > 'test' == 'test'  
 => true 
2.2.3 :013 > { a: 10 } == { a: 10.0 }  
 => true 
2.2.3 :014 > :test == :test  
 => true 
2.2.3 :016 > ['a', :test, 10] == ['a', :test, 10.0]  
 => true

eql? — Value and type comparison

True when two objects have the same value and type

2.2.3 :028 > 'test'.eql? 'test'  # Strings  
 => true 
2.2.3 :029 > 5.eql? 5  # Fixnums  
 => true 
2.2.3 :030 > 5.eql? 5.0  # Fixnum & Float  
 => false 
2.2.3 :032 > { a: 10 }.eql?({ a: 10 })  # Hash  
 => true 
2.2.3 :033 > { a: 10 }.eql?({ a: 10.0 })  
 => false

equal? — Reference comparison

True when two objects share the same memory reference

2.2.3 :017 > 'test'.equal? 'test'  
 => false 
# Each string is an independent object even if they share content
2.2.3 :018 > :test.equal? :test  
 => true 
# Symbols share reference if they have the same content
2.2.3 :019 > 1.equal? 1  
 => true 
2.2.3 :020 > [].equal? []  
 => false 
2.2.3 :021 > a = 'test'  
 => "test" 
2.2.3 :022 > b = a    # b is a reference to the same object as a  
 => "test" 
2.2.3 :023 > b.equal? a  
 => true 

The === method

obj === other → true or false

Case Equality – For class Object, effectively the same as calling #==, but typically overridden by descendants to provide meaningful semantics in case statements.

If you know Javascript you may think this is another method to test equality. Wrong!
For Object the === method and the == are actually the same, so it tests equality, but for every other class the convention is that this should be the case subsumption operator.

Basically, it is a boolean operator which asks "If a described a set, would b be a member of that set?". So more than equality it tests for inclusion.

2.2.3 :001 > 'test' === 'test'  
 => true 
2.2.3 :002 > String === 'test'  
 => true 
2.2.3 :003 > 'test' === String  
 => false 
2.2.3 :004 > Integer === 5  
 => true 
2.2.3 :005 > Float === 5  
 => false 
2.2.3 :006 > Float === 5.0  
 => true 
2.2.3 :007 > (1..10) === 5  
 => true