Inside Enumerable Mike Bowler Gargoyle Software Inc.
Agenda What is Enumerable? What can you do with it? How does it do that?
What is it? It’s a group of related methods all having to do with collections It’s the interesting part behind Array, Set, Hash and Range It’s a Module (often called a mixin)
hash = { :a  => 1,  :b  => 2} hash.collect  do  |key, value|  value * 4 end [4,8] [4,8,12] [4,8,12] array = [1,2,3] array.collect  do  |value| value * 4 end range = 1..3 range.collect  do  |value| value * 4 end
hash = { :a  => 1,  :b  => 2} hash.collect  do  |key, value|  value * 4 end array = [1,2,3] array.collect  do  |value| value * 4 end range = 1..3 range.collect  do  |value| value * 4 end module  Enumerable def  collect ... end end
multiple inheritance
mixins
Mixins Cannot be instantiated Can be mixed in
Mixins usually  don’t stand alone don’t stand alone Typically... mixins aren’t completely self-contained  they rely on certain methods being present on the class they are mixed into This isn’t mandatory but is very common Let’s look at an example...
Enumerable requires each() [1,2,3].collect {|i| i*2} [2,4,6]
Enumerable.collect class  Foo include  Enumerable def  each yield 1 yield 2 yield 3 end end Foo.new.collect do |num| num * 2 end module  Enumerable def  collect array = [] each do |a| array <<  yield (a) end array end end
Enumerable.collect module  Enumerable def  collect array = [] each do |a| array <<  yield (a) end array end end class  Foo include  Enumerable def  each yield 1 yield 2 yield 3 end end Foo.new.collect do |num| num * 2 end
Enumerable.collect module  Enumerable def  collect array = [] each do |a| array <<  yield (a) end array end end class  Foo include  Enumerable def  each yield 1 yield 2 yield 3 end end Foo.new.collect do |num| num * 2 end
Enumerable.collect class  Foo include  Enumerable def  each yield 1 yield 2 yield 3 end end Foo.new.collect do |num| num * 2 end module  Enumerable def  collect array = [] each do |a| array <<  yield (a) end array end end
Enumerable.collect module  Enumerable def  collect array = [] each do |a| array <<  yield (a) end array end end class  Foo include  Enumerable def  each yield 1 yield 2 yield 3 end end Foo.new.collect do |num| num * 2 end
Enumerable.collect class  Foo include  Enumerable def  each yield 1 yield 2 yield 3 end end Foo.new.collect do |num| num * 2 end module  Enumerable def  collect array = [] each do |a| array <<  yield (a) end array end end Result [2,4,6]
Required methods collect() would not have worked if Foo hadn’t declared each() All methods in Enumerable require each() A couple also require <=> min(), max(), sort() Comparison operator
Enumerable methods all?, any?, collect, detect, each_cons, each_slice, each_with_index, entries, enum_cons, enum_slice, enum_with_index, find, find_all, grep, include?, inject, map, max, member?, min, partition, reject, select, sort, sort_by, to_a, to_set, zip
any? [1,2,3,4].any? {|a| a > 2} Returns true if this block... ...returns true for  any of these values
all? [1,2,3,4].all? {|a| a > 2} Returns true if this block... ...returns true for  ALL of these values
collect, map “Returns a new array with the results of running block once for every element in enum” map is an alias for collect [1,2,3].collect {|i| i*2} [2,4,6]
find, detect find(ifnone = nil) {| obj | block } => obj or nil Passes each entry in enum to block. Returns the first for which block is not false. If no object matches, calls ifnone and returns its result when it is specified, or returns nil detect is an alias for find
find_all, select find_all {| obj | block } => array Returns an array containing all elements of enum for which block is not false select is an alias for find_all
grep grep(pattern) => array Returns an array of every element in enum for which Pattern === element. If the optional block is supplied, each matching element is passed to it, and the block‘s result is stored in the output array Case equality
Case equality For most objects, === is the same as == Case equality Regular equality
Case equality case myvar when 1..50 # do something when 51 # do something when /^\d+$/ # do something end Within the range This exact number Matches this regular expression Different kind of equality as a convenience in case statements
Case equality in grep [1,2,3].grep(1..50) [1,2,3].grep(51) [1,2,3].grep(/^\d+$/) Within the range This exact number Matches this regular expression
Wrap up Enumerable is already mixed into all the core collections You can mix it into any of your classes so long as you implement each() It provides all kinds of useful methods to walk across the collections and get information out of them
Shameless Plug I can help you with your Ruby and/or Rails projects.  Ask me how. Mike Bowler [email_address] www.GargoyleSoftware.com (company) www.SphericalImprovement.com (blog)

