Ruby
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Methods and Blocks
-
Section 4: Object-Oriented Ruby
-
Section 5: Metaprogramming
-
Section 6: Working with Data and Files
-
Section 7: Ruby Frameworks Overview
-
Section 8: Ecosystem and Testing
-
Section 9: Practical Projects
-
Section 10: Interview Practice
-
Section 11: Data Structures and Algorithms in Ruby
-
Section 12: More Practice Exercises
-
Section 13: Enumerable and Functional Style
-
Section 14: More OOP Practice
-
Section 15: More Testing
-
Section 16: Enumerable and Comparable Modules In Depth
-
Section 17: Ruby Standard Library: Core Utilities
-
Section 18: Ruby Standard Library: Data and Security
-
Section 19: Ruby Standard Library: CLI and Text
-
Section 20: Ruby Networking
-
Section 21: Ruby on Rails Deep Dive
-
Section 22: Ruby Metaprogramming Deep Dive
-
Section 23: Ruby Design Patterns
-
Section 24: Ruby Concurrency
-
Section 25: Ruby Testing Deep Dive
-
Section 26: Ruby Gems and Packaging
-
Section 27: Ruby Performance
-
Section 28: More Practice Exercises
-
Section 29: More Interview Practice
-
Section 30: Rails API Development
-
Section 31: Rails Authentication and Authorization
-
Section 32: Rails Testing Deep Dive
-
Section 33: Rails Performance
-
Section 34: Rails Deployment
-
Section 35: Sinatra and Lightweight Ruby Web Apps
-
Section 36: More Ruby Language Deep Dive
-
Section 37: Ruby 3.x Modern Features
-
Section 38: More Data Structures in Ruby
-
Section 39: More Practical Projects
-
Section 40: Ruby Ecosystem Tools
-
Section 41: More Practice and Review
-
Section 42: Final Practice and Mastery
-
Section 43: Ruby Interview Deep Dive
-
Section 44: Ruby Background Processing Deep Dive
-
Section 45: Ruby GraphQL
-
Section 46: Ruby Object Model Deep Dive
-
Section 47: Ruby Hanami Framework Overview
-
Section 48: Ruby gRPC and Protocol Buffers
-
Section 49: Ruby Data Processing
-
Section 50: Ruby Search Integration
-
Section 51: Ruby File Upload and Media
-
Section 52: Ruby Email and Notifications
-
Section 53: Ruby Admin Panels
-
Section 54: Ruby Feature Flags and Experimentation
-
Section 55: Ruby Monitoring and Observability
-
Section 56: Ruby Docker and Deployment Deep Dive
-
Section 57: Ruby Security Deep Dive
-
Section 58: More Advanced Metaprogramming
-
Section 59: More Final Projects
61: The Comparable Module and <=>
You've probably run into a situation where you have a custom object—say, a Version number for a piece of software—and you need to know if one version is newer than another. When you start building this, your first instinct might be to just override the operators you actually intend to use in your code.
Writing five methods for one job
Imagine we're building a system to track software releases. We have a Version class that holds a major and minor version number. To make them comparable, you might start by defining the "greater than" and "less than" operators manually. It looks something like this:
class Version
attr_reader :major, :minor
def initialize(major, minor)
@major = major
@minor = minor
end
def >(other)
return true if @major > other.major
return true if @major == other.major && @minor > other.minor
false
end
def <(other)
return true if @major < other.major
return true if @major == other.major && @minor < other.minor
false
end
end
This works for a bit, but it's a maintenance nightmare. What happens when you realize you also need >=, <=, and ==? You'll find yourself copy-pasting nearly identical logic five times over. If you change how a version is calculated—say, you add a 'patch' number—you now have five different methods to update. It's tedious, and it's incredibly easy to make a typo in one of those methods that leads to a bug that only appears when checking a specific edge case.
Letting the spaceship do the heavy lifting
Ruby has a much more elegant way to handle this using the <=> operator, which we call the "spaceship operator." I call it that because it looks like a little UFO. Instead of returning a boolean (true or false), the spaceship operator returns an integer: -1 if the left side is smaller, 0 if they're equal, and 1 if the left side is larger.
The real magic happens when you pair this operator with the Comparable module. When you include Comparable in your class, Ruby looks at your <=> method and automatically generates all the other comparison operators for you. You write one method, and you get five or six for free.
class Version
include Comparable
attr_reader :major, :minor
def initialize(major, minor)
@major = major
@minor = minor
end
def <=>(other)
# Compare major versions first
comparison = @major <=> other.major
# If major versions are the same, use the minor version as the tie-breaker
return comparison == 0 ? @minor <=> other.minor : comparison
end
end
Notice how much cleaner that is. I'm using the spaceship operator inside the method to compare the integers themselves, because integers already know how to use <=>. I'm essentially delegating the hard work to Ruby's built-in types.
Why this makes sorting just work
Beyond just making < and > work, there's a huge architectural win here: compatibility with the rest of the language. Many of Ruby's core methods, like Array#sort or Enumerable#minmax, rely specifically on the <=> operator to function.
If you use the naive approach of only defining > and <, calling versions.sort will throw a NoMethodError because sort doesn't care about those methods—it only cares about the spaceship. By implementing Comparable, your custom objects now behave exactly like native Ruby numbers or strings. You can throw them into a list, call sort, and it just works without you having to pass a block to explain how to compare them.
📋 Practical Task
Implementing a Product Ranking System
You are building a catalog for an e-commerce site. You need to create a Product class that can be compared based on its "Value Score." The Value Score is calculated by dividing the rating (1-5) by the price. A product is considered "greater" (better value) if it has a higher Value Score.
Your task:
- Create a
Productclass withname,price, andratingattributes. - Include the
Comparablemodule. - Implement the
<=>operator to compare products based on their calculated value score (rating / price.to_f). - Verify your implementation by creating an array of three different products and using the
.sortmethod to order them from worst value to best value.
There are no comments for now.