Classes & Objects

Reviewed & published by Brayan K

Ruby is a dynamic, beginner-friendly programming language built around objects, and a class is the blueprint you use to model real-world things — bundling data and the behaviour that goes with it.

Part of the free Ruby course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

By the end of this lesson you'll define classes, create objects, store data in instance variables, and write instance and class methods.

What You'll Learn in This Lesson

1️⃣ Defining a Class and Creating Objects

Use class Name ... end to define a blueprint. The special initialize method runs when you call .new, and stores incoming data in instance variables (the @ ones). Instance methods then act on that data.

# A class is a blueprint. Objects (instances) are built from it.
class Dog
  # initialize runs automatically when you call Dog.new
  def initialize(name, breed)
    @name = name      # @name is an INSTANCE variable — unique per object
    @breed = breed
  end

  # An instance method: behaviour every Dog has.
  def bark
    "#{@name} says Woof!"
  end

  def describe
    "#{@name} is a #{@breed}."
  end
end

# Create instances with .new — arguments go to initialize.
rex = Dog.new("Rex", "Labrador")
fido = Dog.new("Fido", "Poodle")

puts rex.bark         # -> Rex says Woof!
puts fido.describe    # -> Fido is a Poodle.
puts rex.class        # -> Dog
puts rex.is_a?(Dog)   # -> true

2️⃣ Class Variables, Class Methods, and to_s

A class variable (@@) is shared across all instances — perfect for a running total. A class method (defined with self.) is called on the class itself. And defining to_s controls how your object appears when you puts it.

class BankAccount
  # A CLASS variable (@@) is shared by ALL instances.
  @@total_accounts = 0

  def initialize(owner, balance = 0)
    @owner = owner
    @balance = balance
    @@total_accounts += 1
  end

  def deposit(amount)
    @balance += amount
    "#{@owner} now has $#{@balance}"
  end

  # A CLASS method (self.) is called on the class, not an instance.
  def self.total_accounts
    @@total_accounts
  end

  # to_s controls how the object prints with puts.
  def to_s
    "#{@owner}: $#{@balance}"
  end
end

a = BankAccount.new("Ada", 100)
b = BankAccount.new("Bo")
puts a.deposit(50)                     # -> Ada now has $150
puts BankAccount.total_accounts        # -> 2  (class method)
puts a                                  # -> Ada: $150  (uses to_s)

Your turn. Flesh out a Book class with a summary and a long? predicate. Complete the TODOs, then run it.

# 🎯 YOUR TURN — replace each TODO, then run with: ruby book.rb

class Book
  def initialize(title, author, pages)
    @title = title       # 👉 store each argument in an @ variable
    @author = author
    @pages = pages
  end

  # 1) Return a summary line
  def summary
    "#{@title} by #{@author} (#{@pages} pages)"   # 👉 TODO: keep this format
  end

  # 2) Return true if the book is "long" (more than 300 pages)
  def long?
    @pages > 300         # 👉 TODO: complete the comparison
  end
end

novel = Book.new("Dune", "Herbert", 412)
puts novel.summary
puts "Long read? #{novel.long?}"

# ✅ Expected output:
#    Dune by Herbert (412 pages)
#    Long read? true

Mini-Challenge: A Counter Class

Build a small Counter with increment and reset methods that manage an instance variable. Run with ruby counter.rb.

# 🎯 MINI-CHALLENGE: a Counter class.
# Save as counter.rb and run with: ruby counter.rb
#
# 1. Define a class Counter whose initialize sets @count = 0.
# 2. Add an increment method that adds 1 to @count and returns it.
# 3. Add a reset method that sets @count back to 0.
# 4. Create a counter, increment it three times, print the count,
#    reset, and print again.
#
# ✅ Example output:
#    Count: 3
#    After reset: 0

# your code here

Common Errors (and the fix)

Pro Tips

📋 Quick Reference — Classes & Objects

ConceptRuby Syntax
Define classclass Dog ... end
Constructordef initialize(...)
Create objectDog.new("Rex")
Instance var@name
Class methoddef self.count
Printable formdef to_s

🎉 Lesson Complete!

