Ruby Object-Oriented Programming
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