Inheritance
Ruby has single inheritance via class Child < Parent plus modules for shared behaviour (include, prepend, extend). The Method Resolution Order (MRO) walks ancestors top-down.
Inheritance, modules, super, prepend
EXAMPLE
# 1) Single inheritance
class Animal
def initialize(name)
@name = name
end
def sound = "?"
def describe = "#{self.class.name.downcase} called #{@name} says #{sound}"
end
class Dog < Animal
def sound = "woof"
end
puts Dog.new("Rex").describe # "dog called Rex says woof"
# 2) super — call the parent method
class Cat < Animal
def initialize(name, color)
super(name)
@color = color
end
def describe
"#{super} (#{@color})"
end
end
# 3) super vs super() — args
class Foo < Bar
def call(a, b)
super # passes a, b to parent
super() # passes NOTHING to parent
super(a) # passes ONLY a
end
end
# 4) Modules — share behaviour without inheritance
module Auditable
def audit(action)
puts "[#{Time.now}] #{self.class.name}#\#{action}"
end
end
module Discountable
def discount(percent)
@price * (1 - percent / 100.0)
end
end
class Order
include Auditable # adds instance methods
include Discountable
def initialize(price) = @price = price
end
o = Order.new(100)
o.audit("create")
puts o.discount(10) # 90.0
# 5) extend — add module methods as CLASS methods
module SiteHelpers
def site_name = "My Site"
end
class Page
extend SiteHelpers
end
Page.site_name # "My Site"
# 6) include vs prepend — controls ancestor order
module Logger
def call(*args)
puts "calling"
super
end
end
class Service
prepend Logger # Logger#call WRAPS Service#call (super calls down)
def call(name) = "hello #{name}"
end
puts Service.new.call("Ada")
# calling
# hello Ada
Service.ancestors
# [Logger, Service, Object, Kernel, BasicObject]
# 7) Method Resolution Order
# Ruby walks ancestors top-to-bottom; the first defined method wins.
puts Service.ancestors # check what's included where
# 8) Abstract-ish base class — raise NotImplementedError
class Reporter
def render = raise NotImplementedError, "subclasses must override #render"
def title = "Untitled"
end
class PdfReporter < Reporter
def render = "<pdf>"
end
# 9) Singleton class — define a method on ONE object
ada = User.new("Ada")
def ada.greeting = "Hello, Ada specifically!"
ada.greeting # works
# User.new("Bo").greeting # NoMethodError
# 10) Modules with shared state (rarely needed) — use class-level vars carefully
module Counter
def self.included(base)
base.class_variable_set(:@@count, 0)
base.define_singleton_method(:count) { class_variable_get(:@@count) }
end
def bump = self.class.class_variable_set(:@@count, self.class.class_variable_get(:@@count) + 1)
end
# 11) Composition > inheritance
# Default to MODULES + COMPOSITION; reach for inheritance only when there's a true is-a relationship.
# Inheritance trees deeper than ~3 levels become hard to read.
Why it matters
prepend + super is the cleanest way to wrap behaviour (logging, caching, timing) without forking the original method. The decorator pattern, Ruby-style — one module per concern.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
class Animal
def speak; '…'; end
end
class Dog < Animal
def speak; 'woof'; end
end
Try it Yourself »
Discussion
Loading…