Classes & Modules
Learn Ruby class syntax, initialize, attr_accessor, inheritance, and how modules provide mixins for sharing behavior across classes.
Introduction
Ruby's classes work much like classes in other object-oriented languages, but modules add something distinctive: a clean way to share behavior across unrelated classes without forcing them into a single-parent inheritance chain.
- How to define a class with initialize and instance methods.
- How attr_accessor, attr_reader, and attr_writer generate getters and setters for you.
- How single inheritance works with <, and how to override a parent method.
- What a module is, and how include gives a class its behavior as a "mixin."
Defining a Class
initialize is Ruby's constructor — automatically called when you write ClassName.new(...). Inside any instance method, self refers to the current object.
class Dog def initialize(name) @name = name end
def bark "#{@name} says Woof!" endend
rex = Dog.new("Rex")puts rex.barkClick Run to see what this code prints.
attr_accessor and Friends
Writing a getter and setter method by hand for every instance variable is repetitive, so Ruby provides three shortcuts: attr_reader (getter only), attr_writer (setter only), and attr_accessor (both).
class Dog attr_accessor :name, :age
def initialize(name, age) @name = name @age = age endend
rex = Dog.new("Rex", 3)puts rex.name # calls the generated getterrex.age = 4 # calls the generated setterputs rex.ageClick Run to see what this code prints.
Inheritance
The < operator declares a class's parent. A subclass inherits all of its parent's methods, and can override any of them by redefining a method with the same name — calling super invokes the parent's version.
class Animal def initialize(name) @name = name end
def speak "#{@name} makes a sound." endend
class Cat < Animal def speak super + " Specifically, a meow." endend
whiskers = Cat.new("Whiskers")puts whiskers.speakClick Run to see what this code prints.
Class Variables and Class Methods
A @@ class variable is shared across every instance of a class. A method defined with self. instead of a plain name becomes a class method, callable directly on the class itself without creating an instance.
class Dog @@total_dogs = 0
def initialize(name) @name = name @@total_dogs += 1 end
def self.total_dogs @@total_dogs endend
Dog.new("Rex")Dog.new("Buddy")puts Dog.total_dogsClick Run to see what this code prints.
Modules: Mixins
Use case: a module groups related methods together, similar to a class, but is never instantiated directly. include-ing a module inside a class adds all of its methods to that class — a "mixin" — letting unrelated classes share behavior without forcing a common parent class.
module Greetable def greet "Hello, I am #{name}." endend
class Person include Greetable attr_accessor :name def initialize(name) @name = name endend
class Robot include Greetable attr_accessor :name def initialize(name) @name = name endend
puts Person.new("Anaya").greetputs Robot.new("Unit-7").greetClick Run to see what this code prints.
Person and Robot have nothing meaningfully in common as a shared parent class — forcing both to inherit from some artificial "Greetable" base class would be awkward. A module lets both share the exact same greet behavior without pretending they're the same kind of thing.
Common Mistakes
- Writing manual getter/setter methods by hand when attr_accessor (or attr_reader/attr_writer) would do it in one line.
- Overusing class variables (@@) for state that really belongs on individual instances (@).
- Reaching for deep inheritance chains when a module mixin would express shared behavior more cleanly.
Best Practices
- Use attr_accessor/attr_reader/attr_writer instead of hand-written getters and setters unless you need custom logic in one.
- Reach for a module mixin when unrelated classes need to share behavior, rather than forcing an artificial inheritance relationship.
- Keep inheritance hierarchies shallow — Ruby, like most single-inheritance languages, gets harder to reason about with deep chains.
Frequently Asked Questions
Yes — a class can include as many modules as it needs, which is exactly how Ruby achieves many of the practical benefits of multiple inheritance without its complexity.
A module can't be instantiated with .new and has no inheritance chain of its own — it exists purely to group related methods (or constants) for use via include, or as a namespace.
Yes, conceptually — self refers to "the current object" inside an instance method, or "the class itself" inside a method defined with self., very similar to this in Java/JavaScript or self in Python.
Key Takeaways
- initialize is Ruby's constructor, automatically called by ClassName.new(...).
- attr_accessor, attr_reader, and attr_writer generate common getter/setter methods for you.
- The < operator declares inheritance; super calls the parent class's version of an overridden method.
- A module groups reusable methods; include mixes those methods into a class without full inheritance.
Summary
Classes and modules together give Ruby a flexible, expressive object-oriented toolkit — inheritance for "is-a" relationships, and mixins for shared behavior across otherwise-unrelated classes. Next, you'll cover Ruby's two core collection types: Arrays and Hashes.