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
- Defining a class and creating objects with .new
- The initialize setup method
- Instance variables (@) and instance methods
- Class variables (@@) shared across instances
- Class methods with self.
- Customising output with to_s
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) # -> true2️⃣ 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? trueMini-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 hereCommon Errors (and the fix)
- Forgetting the @ — A plain name inside a method is a local variable that vanishes; use @name to persist data on the object.
- Calling initialize directly — Don't. Use Dog.new(...), which calls initialize for you.
- "wrong number of arguments" on .new — Pass exactly what initialize declares (or add defaults).
- Reading an @variable outside the object — Instance variables are private; expose them with methods (attr_accessor, in the next lesson, writes them for you).
- Mixing up self. and instance methods — self. methods are called on the class; plain methods on an instance.
Pro Tips
- 💡 One responsibility: a class should model one clear concept; if it grows unwieldy, split it.
- 💡 Define to_s early: friendly printing makes debugging far easier.
- 💡 Predicates end in ?: name boolean methods like long? and active?.
📋 Quick Reference — Classes & Objects
| Concept | Ruby Syntax |
|---|---|
| Define class | class Dog ... end |
| Constructor | def initialize(...) |
| Create object | Dog.new("Rex") |
| Instance var | @name |
| Class method | def self.count |
| Printable form | def to_s |
🎉 Lesson Complete!
- ✅ A class is a blueprint; objects are instances of it
- ✅ initialize runs on .new to set up an object
- ✅ Instance variables (@) hold per-object data
- ✅ Class variables (@@) and class methods (self.) belong to the class
- ✅ to_s controls how an object prints
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
- Previous: Iterators & Enumerable
- Next: Attributes (attr_accessor) — Generate getters and setters automatically for instance data
- Quick reference: Ruby cheat sheet › Classes & Modules
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.