Practice quiz

Which method runs automatically when you call Dog.new(...)?

  • new
  • setup
  • initialize
  • create

Answer: initialize. Ruby calls initialize automatically when you create an object with .new.

What does a single @ prefix mark, as in @name?

  • An instance variable, unique to one object
  • A class variable shared by all instances
  • A global variable
  • A constant

Answer: An instance variable, unique to one object. A single @ marks an instance variable that belongs to one specific object.

What does @@ mark, as in @@total_accounts?

  • An instance variable
  • A local variable
  • A frozen value
  • A class variable shared by ALL instances of the class

Answer: A class variable shared by ALL instances of the class. @@ marks a class variable, shared across every instance of the class.

How is a class method defined?

  • def @method_name
  • def self.method_name
  • class def method_name
  • static def method_name

Answer: def self.method_name. A method defined with self. (def self.total) is a class method, called on the class itself.

For rex = Dog.new("Rex", "Lab"), what does rex.class return?

  • Dog
  • "Rex"
  • Object
  • Class

Answer: Dog. rex.class returns the class the object was made from: Dog.

Defining to_s on a class controls:

  • How the object is sorted
  • Whether the object is frozen
  • How the object prints with puts and string interpolation
  • The object's class name

Answer: How the object prints with puts and string interpolation. to_s defines the object's string form, which puts and interpolation use.

If you write a plain name = value (no @) inside an instance method, what happens?

  • It sets the instance variable @name
  • It creates a local variable that vanishes when the method ends
  • It raises a NoMethodError
  • It defines a class variable

Answer: It creates a local variable that vanishes when the method ends. Without @, name is just a local variable that disappears; use @name to persist data on the object.

How do you call a class method named total_accounts on BankAccount?

  • BankAccount.new.total_accounts
  • total_accounts(BankAccount)
  • @@total_accounts
  • BankAccount.total_accounts

Answer: BankAccount.total_accounts. Class methods are called on the class itself: BankAccount.total_accounts.

By convention, a boolean (predicate) method like 'is it long?' should be named:

  • is_long
  • long?
  • long!
  • get_long

Answer: long?. Ruby names predicate methods with a trailing ?, like long? or active?.

Why can't you read an object's @name directly from outside the object?

  • @name does not exist until printed
  • Ruby forbids the @ symbol outside classes
  • Instance variables are private; you expose them via methods (e.g. attr_accessor)
  • You can — there is no restriction

Answer: Instance variables are private; you expose them via methods (e.g. attr_accessor). Instance variables are private to the object; getters/setters (often attr_accessor) expose them.

Continue this course

Frequently asked questions

What's the difference between a class and an object?

A class is a blueprint that describes what data and behaviour something has; an object (also called an instance) is a concrete thing built from that blueprint. Dog is the class — the idea of a dog — while rex = Dog.new("Rex", "Lab") is one specific dog object. From a single class you can create many independent objects, each with its own data. The class defines the methods; every object made from it can use them.

What does the initialize method do?

initialize is a special setup method that Ruby calls automatically whenever you create an object with .new. Any arguments you pass to .new are forwarded to initialize, where you typically store them in instance variables (the @-prefixed ones). So Dog.new("Rex", "Lab") runs initialize("Rex", "Lab"), which sets @name and @breed. You never call initialize directly — .new does it for you.

What are the @, @@, and self. prefixes?

A single @ marks an instance variable, which belongs to one specific object — each Dog has its own @name. A double @@ marks a class variable, shared by every instance of the class, useful for things like a running total. A method defined with self. (like def self.total) is a class method, called on the class itself (BankAccount.total) rather than on an instance. Most of your code uses plain instance variables and instance methods; the others appear when data or behaviour belongs to the class as a whole.

Why override to_s, and how is it used?

to_s defines how your object turns into a string, which is what puts and string interpolation use. Without it, puts some_object prints something unhelpful like #<Dog:0x00007f...>. By defining def to_s; "..."; end, you control that output — for example showing an account's owner and balance. There's a related method, inspect, used for debugging output (and by p), which conventionally shows a more detailed, developer-focused representation.