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.
Recent Comments