Generally if your class has an array/hash, sometimes you don’t want to expose the implementation of those collections outside of the object. Creating your own iterator will make your object easier to use.

class Headphone
  attr_reader :name, :brand, :version

  def initialize(name, brand, version)
    @name = name
    @brand = brand
    @version = version
    @accessories = []
  end

  def add_accessory(name)
    @accessories << name
  end

  def each_accessory
    @accessories.each { |x| yield x.name }
  end
end

Accessory = Struct.new(:name, :color)
a1 = Accessory.new("Headphone cable", :black)
a2 = Accessory.new("Connector Adapter", :gold)
a3 = Accessory.new("Carrying Pouch", :gray)
a4 = Accessory.new("Earpds", :brown)

a = Headphone.new("AudioTechnica", "M50X", 1.0)

a.add_accessory(a1)
a.add_accessory(a2)
a.add_accessory(a3)
a.add_accessory(a4)

a.each_accessory do |x|
  puts "Accessory: #{x}"
end

# Accessory: Headphone cable
# Accessory: Connector Adapter
# Accessory: Carrying Pouch
# Accessory: Earpds

I think another way to demonstrate this is to show how the “each” and “times” methods work in Ruby. There isn’t much magic involved. For times all you have to do is open up the Integer class and define your own with a while loop:

class Integer
  def my_times
    i = 0
    while i < self
      yield i
      i += 1
    end
  end
end

13.my_times do |x|
  puts x
end

Output:
0
1
2
3
4
5
6
7
8
9
10
11
12

As for each it’s very similar:

class Array
  def my_each
    i = 0
    while i < self.size
      yield self[i]
      i += 1
    end
  end
end

types_of_bacon = ["Canadian", "Turkey", "Cottage", "Smoked"]
types_of_bacon.my_each do |b|
  puts b
end

Output: 
Canadian
Turkey
Cottage
Smoked

Hopefully this helps demystify these methods we use and love so much.