Understanding Object-Oriented Programming in Ruby

Raghavendra S
4 min readDec 23, 2024

--

Ruby is a fully object-oriented programming (OOP) language, meaning almost everything in Ruby is an object. Ruby’s OOP paradigm makes it easy to write clean, reusable, and modular code. In this blog, we’ll explore the fundamentals of object-oriented programming in Ruby, including classes, objects, inheritance, polymorphism, encapsulation, and modules — all explained with detailed examples.

1. What is Object-Oriented Programming?

OOP is a programming paradigm that organizes code into objects. Objects are instances of classes, which encapsulate data (attributes) and behaviors (methods). Ruby’s OOP model provides key features:

  • Encapsulation: Hiding the internal state of objects and requiring all interactions to be performed through methods.
  • Inheritance: Allowing a class to derive from another class, inheriting its methods and attributes.
  • Polymorphism: Using a common interface for different data types or classes.

2. Classes and Objects

A class is a blueprint for creating objects. Objects are specific instances of a class. In Ruby, creating and using objects is intuitive.

Code Example:

# Define a class
class Person
attr_accessor :name, :age
  def initialize(name, age)
@name = name
@age = age
end
def greet
"Hello, my name is #{@name} and I am #{@age} years old."
end
def birthday
@age += 1
"Happy Birthday! #{@name} is now #{@age} years old."
end
end
# Create objects
person1 = Person.new("Alice", 30)
person2 = Person.new("Bob", 25)
# Call methods on objects
puts person1.greet # Output: Hello, my name is Alice and I am 30 years old.
puts person2.birthday # Output: Happy Birthday! Bob is now 26 years old.

3. Inheritance

Inheritance allows a class (child) to inherit attributes and methods from another class (parent). Ruby uses the < symbol to denote inheritance.

Code Example:

# Parent class
class Animal
attr_reader :name
  def initialize(name)
@name = name
end
def speak
"#{@name} makes a sound."
end
end
# Child class
class Dog < Animal
def speak
"#{@name} barks."
end
end
# Child class
class Cat < Animal
def speak
"#{@name} meows."
end
end
# Create objects
dog = Dog.new("Rex")
cat = Cat.new("Whiskers")
puts dog.speak # Output: Rex barks.
puts cat.speak # Output: Whiskers meows.

4. Polymorphism

Polymorphism allows objects of different classes to respond to the same method call in their unique way. This is achieved through method overriding.

Code Example:

class Employee
def initialize(name, salary)
@name = name
@salary = salary
end
  def details
raise "This method should be overridden by subclasses."
end
end
class Manager < Employee
def details
"#{@name} is a Manager earning $#{@salary} per year."
end
end
class Developer < Employee
def details
"#{@name} is a Developer earning $#{@salary} per year."
end
end
# Use polymorphism
employees = [Manager.new("Alice", 100000), Developer.new("Bob", 80000)]
employees.each do |employee|
puts employee.details
end
# Output:
# Alice is a Manager earning $100000 per year.
# Bob is a Developer earning $80000 per year.

5. Encapsulation

Encapsulation restricts access to the internal state of an object and only allows modification through defined methods. Ruby achieves this by using private or protected methods.

Code Example:

class BankAccount
def initialize(balance)
@balance = balance
end
  # Public method to display balance
def show_balance
"Your balance is $#{@balance}."
end
# Public method to deposit money
def deposit(amount)
if valid_transaction?(amount)
@balance += amount
"Deposited $#{amount}. New balance is $#{@balance}."
else
"Invalid transaction."
end
end
private # Private method to validate transactions
def valid_transaction?(amount)
amount > 0
end
end
account = BankAccount.new(1000)
puts account.show_balance # Output: Your balance is $1000.
puts account.deposit(500) # Output: Deposited $500. New balance is $1500.
puts account.deposit(-100) # Output: Invalid transaction.

6. Modules and Mixins

Modules group reusable methods and can be mixed into classes using include or extend. They provide a way to share behaviors across multiple classes.

Code Example:

module Flyable
def fly
"#{self.class} is flying!"
end
end
class Bird
include Flyable
end
class Plane
include Flyable
end
bird = Bird.new
plane = Plane.new
puts bird.fly # Output: Bird is flying!
puts plane.fly # Output: Plane is flying!

7. Advanced Example: Real-World Application

Let’s build a library system to demonstrate all OOP principles together.

Code Example:

module Searchable
def find_by_title(title)
@items.find { |item| item.title == title }
end
end
class Library
include Searchable
def initialize
@items = []
end
def add_item(item)
@items << item
end
def list_items
@items.map(&:details).join("\n")
end
end
class Book
attr_reader :title
def initialize(title, author)
@title = title
@creator = author
end
def details
"Book: #{@title} by #{@creator}"
end
end
class DVD
attr_reader :title
def initialize(title, director)
@title = title
@creator = director
end
def details
"DVD: #{@title} directed by #{@creator}"
end
end
library = Library.new
book = Book.new("1984", "George Orwell")
dvd = DVD.new("Inception", "Christopher Nolan")
library.add_item(book)
library.add_item(dvd)
puts library.list_items
# Output:
# Book: 1984 by George Orwell
# DVD: Inception directed by Christopher Nolan
item = library.find_by_title("1984")
puts item.details # Output: Book: 1984 by George Orwell

Conclusion

Ruby’s object-oriented programming features provide the tools to create modular, reusable, and maintainable code. By mastering classes, objects, inheritance, polymorphism, encapsulation, and modules, you can leverage Ruby’s full potential to build scalable applications. Practice these concepts and experiment with your own projects to enhance your understanding!

--

--

Raghavendra S
Raghavendra S

Written by Raghavendra S

Artificial enthusiast. Rubyist.

No responses yet