The Enumerable Module
Part of the Object Oriented Programming section of Coddy's Ruby journey. Lesson 30 of 57.
Enumerable is the module behind the collection methods of arrays and hashes. A class that defines each, yielding its elements one by one, and includes Enumerable gets map, select, count, sort_by, min_by, sum, include? and dozens more:
class Playlist
include Enumerable
def initialize(*songs)
@songs = songs
end
def each
@songs.each { |song| yield song }
end
end
list = Playlist.new("Intro", "Dune", "Outro")
puts list.map(&:upcase).join(", ")
puts list.select { |s| s.size > 4 }.inspect
puts list.count
puts list.include?("Dune")Output:
INTRO, DUNE, OUTRO
["Intro", "Outro"]
3
trueyield passes a value to the block the caller gave to each. The class decides what one element is, for example a line of text, a pair of values or one of its own objects:
class Inventory
include Enumerable
def initialize
@stock = { "apple" => 3, "pear" => 0, "plum" => 7 }
end
def each
@stock.each { |name, qty| yield name, qty }
end
end
inv = Inventory.new
p inv.select { |_, qty| qty.positive? }.map(&:first)
p inv.max_by { |_, qty| qty }Output:
["apple", "plum"]
["plum", 7]The elements do not have to be stored. each can compute them as it goes, and methods such as first stop the loop early:
class Squares
include Enumerable
def initialize(limit)
@limit = limit
end
def each
n = 1
while n * n <= @limit
yield n * n
n += 1
end
end
end
p Squares.new(50).to_a
p Squares.new(1000).first(3)
puts Squares.new(100).sumOutput:
[1, 4, 9, 16, 25, 36, 49]
[1, 4, 9]
385When the elements define <=>, the sorting methods of Enumerable, such as sort, min and max, work without a block. Otherwise they take one, as in sort_by and min_by:
class Team
include Enumerable
def each(&block)
@players.each(&block) # pass the block straight on
end
end
team.sort_by(&:age)
team.min_by(&:score)Challenge
EasyComplete the class Playlist. It holds Song objects (with title and seconds) added with add, includes Enumerable and defines each, which yields every song in the order added.
The supplied code adds one song per input line (title,seconds) and then uses only Enumerable methods on the playlist: it prints the number of songs, the titles joined by commas, the total length in m:ss, the longest title, and the titles of songs over 3 minutes, sorted alphabetically (or none).
Your code goes in song.rb and playlist.rb. main.rb holds the supplied input/output code and cannot be edited.
Try it yourself
require_relative 'song'
require_relative 'playlist'
# Supplied input/output code: keep it as it is
input = []
while (line = gets)
input << line.chomp
end
list = Playlist.new
input.each do |line|
title, seconds = line.split(",")
list.add(Song.new(title, seconds.to_i))
end
total = list.sum(&:seconds)
long = list.select { |s| s.seconds > 180 }.map(&:title).sort
puts "songs: #{list.count}"
puts "titles: #{list.map(&:title).join(", ")}"
puts format("total: %d:%02d", total / 60, total % 60)
puts "longest: #{list.max_by(&:seconds).title}"
puts "over 3 min: #{long.empty? ? "none" : long.join(", ")}"
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Classes and Objects
Working With FilesDefining ClassesInstance VariablesMethods and selfto_s and inspectRecap - Library Card7Polymorphism and Duck Typing
PolymorphismDuck TypingAbstract Methodscase and ClassesRecap - Payment Methods2Accessors and Self
Readers and WritersCustom Settersself in MethodsIdentity and EqualityRecap - Contact List8Special Methods
Equality and hashOperator MethodsIndexing and AppendingCustom CollectionsRecap - Fractions11Project: Library Management
Books and MembersBorrowing Books3Class Methods and Variables
Class MethodsClass Instance VariablesConstantsFactory MethodsRecap - Coupon Codes6Modules and Mixins
Modules and includeExtending ObjectsThe Comparable ModuleThe Enumerable ModuleRecap - Sports LeaguePractice on your own: Online Ruby compiler