Classes & Objects
Ruby classes are open and dynamic. Define one with class Foo; add methods anytime; mix in modules. initialize is the constructor; attr_accessor / attr_reader generate accessors.
attr, modules, inheritance, comparable
EXAMPLE
# 1) Basic class
class User
attr_accessor :name, :email # generates getters AND setters
attr_reader :id # getter only
def initialize(id, name, email)
@id = id
@name = name
@email = email
end
def greet = "Hi, I'm \#{@name}" # one-line method (3.0+)
def to_s
"\#{@name} <\#{@email}>"
end
end
u = User.new(1, 'Ada', 'ada@example.com')
puts u.greet
puts u # uses to_s
# 2) Inheritance
class Admin < User
def initialize(id, name, email, perms:)
super(id, name, email)
@perms = perms
end
def can?(action) = @perms.include?(action)
end
a = Admin.new(2, 'Cy', 'cy@example.com', perms: [:delete])
puts a.can?(:delete)
# 3) Module mixin — add behaviour without inheritance
module Auditable
def audit_log
"AUDIT: \#{self.class.name}#\#{__method__}"
end
end
class Order
include Auditable
end
puts Order.new.audit_log
# 4) class methods
class User
@@count = 0 # class variable (avoid; use class instance var)
def initialize(...) = @@count += 1
def self.count
@@count
end
end
# 5) Private + protected
class Account
def initialize(balance) = @balance = balance
def transfer(other, amount)
debit(amount)
other.send(:credit, amount) # protected — same class
end
protected
def credit(n) = @balance += n
def debit(n) = @balance -= n
end
# 6) Comparable mixin — define <=>, get >, <, ==, between?
class Version
include Comparable
attr_reader :parts
def initialize(s)
@parts = s.split('.').map(&:to_i)
end
def <=>(other) = parts <=> other.parts
end
versions = ['1.2.3', '1.10.0', '0.9'].map { Version.new(_1) }.sort
puts versions.map { _1.parts.join('.') } # 0.9, 1.2.3, 1.10.0
# 7) Struct — quick class for a value object
Point = Struct.new(:x, :y) do
def distance_to(other) = Math.hypot(x - other.x, y - other.y)
end
p = Point.new(0, 0)
q = Point.new(3, 4)
puts p.distance_to(q) # 5.0
# 8) Data — immutable value object (Ruby 3.2+)
Money = Data.define(:amount, :currency)
m = Money.new(amount: 9.99, currency: 'AUD')
m.amount # 9.99
# m.amount = 1 — NoMethodError; immutable
# 9) ObjectSpace + reflection — rarely needed, but handy in tests
User.instance_methods(false) # methods defined on User itself
Why it matters
Reach for Data.define (3.2+) when you want a value object — immutable, value-equality semantics, and one line of code. Struct is the mutable older sibling.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
class User
attr_accessor :name, :age
def initialize(name, age)
@name = name
@age = age
end
def greet = "hi, #{@name}"
end
puts User.new('Ada', 36).greet
Try it Yourself »
Exercise
Constructor method name.
def
(name)
@name = name
end
Ten letters.
Discussion
Loading…