ENUMERABLE
A powerful Ruby Module for Collections
WHY USE ENUMERABLES

• Ruby's Enumerable module has methods for all kinds of tasks
  which operate on a collection.
• If you can imagine a use for the #each method other than simply
  iterating, there is a good chance a method exists to do what you
  have in mind.
WHAT DOES ENUMERABLE
           MEAN?
• Collection objects (instances of Array, Hash, etc) typically “mixin”
  the Enumerable module
• The Enumerable module gives objects of collection classes
  additional collection-specific behaviors.
• The class requiring the Enumerable module must have an #each
  method because the additional collection-specific behaviors given
  by Enumerable are defined in terms of #each
MIXING IN ENUMERABLE

class MyCollection

 include Enumerable

 #lots of code


 def each

 
 #more code

 end
end
VIEW ALL CLASSES MIXING IN
             ENUMERABLE


ObjectSpace.each_object(Class) do |cl|

 
 puts cl if cl < Enumerable
end
Enumerable::Enumerator
Struct::Tms
Dir
File
IO
Range
Struct
Hash
Array
String
Struct::Group
Struct::Passwd
MyCollection
StringIO
Gem::SourceIndex
YAML::Set
YAML::Pairs
YAML::Omap
YAML::SpecialHas
TEST AN INSTANCE OR CLASS

>> a = [1,2,3]
=> [1, 2, 3]
>> a.respond_to? :any?
=> true
>> a.is_a? Enumerable
=> true
>> Array < Enumerable
=> true
ENUMERABLE METHODS

• Collection Behavior
EACH
• Classes that include the Enumerable module must have an #each
  method.
• The #each method yields items to a supplied code block, one
  at a time
• Different Classes define #each differently
  • Array: #each yields each element
  • Hash: each yields #each key/value pair as a two-element array

>>   v_names = %w(car truck bike)
=>   ["car", "truck", "bike"]
>>   v_names.each do |vehicle|
?>   puts vehicle
>>   end
MAP

• The map method modifies each member according to
  instructions in a block and returns the modified collection of
  members.

>> v_names.map { |v| v.upcase}
=> ["CAR", "TRUCK", "BIKE"]
GREP

• The grep method 'searches' for members using a regular
  expression.
>> v_names.grep /a/
=> ["car"]
>> v_names.grep(/a/) { |v| v.upcase}
=> ["CAR"]
FIND
>> v_names.find { |v| v.size > 3}
=> "truck"

>> v_names.find { |v| v.size > 2}
=> "car"

>> v_names.find do |v|
v.size > 3 && v.size < 5
end
=> "bike"
ALL?

• The all? method returns true if all of the members of a collection
  satisfy the evaluation of the block. Otherwise it returns false.


>> v_names.all? { |v| v.length > 2}
=> true


>> v_names.all? { |v| v.length > 10}
=> false
ANY?

• The any? method returns true if any of the members of a
  collection satisfy the evaluation of the block. Otherwise it returns
  false.


>> v_names.any? { |v| v.length == 3}
=> true

>> v_names.any? { |v| v = "car"}
=> true
WORKING WITH COMPLEX
           DATA
irb
>> load 'vehicles.rb'
=> true
INJECT

>>   $vehicles.inject(0) do |total_wheels, v|
?>   total_wheels += v[:wheels]
>>   end
=>   10

>>   $vehicles.inject([]) do |classes, v|
?>   classes += v[:classes]
>>   end.uniq
=>   [:ground, :water, :air]
COMPLEX OPERATIONS
>>   $vehicles.find do |v|
?>   v[:name] =~ /Plane/
>>   end[:name]
=>   "Plane"

>>   $vehicles.find_all do |v|
?>   v[:name] =~ /Plane/
>>   end.collect { |v| v[:name] }
=>   ["Plane", "Sea Plane"]

>>   $vehicles.find_all do |v|
?>   v[:wheels] > 0
>>   end.collect { |v| v[:name] }
=>   ["Car", "Truck", "Bike"]
COMPLEX OPERATIONS
           CONTINUED
>>   $vehicles.find_all do |v|
?>   v[:classes].include? :ground
>>   end.collect { |v| v[:name] }
=>   ["Car", "Truck", "Bike", "Sea Plane"]

