RbRuby · Lesson 7 of 11

Classes & OOP

Ruby's OOP is clean and expressive. Everything is an object, inheritance is single (by class), and modules fill in for multiple inheritance. The `attr_accessor` macro writes getters and setters so you don't have to.

Ruby
class Animal
  # attr_accessor generates getter AND setter methods
  # attr_reader = getter only, attr_writer = setter only
  attr_accessor :name, :sound
  attr_reader :species

  # Class variable (shared across all instances)
  @@count = 0

  def initialize(name, sound, species)
    @name    = name
    @sound   = sound
    @species = species
    @@count += 1
  end

  def speak
    "#{@name} says #{@sound}!"
  end

  def to_s
    "#{@species}(#{@name})"
  end

  def self.count   # class method
    @@count
  end
end

dog = Animal.new("Rex", "woof", "Dog")
cat = Animal.new("Whiskers", "meow", "Cat")

puts dog.speak          # Rex says woof!
puts cat.name           # Whiskers
cat.name = "Luna"       # setter
puts Animal.count       # 2
puts dog                # Dog(Rex)  — calls to_s
Ruby
# Inheritance
class Dog < Animal
  attr_reader :breed, :tricks

  def initialize(name, breed)
    super(name, "woof", "Dog")   # call parent initialize
    @breed  = breed
    @tricks = []
  end

  def learn(trick)
    @tricks << trick
    self   # return self to enable chaining
  end

  def speak
    "#{name} the #{breed} barks!"
  end

  def show_tricks
    @tricks.empty? ? "No tricks yet" : @tricks.join(", ")
  end
end

buddy = Dog.new("Buddy", "Labrador")
buddy.learn("sit").learn("shake").learn("roll over")   # chaining

puts buddy.speak         # Buddy the Labrador barks!
puts buddy.show_tricks   # sit, shake, roll over
puts buddy.is_a?(Dog)    # true
puts buddy.is_a?(Animal) # true — inheritance check
puts buddy.class         # Dog
Ruby
# Protected and private methods
class BankAccount
  def initialize(balance)
    @balance = balance
  end

  def deposit(amount)
    validate_amount!(amount)
    @balance += amount
  end

  def >(other)
    balance > other.balance
  end

  def to_s
    "Account(#{"$%.2f" % @balance})"
  end

  protected

  def balance   # accessible to other BankAccount instances
    @balance
  end

  private

  def validate_amount!(amount)   # ! = raises exception on bad input
    raise ArgumentError, "Amount must be positive" unless amount > 0
  end
end

acc1 = BankAccount.new(1000)
acc2 = BankAccount.new(500)
acc1.deposit(250)
puts acc1 > acc2   # true
✦ Tip
Use `attr_accessor` for simple data attributes — it generates clean getter/setter methods. Add custom getter/setter methods only when you need validation or computation. Ruby convention: `def name` for getter, `def name=(val)` for setter.