This episode dissects Ruby's Object-Oriented Programming: class, initialize, instance methods and class methods, attr_accessor, inheritance, modules with include, extend, and prepend, the Comparable and Enumerable modules, and method visibility.

In episode 2 we mentioned that Ruby adheres to everything is object. Now it's time to use that paradigm to its full extent: modeling the real world into classes, objects, and modules. OOP is Ruby's way of organizing code — state is stored in objects, behavior is defined in classes, and modules provide shareable behavior.
This episode 6 dissects the four pillars of Ruby OOP: creating classes with initialize and accessors, inheritance and class methods, using modules as mixins and namespaces, and public, protected, and private visibility. All of these concepts will become the building blocks when you read Rails code full of classes and modules.
A class in Ruby begins with the class keyword and closes with end. The initialize method is the constructor called by new. To expose and write instance variables from outside, Ruby provides attr_accessor:
class Pengguna
attr_accessor :nama, :umur
def initialize(nama, umur)
@nama = nama
@umur = umur
end
def sapa
"Halo, saya #{@nama}"
end
end
pengguna = Pengguna.new("Arman", 30)
puts pengguna.sapa
puts pengguna.nama
pengguna.nama = "Ruby"
puts pengguna.namaPengguna.new("Arman", 30) creates a new object and calls initialize. attr_accessor :nama, :umur automatically creates the nama, nama=, umur, and umur= methods. If you only need read access, use attr_reader; if only write, attr_writer.
Methods defined inside a class are instance methods — callable only by objects of that class. The self keyword refers to the object currently executing the method. self.class returns the object's class, which is useful for dynamic inspection.
Inheritance uses the < symbol. A subclass inherits all the methods and accessors of its superclass, and can override methods with the same name. The super keyword calls the superclass version:
class Admin < Pengguna
def self.tipe
"admin"
end
def sapa
super + " (admin)"
end
end
puts Admin.tipe
puts Admin.new("Budi", 25).sapaAdmin < Pengguna makes Admin a subclass of Pengguna. super inside sapa calls Pengguna's sapa then appends the suffix. The Admin class automatically has nama, umur, and all of Pengguna's behavior.
Methods starting with self. (like self.tipe) are class methods — called directly from the class, not from an object. Common examples are factory methods like Pengguna.by_id(3). Behind the scenes, class methods live in the singleton class, consistent with episode 2's explanation of class objects.
A module is a collection of methods that cannot be instantiated, but can be inserted into classes. include makes a module's methods instance methods, extend makes them class methods, and prepend inserts methods higher in the lookup chain (before the class's own methods):
module BisaBerjalan
def berjalan
"berjalan dari #{self.class}"
end
end
class Kucing
include BisaBerjalan
end
puts Kucing.new.berjalaninclude BisaBerjalan gives every Kucing object the berjalan method. This is what's called a mixin — Ruby's way of sharing behavior without complicated multiple inheritance. prepend is used to alter behavior without changing the original class code, for example to add logging.
Modules also act as namespaces to group related classes, for example API::Klien and API::Server. Ruby ships with very useful built-in modules, especially Comparable and Enumerable. With include Comparable, a class only needs to define <=> and automatically gets <, >, <=, >=, and between?:
class Suhu
include Comparable
def initialize(derajat)
@derajat = derajat
end
def <=>(lain)
@derajat <=> lain.derajat
end
attr_reader :derajat
end
a = Suhu.new(30)
b = Suhu.new(40)
puts a < bBy only defining <=> (the spaceship we learned in episode 4), the Suhu class immediately supports comparisons. a < b produces true because 30 is smaller than 40. Likewise, include Enumerable gives any collection the map, select, and reduce methods from episode 5.
Ruby has three levels of method visibility. By default every method is public (callable from anywhere). private restricts calls to within the same object without an explicit receiver, and protected allows calls between objects of the same class:
class Rekening
def initialize(saldo)
@saldo = saldo
end
def info
"Saldo #{@saldo}"
end
private
def validasi
@saldo > 0
end
end
rekening = Rekening.new(500)
puts rekening.infoAll methods after the private keyword (that is, validasi) cannot be called from outside: rekening.validasi will trigger a NoMethodError. The info method stays public. This private rule is widely used to hide internal details and keep a class's interface clean.
Tip
In Rails, ActiveRecord models use this OOP pattern extensively: attr_accessor for virtual fields, modules for shared behavior, and private for internal helper methods. Understanding this episode will make Rails code much easier to read.
Episode 6 equips you with Ruby OOP: classes with initialize and attr_accessor, instance methods and class methods, inheritance with super, modules as mixins and namespaces, the built-in Comparable and Enumerable modules, and method visibility control.
Key takeaways:
attr_reader, attr_writer, and attr_accessor control access to instance variables.super calls the overridden superclass method.self. are class methods called from the class.include makes module methods instance methods; extend makes them class methods.include Comparable only needs the <=> method to get all comparison operators.private methods cannot be called from outside the object.In the next episode, episode 7, we will discuss error handling, debugging, and warnings — exceptions with begin, rescue, ensure, and raise, exception classes like StandardError and ArgumentError, custom exceptions, debugging with binding.irb and the debug gem, backtraces, and running code with the -w flag to see deprecation warnings. These are survival skills for production.