>>   $vehicles.find_all do |v|
?>   v[:classes].include? :air
>>   end.collect { |v| v[:name] }
=>   ["Plane", "Helicopter", "Sea Plane"]

Enumerables

  • 1.
    ENUMERABLE A powerful RubyModule for Collections
  • 2.
    WHY USE ENUMERABLES •Ruby's Enumerable module has methods for all kinds of tasks which operate on a collection. • If you can imagine a use for the #each method other than simply iterating, there is a good chance a method exists to do what you have in mind.
  • 3.
    WHAT DOES ENUMERABLE MEAN? • Collection objects (instances of Array, Hash, etc) typically “mixin” the Enumerable module • The Enumerable module gives objects of collection classes additional collection-specific behaviors. • The class requiring the Enumerable module must have an #each method because the additional collection-specific behaviors given by Enumerable are defined in terms of #each
  • 4.
    MIXING IN ENUMERABLE classMyCollection include Enumerable #lots of code def each #more code end end
  • 5.
    VIEW ALL CLASSESMIXING IN ENUMERABLE ObjectSpace.each_object(Class) do |cl| puts cl if cl < Enumerable end
  • 6.
  • 7.
    TEST AN INSTANCEOR CLASS >> a = [1,2,3] => [1, 2, 3] >> a.respond_to? :any? => true >> a.is_a? Enumerable => true >> Array < Enumerable => true
  • 8.
  • 9.
    EACH • Classes thatinclude the Enumerable module must have an #each method. • The #each method yields items to a supplied code block, one at a time • Different Classes define #each differently • Array: #each yields each element • Hash: each yields #each key/value pair as a two-element array >> v_names = %w(car truck bike) => ["car", "truck", "bike"] >> v_names.each do |vehicle| ?> puts vehicle >> end
  • 10.
    MAP • The mapmethod modifies each member according to instructions in a block and returns the modified collection of members. >> v_names.map { |v| v.upcase} => ["CAR", "TRUCK", "BIKE"]
  • 11.
    GREP • The grepmethod 'searches' for members using a regular expression. >> v_names.grep /a/ => ["car"] >> v_names.grep(/a/) { |v| v.upcase} => ["CAR"]
  • 12.
    FIND >> v_names.find {|v| v.size > 3} => "truck" >> v_names.find { |v| v.size > 2} => "car" >> v_names.find do |v| v.size > 3 && v.size < 5 end => "bike"
  • 13.
    ALL? • The all?method returns true if all of the members of a collection satisfy the evaluation of the block. Otherwise it returns false. >> v_names.all? { |v| v.length > 2} => true >> v_names.all? { |v| v.length > 10} => false
  • 14.
    ANY? • The any?method returns true if any of the members of a collection satisfy the evaluation of the block. Otherwise it returns false. >> v_names.any? { |v| v.length == 3} => true >> v_names.any? { |v| v = "car"} => true
  • 15.
    WORKING WITH COMPLEX DATA irb >> load 'vehicles.rb' => true
  • 16.
    INJECT >> $vehicles.inject(0) do |total_wheels, v| ?> total_wheels += v[:wheels] >> end => 10 >> $vehicles.inject([]) do |classes, v| ?> classes += v[:classes] >> end.uniq => [:ground, :water, :air]
  • 17.
    COMPLEX OPERATIONS >> $vehicles.find do |v| ?> v[:name] =~ /Plane/ >> end[:name] => "Plane" >> $vehicles.find_all do |v| ?> v[:name] =~ /Plane/ >> end.collect { |v| v[:name] } => ["Plane", "Sea Plane"] >> $vehicles.find_all do |v| ?> v[:wheels] > 0 >> end.collect { |v| v[:name] } => ["Car", "Truck", "Bike"]
  • 18.
    COMPLEX OPERATIONS CONTINUED >> $vehicles.find_all do |v| ?> v[:classes].include? :ground >> end.collect { |v| v[:name] } => ["Car", "Truck", "Bike", "Sea Plane"] >> $vehicles.find_all do |v| ?> v[:classes].include? :air >> end.collect { |v| v[:name] } => ["Plane", "Helicopter", "Sea Plane"]