ð ruby-oop
Use when working with Ruby's object-oriented programming features including classes, modules, inheritance, mixins, and method visibility.
Overview
Master Ruby's elegant object-oriented programming features. Ruby is a pure object-oriented language where everything is an object.
Class Definition
Basic Class Structure
class Person
# Class variable (shared across all instances)
@@count = 0
# Constant
MAX_AGE = 150
# Class method
def self.count
@@count
end
# Constructor
def initialize(name, age)
@name = name # Instance variable
@age = age
@@count += 1
end
# Instance method
def introduce
"Hi, I'm #{@name} and I'm #{@age} years old"
end
# Attribute accessors (getter and setter)
attr_accessor :name
attr_reader :age # Read-only
attr_writer :email # Write-only
end
person = Person.new("Alice", 30)
puts person.introduce
person.name = "Alicia"
Method Visibility
class BankAccount
def initialize(balance)
@balance = balance
end
# Public methods (default)
def deposit(amount)
@balance += amount
log_transaction(:deposit, amount)
end
def balance
format_currency(@balance)
end
# Protected methods - callable by instances of same class/subclass
protected
def log_transaction(type, amount)
puts "[#{type}] #{amount}"
end
# Private methods - only callable within this instance
private
def format_currency(amount)
"$#{amount}"
end
end
Inheritance
Single Inheritance
class Animal
def initialize(name)
@name = name
end
def speak
"Some sound"
end
end
class Dog < Animal
def speak
"Woof! My name is #{@name}"
end
# Call parent method with super
def introduce
super # Calls parent's speak method
puts "I'm a dog"
end
end
dog = Dog.new("Buddy")
puts dog.speak
Method Override and Super
class Vehicle
def initialize(brand)
@brand = brand
end
def start_engine
puts "Engine starting..."
end
end
class Car < Vehicle
def initialize(brand, model)
super(brand) # Call parent constructor
@model = model
end
def start_engine
super # Call parent method
puts "#{@brand} #{@model} is ready to drive"
end
end
Modules and Mixins
Module as Namespace
module MyApp
module Utils
def self.format_date(date)
date.strftime("%Y-%m-%d")
end
end
end
MyApp::Utils.format_date(Time.now)
Module as Mixin
module Swimmable
def swim
"I'm swimming!"
end
end
module Flyable
def fly
"I'm flying!"
end
end
class Duck
include Swimmable # Instance methods
include Flyable
def quack
"Quack!"
end
end
duck = Duck.new
puts duck.swim
puts duck.fly
Extend vs Include
module Greetable
def greet
"Hello!"
end
end
class Person
include Greetable # Adds as instance method
end
class Company
extend Greetable # Adds as class method
end
Person.new.greet # Works
Company.greet # Works
Advanced OOP Patterns
Singleton Pattern
class Database
@instance = nil
private_class_method :new
def self.instance
@instance ||= new
end
def connect
puts "Connected to database"
end
end
db1 = Database.instance
db2 = Database.instance
db1.object_id == db2.object_id # true
Method Missing (Dynamic Methods)
class DynamicAttributes
def method_missing(method_name, *args)
attribute = method_name.to_s
if attribute.end_with?("=")
# Setter
instance_variable_set("@#{attribute.chop}", args.first)
else
# Getter
instance_variable_get("@#{attribute}")
end
end
def respond_to_missing?(method_name, include_private = false)
true
end
end
obj = DynamicAttributes.new
obj.name = "Ruby"
puts obj.name # "Ruby"
Class Instance Variables
class Product
@inventory = []
class << self
attr_accessor :inventory
def add(product)
@inventory << product
end
end
end
Product.add("Laptop")
Struct and OpenStruct
Struct (Immutable-ish)
Person = Struct.new(:name, :age) do
def introduce
"I'm #{name}, #{age} years old"
end
end
person = Person.new("Bob", 25)
puts person.name
person.age = 26
OpenStruct (Dynamic Attributes)
require 'ostruct'
person = OpenStruct.new
person.name = "Charlie"
person.age = 30
person.email = "charlie@example.com"
puts person.name
Composition Over Inheritance
class Engine
def start
"Engine started"
end
end
class Wheels
def rotate
"Wheels rotating"
end
end
class Car
def initialize
@engine = Engine.new
@wheels = Wheels.new
end
def start
@engine.start
end
def drive
@wheels.rotate
end
end
Comparable and Enumerable
Making Classes Comparable
class Person
include Comparable
attr_reader :age
def initialize(name, age)
@name = name
@age = age
end
def <=>(other)
age <=> other.age
end
end
people = [Person.new("Alice", 30), Person.new("Bob", 25)]
puts people.sort.map(&:age) # [25, 30]
Class Variables vs Instance Variables
class Counter
@@count = 0 # Class variable (shared)
@instances = [] # Class instance variable (not shared with subclasses)
def initialize
@@count += 1
end
def self.count
@@count
end
end
Best Practices
- Prefer composition over inheritance for complex relationships
- Use modules for mixins to share behavior across unrelated classes
- Keep classes small and focused (Single Responsibility Principle)
- Use attr_accessor/reader/writer instead of manual getters/setters
- Make use of private/protected to encapsulate implementation details
- Prefer instance variables over class variables to avoid unexpected sharing
- Use Struct for simple data objects instead of full classes
- Override to_s for debugging to provide meaningful string representations
Anti-Patterns
â Don't use class variables unnecessarily - they're shared across inheritance hierarchy â Don't create god objects - keep classes focused and small â Don't expose internal state - use methods instead of direct instance variable access â Don't overuse inheritance - prefer composition or modules â Don't ignore visibility modifiers - they exist for encapsulation
Related Skills
- ruby-metaprogramming - For dynamic class/method generation
- ruby-blocks-procs-lambdas - For functional programming patterns
- ruby-modules - For advanced module usage