Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Enumerable Module or How I Fell in Love with Ruby

harisamin
September 26, 2011

The Enumerable Module or How I Fell in Love with Ruby

Presented at Cascadia Ruby Conf 2011 July 29, 2011 in Seattle, WA by Haris Amin. The presentation can be viewed here http://confreaks.net/videos/607-cascadiaruby2011-the-enumerable-module-or-how-i-fell-in-love-with-ruby

harisamin

September 26, 2011
Tweet

More Decks by harisamin

Other Decks in Programming

Transcript

  1. THE ENUMERABLE MODULE or How I Fell In Love with

    Ruby! Haris Amin Cascadia Ruby Conf 2011 07/29/2011 Monday, August 1, 2011
  2. WHO IS THIS GUY? • Haris Amin • Software/Web Developer

    • Live in New York City Monday, August 1, 2011
  3. LOOK MA I HAS DEGREE! • Studies Physics/Math in Undergrad

    • E = mc^2 , doesn’t pay for food • Programming, for me in college was just a means to compute something Monday, August 1, 2011
  4. LAST TALK I GAVE AT A CONFERENCE? • Simulation of

    Viscoelastic Fluids • What did I do? • Employed a weighted-norm least-squares finite element method to approximate the solution to Oldroyd-B equations • So...yeah... for me programming was just a way to compute stuff :) Monday, August 1, 2011
  5. WHAT IS THE ENUMERABLE MODULE? • A module, you can

    MIX IT IN! • A bunch of methods that work with collections • Empowers the most notably the Array and Hash classes (among others i.e. Set, Range, File, etc.) Monday, August 1, 2011
  6. HOW TO ‘MIX-IN’ THE ENUMERABLE? • A class ‘including’ or

    ‘mixing-in’ Enumerable must define the ‘#each’ method • Yielded items from the #each method empower the collection awareness for the class Monday, August 1, 2011
  7. • The #collect method executes the provided block to all

    of the values yielded by #each class PlanetExpress include Enumerable def each yield “Bender” yield “Frye” yield “Leela” yield “Zoidberg” end end PlanetExpress.new.collect do |member| “#{member} works at Planet Express” end Monday, August 1, 2011
  8. LOOK AT ALL THESE 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 Monday, August 1, 2011
  9. PROGRAMMER HAPPINESS “Programmers often feel joy when they can concentrate

    on the creative side of programming, so Ruby is designed to make programmers happy.” - Yukihiro Matsumoto (Matz) Monday, August 1, 2011
  10. each • The #each method yields items to a supplied

    block of code one at a time • Classes implement #each differently names = %w{ Frye Leela Zoidberg } names.each do |name| “#{name} works at Planet Express” end Monday, August 1, 2011
  11. find • Elegantly simple, find one item that matches the

    condition supplied by the block • Consider how a library like ActiveRecord would reimplemnt find from Enumerable? names = %w{ Frye Leela Zoidberg } names.find { |name| name.length > 4} Monday, August 1, 2011
  12. group_by • It takes a block, and returns a hash,

    with the returned value from the block set as the key • Consider how one could use this as word count for a document/text names = %w{ Frye Bender Leela Zoidberg } names.group_by { |name| name.length} # => {4=>["Frye"], 6=>["Bender"], 5=>["Leela"], 8=>["Zoidberg"]} Monday, August 1, 2011
  13. grep • Searches for members of the collection according to

    a pattern.... pattern matching • It uses the === operator for pattern matching names = %w{ Frye Bender Leela Zoidberg } names.grep(/oidber/) # => ["Zoidberg"] Monday, August 1, 2011
  14. GREP-ALICOUS! • Using the === allows us to do some

    fancy matching • We can grep for types or objects • Equivalent to stuff.select { |element| String === element} Dr. Zoidberg’s Tip (The doctor is in!) stuff = [ “Zoidberg”, Pizza.new, :homeless, “Dr."] stuff.grep(String) # => [ “Zoidberg”, “Dr.”] Monday, August 1, 2011
  15. map / collection • Think of it as a transformation

    method, that applies the block as a transformation • Always returns a new Array with the transformation applied • Different then #each, return value matters with #map names = %w{ Frye Bender Leela Zoidberg } names.map { |name| name.downcase } # => [“frye”, “bender”, “leela”, “zoidberg” ] Monday, August 1, 2011
  16. ENUMERATOR • We can create an Enumerator without mixing-in the

    Enumerable module and still have the power of Enumerable methods • 3 ways to create Enumerator without mixing-in Enumerable 1. Create Enumerator explicitly with a code block 2. Attach an Enumerator to another object 3. Create Enumerator implicitly with blockless iterators Monday, August 1, 2011
  17. Create Enumerator explicitly with a code block • y is

    the yielder, an instance of Enumerator::Yielder • You don’t yield from the block, you only append to the yielder e = Enumerator.new do |y| y << “Frye” y << “Bender” y << “Leela” y << “Zoidberg” end Monday, August 1, 2011
  18. Attach an Enumerator to another object • knows/learns how to

    implement #each from another object • we’re binding the Enumerator to the #select method of the names array names = %w { Frye Bender Leela Zoidberg } e = names.enum_for(:select) Monday, August 1, 2011
  19. Create Enumerator implicitly with blockless iterators • most iterators when

    called without a block return an Enumerator • our blockless iterator returned the same Enumerator as the enum_for approach names = %w { Frye Leela Bender } names.enum_for(:select) # => #<Enumerator: ["Frye", "Leela", "Bender"]:map> names.map # => #<Enumerator: ["Frye", "Leela", "Bender"]:map> Monday, August 1, 2011
  20. Add Enumerability to an existing object • Now we can

    use Enumerable methods on our ship object module PlanetExpress class Ship PARTS= %w{ sprockets black-matter } def survey_parts PARTS.each {|part| yield part } end end end ship = PlanetExpress::Ship.new enum = ship.enum_for(:survey_parts) Monday, August 1, 2011
  21. Fine Grained Iteration • An Enumerator is an object, it

    can maintain state • Think film reels, state machines, etc... scenes = %w{ credits opening climax end } e = scenes puts e.next puts e.next e.rewind puts e.next Monday, August 1, 2011
  22. CHAINING ENUMERATORS • Normally chaining enumerators isn’t very useful •

    names.map.select might as well be names.select • Most enumerators are just passing the array of values down the chain Monday, August 1, 2011
  23. LAZY SLICE • Instead of creating a 2-element slices for

    the whole array in memory, the enumerator can create slices in a “lazy” manner and only create them as they are needed Dr. Zoidberg’s Tip (can i have a slice) names = %w { Frye Bender Leela Zoidberg } names.each_slice(2).map do |first, second| “#{first} gets a slice & #{second} gets a slice” end Monday, August 1, 2011
  24. MAP WITH INDEX...WTF? • There is no #map_with_index defined in

    Enumerable • Ah but we can chain... chain... chain! Dr. Zoidberg’s Tip (what map? i don’t even know where we are!) names = %w { Leela Bender Frye Zoidberg } names.map.with_index do |name, i| “#{name} has a rank #{i}” end Monday, August 1, 2011
  25. WHAT IS SET? • The Set class is a Standard

    Lib class in Ruby • You use it by requiring it explicitly ( require ‘set’ ) • It stores a collection of unordered, unique values • It mixes-in the Enumerable module Monday, August 1, 2011
  26. SET IS ENUMERABLE class Set include Enumerable #... def each

    block_given? or return enum_for(__method__) @hash.each_key { |o| yield(o) } self end end • Calls a block for each member of the set passing the member as a parameter • Returns an enumerator if no block is given Monday, August 1, 2011
  27. SET IS ENUMERABLE • Actually uses Hash for implementing unique

    values class Set include Enumerable #... def initialize @hash ||= Hash.new enum.nil? and return if block do_with_enum(enum) { |o| add(block[o]) } else merge(enum) end end end Monday, August 1, 2011
  28. SET IS ENUMERABLE • Defines its own implementation of Enumerable

    methods class Set include Enumerable #... def include? @hash.include?(o) end alias member? include? end Monday, August 1, 2011
  29. THEN READ THIS • This talk was inspired by the

    AWESOME discussion of Enumerable by David A. Black • READ IT! SPREAD THE WORD!!!! Monday, August 1, 2011