liveBook · Manning

Case equality operator

As explained in The Well-Grounded Rubyist, Fourth Edition

The Ruby case equality operator is the === method whose receiver tests whether its argument matches a when condition.

In Ruby, a `case` statement tries its `when` conditions in order. The match test is a call to `===`, often called the case equality or threequal operator. For `case answer; when "yes"`, Ruby tests `"yes" === answer`. The `when` object is the receiver; the `case` object is the argument. That order matters because reversing them need not give the same result. section 6.1.3

The operator is a method, so its meaning depends on the receiver. For a string tested against another string, it checks for matching contents. A class can define `===` to supply its own matching rule. Where it has not been overridden, `===` has the same behavior as `==`. section 6.1.3 section 11.7.4

Listing 6.2 Implementing case statement behavior for the Ticket class
class Ticket
  attr_accessor :venue, :date
  def initialize(venue, date)
    self.venue = venue
    self.date = date
  end
  def ===(other_ticket)              1
    self.venue == other_ticket.venue
  end
end
ticket1 = Ticket.new("Town Hall", "07/08/25")
ticket2 = Ticket.new("Conference Center", "07/08/25")
ticket3 = Ticket.new("Town Hall", "08/09/25")
puts "ticket1 is for an event at: #{ticket1.venue}."
case ticket1    
when ticket2                           2
  puts "Same location as ticket2!"
when ticket3                            3
  puts "Same location as ticket3!"
else
  puts "No match."
end

The `Ticket` example defines `===` to compare venues. In `case ticket1`, each ticket after `when` tests `ticket1`, so the ticket with the same venue matches even though its date differs. section 6.1.3

The receiver also determines what a match means elsewhere:

  • A regular expression tests whether a string matches its pattern. Thus `when /^y/i` can accept an answer beginning with `y`, regardless of case. Unlike `match`, which returns `nil` or a `MatchData` object, `===` gives a true-or-false test. section 11.7.4
  • `Enumerable#grep(expression)` selects elements for which `expression === element` is true. A class can select strings, a range can select an included number, and a regular expression can select matching strings. An optional block transforms the selected results. section 10.3.3 section 11.7.4
>> miscellany = [75, "hello", 10...20, "goodbye"]
=> [75, "hello", 10...20, "goodbye"]
>> miscellany.grep(String)              1
=> ["hello", "goodbye"]                 1
>> miscellany.grep(50..100)     2
=> [75]                         2

The mixed array makes receiver behavior visible: `grep(String)` returns its strings, while `grep(50..100)` returns `75`. section 10.3.3

How The Well-Grounded Rubyist, Fourth Edition covers it

How deep it goes
Explains `===` as receiver-directed method dispatch, then works through string, custom-class, regular-expression, and enumerable behavior.
Examples
Uses yes/no input, custom ticket matching, class and range filtering, and regular-expression matches.
What it assumes
Assumes familiarity with Ruby objects and method calls while explaining how `case`/`when` invokes `===`.
What you can do after
Apply it via Ruby `case`/`when` and `Enumerable#grep`, or define `===` to customize matching.
How it connects
Connects case equality to `case`/`when`, method overriding, regular expressions, `Enumerable#grep`, and `Enumerable#select`.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Well-Grounded Rubyist, Fourth Edition. The section links point to the parts of the book it draws on.