Ruby
02 / 07

OOP, Modules & Mixins

Ruby: OOP, Modules & Mixins

Classes

class Animal
  attr_accessor :name, :age  # generates getter + setter
  attr_reader :species       # getter only
  attr_writer :nickname      # setter only

  @@count = 0               # class variable

  def initialize(name, age, species)
    @name = name
    @age = age
    @species = species
    @@count += 1
  end

  def self.count             # class method
    @@count
  end

  def to_s                   # string representation
    "#{@species} named #{@name}"
  end

  def <=>(other)             # comparison (enables sort)
    @age <=> other.age
  end

  protected

  def secret_method          # only accessible within class hierarchy
  end

  private

  def internal               # only accessible within this object
  end
end

class Dog < Animal           # inheritance
  def initialize(name, age)
    super(name, age, "Dog")  # call parent initialize
  end

  def speak
    "Woof!"
  end

  def to_s
    super + " (dog)"         # call parent to_s
  end
end

rex = Dog.new("Rex", 3)
puts rex         # "Dog named Rex (dog)"
Dog.count        # 1

Modules & Mixins

# Module: namespace + mixin (can't be instantiated)
module Greetable
  def greet
    "Hello, I am #{name}"
  end

  def farewell
    "Goodbye from #{name}"
  end
end

module Serializable
  def to_json
    instance_variables.each_with_object({}) do |var, h|
      h[var.to_s.delete('@')] = instance_variable_get(var)
    end.to_json
  end
end

class Person
  include Greetable     # mixin — adds instance methods
  include Serializable
  extend Greetable      # extend — adds as class methods

  attr_reader :name

  def initialize(name)
    @name = name
  end
end

alice = Person.new("Alice")
alice.greet      # "Hello, I am Alice"
alice.to_json    # '{"name":"Alice"}'

# Comparable mixin — adds <, <=, >, >=, between?, clamp
class Box
  include Comparable
  attr_reader :volume

  def initialize(volume)
    @volume = volume
  end

  def <=>(other)
    volume <=> other.volume
  end
end

# Enumerable mixin — adds map, select, sort, etc.
class WordCollection
  include Enumerable

  def initialize(words)
    @words = words
  end

  def each(&block)           # Enumerable requires each
    @words.each(&block)
  end
end

Duck Typing & Interfaces

  • Ruby has no interfaces — uses duck typing: "if it responds to the method, it works"

  • respond_to?(:method_name) — check before calling a method on an unknown object

  • is_a? / kind_of? — check class membership

  • Comparable, Enumerable — standard mixins that define protocols through duck typing

  • Struct: Struct.new(:name, :age) — creates a simple class with accessors and equality

Point = Struct.new(:x, :y) do
  def distance_to(other)
    Math.sqrt((x - other.x)**2 + (y - other.y)**2)
  end
end

p = Point.new(0, 0)
q = Point.new(3, 4)
p.distance_to(q)  # 5.0
p == Point.new(0, 0)  # true (value equality)

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free