Inside Enumerable

  • 1.
    Inside Enumerable MikeBowler Gargoyle Software Inc.
  • 2.
    Agenda What isEnumerable? What can you do with it? How does it do that?
  • 3.
    What is it?It’s a group of related methods all having to do with collections It’s the interesting part behind Array, Set, Hash and Range It’s a Module (often called a mixin)
  • 4.
    hash = {:a => 1, :b => 2} hash.collect do |key, value| value * 4 end [4,8] [4,8,12] [4,8,12] array = [1,2,3] array.collect do |value| value * 4 end range = 1..3 range.collect do |value| value * 4 end
  • 5.
    hash = {:a => 1, :b => 2} hash.collect do |key, value| value * 4 end array = [1,2,3] array.collect do |value| value * 4 end range = 1..3 range.collect do |value| value * 4 end module Enumerable def collect ... end end
  • 6.
  • 7.
  • 8.
    Mixins Cannot beinstantiated Can be mixed in
  • 9.
    Mixins usually don’t stand alone don’t stand alone Typically... mixins aren’t completely self-contained they rely on certain methods being present on the class they are mixed into This isn’t mandatory but is very common Let’s look at an example...
  • 10.
    Enumerable requires each()[1,2,3].collect {|i| i*2} [2,4,6]
  • 11.
    Enumerable.collect class Foo include Enumerable def each yield 1 yield 2 yield 3 end end Foo.new.collect do |num| num * 2 end module Enumerable def collect array = [] each do |a| array << yield (a) end array end end
  • 12.
    Enumerable.collect module Enumerable def collect array = [] each do |a| array << yield (a) end array end end class Foo include Enumerable def each yield 1 yield 2 yield 3 end end Foo.new.collect do |num| num * 2 end
  • 13.
    Enumerable.collect module Enumerable def collect array = [] each do |a| array << yield (a) end array end end class Foo include Enumerable def each yield 1 yield 2 yield 3 end end Foo.new.collect do |num| num * 2 end
  • 14.
    Enumerable.collect class Foo include Enumerable def each yield 1 yield 2 yield 3 end end Foo.new.collect do |num| num * 2 end module Enumerable def collect array = [] each do |a| array << yield (a) end array end end
  • 15.
    Enumerable.collect module Enumerable def collect array = [] each do |a| array << yield (a) end array end end class Foo include Enumerable def each yield 1 yield 2 yield 3 end end Foo.new.collect do |num| num * 2 end
  • 16.
    Enumerable.collect class Foo include Enumerable def each yield 1 yield 2 yield 3 end end Foo.new.collect do |num| num * 2 end module Enumerable def collect array = [] each do |a| array << yield (a) end array end end Result [2,4,6]
  • 17.
    Required methods collect()would not have worked if Foo hadn’t declared each() All methods in Enumerable require each() A couple also require <=> min(), max(), sort() Comparison operator
  • 18.
    Enumerable methods all?,any?, collect, detect, each_cons, each_slice, each_with_index, entries, enum_cons, enum_slice, enum_with_index, find, find_all, grep, include?, inject, map, max, member?, min, partition, reject, select, sort, sort_by, to_a, to_set, zip
  • 19.
    any? [1,2,3,4].any? {|a|a > 2} Returns true if this block... ...returns true for any of these values
  • 20.
    all? [1,2,3,4].all? {|a|a > 2} Returns true if this block... ...returns true for ALL of these values
  • 21.
    collect, map “Returnsa new array with the results of running block once for every element in enum” map is an alias for collect [1,2,3].collect {|i| i*2} [2,4,6]
  • 22.
    find, detect find(ifnone= nil) {| obj | block } => obj or nil Passes each entry in enum to block. Returns the first for which block is not false. If no object matches, calls ifnone and returns its result when it is specified, or returns nil detect is an alias for find
  • 23.
    find_all, select find_all{| obj | block } => array Returns an array containing all elements of enum for which block is not false select is an alias for find_all
  • 24.
    grep grep(pattern) =>array Returns an array of every element in enum for which Pattern === element. If the optional block is supplied, each matching element is passed to it, and the block‘s result is stored in the output array Case equality
  • 25.
    Case equality Formost objects, === is the same as == Case equality Regular equality
  • 26.
    Case equality casemyvar when 1..50 # do something when 51 # do something when /^\d+$/ # do something end Within the range This exact number Matches this regular expression Different kind of equality as a convenience in case statements
  • 27.
    Case equality ingrep [1,2,3].grep(1..50) [1,2,3].grep(51) [1,2,3].grep(/^\d+$/) Within the range This exact number Matches this regular expression
  • 28.
    Wrap up Enumerableis already mixed into all the core collections You can mix it into any of your classes so long as you implement each() It provides all kinds of useful methods to walk across the collections and get information out of them
  • 29.
    Shameless Plug Ican help you with your Ruby and/or Rails projects. Ask me how. Mike Bowler [email_address] www.GargoyleSoftware.com (company) www.SphericalImprovement.com (blog)