Ruby Classes and Objects: How to Define and Use Them
Classes and objects are the foundation of object-oriented programming in Ruby. If you’ve been learning Ruby, you’ve already been using objects—strings, arrays, and hashes are all objects. Now it’s time to create your own.
You will learn what classes are, how to define them, and how to use objects to organize your code.
intro context
Classes are Ruby’s way of bundling related data and behavior into one object. That is useful because a program becomes easier to understand when each object has a clear job. Instead of asking a dozen unrelated variables to describe one concept, you can put the concept into a class and let the object carry its own state.
The big shift is mental rather than mechanical. Once you see that objects are just structured values with methods attached, object-oriented Ruby starts to feel practical instead of abstract. The class is the blueprint, and every object you create from it is a real instance with its own data.
tl;dr
Use classes when you want to model a real thing or a closely related set of behaviors. initialize sets up new objects, instance variables store per-object state, and accessor methods decide how other code should read or change that state.
intro context
Object-oriented Ruby becomes much easier once you stop thinking of classes as a special advanced feature. A class is just a way to bundle data and behavior so you can work with named things instead of loose variables. That structure helps as soon as your program needs more than one piece of state.
The real benefit shows up when your code starts to model things that already exist in your problem domain. A Person, Order, or Invoice object is easier to reason about than a pile of unrelated hashes because the class gives the object a clear shape and a clear place for its behavior.
tl;dr
Use classes when you want to group related data and methods into reusable objects. Use initialize to set up state, instance variables to store per-object data, and accessor methods when you need to expose or update that data safely.
What are classes and objects?
A class is a blueprint for creating objects. It defines what attributes and behaviors objects of that type will have. An object is a specific instance of a class—it’s created from the blueprint and has its own unique data.
Think of it like a cookie cutter and cookies:
- The class is the cookie cutter (the blueprint)
- Each cookie is an object (an instance)
In Ruby, everything is an object. Even numbers and nil are objects with their own classes (Integer and NilClass).
Defining a Class
To create a class in Ruby, use the class keyword followed by the class name in CamelCase:
class Person
# This is where we'll define the class behavior
end
Class names must start with a capital letter. By convention, multi-word class names use CamelCase like BankAccount or ShoppingCart.
Creating Objects
Once you have a class, you can create objects (instances) using the .new method:
class Person
end
person1 = Person.new
person2 = Person.new
puts person1.class # => Person
puts person2.class # => Person
Each call to Person.new creates a new, separate object.
The initialize Method
The initialize method is a special method that runs automatically when you call .new. It’s Ruby’**s equivalent of a constructor:
class Person
def initialize
puts "A new person is born!"
end
end
person = Person.new
# Output: A new person is born!
You’ll typically use initialize to set up the object’s initial state with instance variables.
Instance Variables
Instance variables store data that belongs to each individual object. They start with @ and are accessible throughout the class:
class Person
def initialize(name, age)
@name = name
@age = age
end
end
person1 = Person.new("Alice", 30)
person2 = Person.new("Bob", 25)
# Each object has its own @name and @age
Instance variables are private by default; you can’t access them directly from outside the object.
That privacy is helpful because it keeps callers from poking at internal state without going through the methods you provide. When the object needs to change later, you can update the implementation inside the class without changing every caller that uses it.
Instance Methods
Instance methods are behaviors that belong to objects. They’re defined inside the class and can access instance variables:
class Person
def initialize(name, age)
@name = name
@age = age
end
def greet
"Hello, my name is #{@name}!"
end
def celebrate_birthday
@age += 1
"Happy birthday! I am now #{@age} years old."
end
end
person = Person.new("Alice", 30)
puts person.greet # => Hello, my name is Alice!
puts person.celebrate_birthday # => Happy birthday! I am now 31 years old.
Instance methods define the behaviors that belong to each object. They have direct access to instance variables through the @ prefix, which means they can read and modify the object’s internal state without needing getters and setters. This is what makes objects self-contained: the data and the operations on that data live together in one place.
Accessor Methods
To read or modify instance variables from outside the object, you need accessor methods. Ruby provides shorthand macros for this:
class Person
def initialize(name, age)
@name = name
@age = age
end
# Shorthand for reading the variable
attr_reader :name
# Shorthand for modifying the variable
attr_writer :name
# Shorthand for both reading and writing
attr_accessor :age
end
person = Person.new("Alice", 30)
# Using attr_reader
puts person.name # => Alice
# Using attr_writer
person.name = "Alicia"
puts person.name # => Alicia
# Using attr_accessor
puts person.age # => 30
person.age = 31
puts person.age # => 31
For most cases, use attr_accessor to create both getter and setter methods. Use attr_reader or attr_writer when you only need one.
The to_s Method
Ruby calls the to_s method automatically when you convert an object to a string (like with puts). Override it to make your objects display useful information:
class Person
attr_accessor :name, :age
def initialize(name, age)
@name = name
@age = age
end
def to_s
"Person: #{@name}, #{@age} years old"
end
end
person = Person.new("Alice", 30)
puts person
# => Person: Alice, 30 years old
The to_s method is called automatically whenever Ruby needs a string representation of your object — for example, in string interpolation or when passed to puts. Overriding it gives you control over how your objects appear in logs, error messages, and debugging output without writing explicit conversion code every time.
Class variables and class methods
Sometimes you need data that belongs to the class itself, not individual objects. Use class variables (@@) and class methods:
class Person
# Class variable - shared by all instances
@@population = 0
def initialize(name)
@name = name
@@population += 1 # Increment when new person created
end
# Class method - called on the class, not instances
def self.population
@@population
end
def introduce
"Hi, I'm #{@name}"
end
end
person1 = Person.new("Alice")
person2 = Person.new("Bob")
puts Person.population # => 2
puts person1.introduce # => Hi, I'm Alice
Class methods are defined with self.method_name and are useful for factory methods or operations that don’t need instance data.
summary
Classes let Ruby code move from simple values to custom objects with behavior. Once you understand initialize, instance variables, accessor methods, and class methods, you can organize Ruby programs around meaningful objects instead of around scattered pieces of state.
That structure pays off quickly. When the code grows, each class gives you a place to put the rules for one concept, and that makes the rest of the program easier to scan. If a method becomes hard to explain in one sentence, it is often a sign that its class needs to be broken into smaller responsibilities.
That is usually the point where classes stop feeling theoretical and start feeling practical.
When to use classes
Use classes when you need to:
- Model real-world entities with properties and behaviors
- Group related data and functionality together
- Create multiple instances with shared behavior but different data
- Organize code into reusable components
When not to use classes
Avoid classes when:
- You only need to group a few unrelated methods
- A simple module would suffice
- Functional programming patterns fit better (like with
Enumerable)
Conclusion
Classes and objects are essential tools in Ruby. They let you create custom data types with their own behavior, organize code logically, and model real-world concepts in your programs.
Key takeaways:
- A class is a blueprint; an object is an instance of that class
- Use
initializeto set up new objects - Instance variables (
@) store per-object data attr_accessor,attr_reader, andattr_writercreate getter/setter methods- Class variables and methods belong to the class itself
Next steps
Now that you understand classes and objects, continue with:
- Modules and Mixins ; Reuse code across classes
- Inheritance and Method Lookup ; Build on existing classes