Home arrow Ruby-on-Rails arrow Iterators in Ruby
RUBY-ON-RAILS

Iterators in Ruby


In this second part of a three-part article, we continue our discussion of code blocks and begin focusing on iterators as well. It is excerpted from chapter eight of the Ruby Cookbook, written by Lucas Carlson and Leonard Richardson (O'Reilly, 2006; ISBN: 0596523696). Copyright © 2006 O'Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O'Reilly Media.

Author Info:
By: O'Reilly Media
Rating: 5 stars5 stars5 stars5 stars5 stars / 8
March 08, 2007
TABLE OF CONTENTS:
  1. · Iterators in Ruby
  2. · 7.5 Writing an Iterator Over a Data Structure
  3. · 7.6 Changing the Way an Object Iterates
  4. · 7.7 Writing Block Methods That Classify or Collect

print this article
SEARCH DEVARTICLES

Iterators in Ruby
(Page 1 of 4 )

7.4 Blocks as Closures: Using Outside Variables Within a Code Block

Problem

You want to share variables between a method, and a code block defined within it.

Solution

Just reference the variables, and Ruby will do the right thing. Here’s a method that adds a certain number to every element of an array:

  def add_to_all(array, number)
    array.collect { |x| x + number }
  end

  add_to_all([1, 2, 3], 10)   # => [11, 12, 13]

Enumerable#collectcan’t accessnumberdirectly, but it’s passed a block that can access it, sincenumberwas in scope when the block was defined.

Discussion

A Ruby block is a closure: it carries around the context in which it was defined. This is useful because it lets you define a block as though it were part of your normal code, then tear it off and send it to a predefined piece of code for processing.

A Ruby block contains references to the variable bindings, not copies of the values. If the variable changes later, the block will have access to the new value:

  tax_percent = 6
  position = lambda do
   
"I have always supported a #{tax_percent}% tax on imported limes."
  end
  position.call
  # => "I have always supported a 6% tax on imported limes."

  tax_percent = 7.25
  position.call
  # => "I have always supported a 7.25% tax on imported limes."

This works both ways: you can rebind or modify a variable from within a block.

  counter = 0
  4.times { counter += 1; puts "Counter now #{counter}"}
  # Counter now 1
  # Counter now 2
  # Counter now 3
  # Counter now 4
  counter                            # => 4

This is especially useful when you want to simulateinjectorcollect in conjunction with a strange iterator. You can create a storage object outside the block, and add things to it from within the block. This code simulatesEnumerable#collect, but it collects the elements of an array in reverse order:

  accumulator = []
  [1, 2, 3].reverse_each { |x| accumulator << x + 1 }

  accumulator               # => [4, 3, 2]

Theaccumulatorvariable is not within the scope ofArray#reverse_each, but it is within the scope of the block.


blog comments powered by Disqus
RUBY-ON-RAILS ARTICLES

- Ruby-on-Rails Faces Second Security Flaw in ...
- Ruby 2.0 Prepped for February 2013 Release
- Why LinkedIn Switched from Ruby on Rails
- Adding Style with Action Pack
- Handling HTML in Templates with Action Pack
- Filters, Controllers and Helpers in Action P...
- Action Pack and Controller Filters
- Action Pack Categories and Events
- Logging Out, Events and Templates with Actio...
- Action Pack Sessions and Architecture
- More on Action Pack Partial Templates
- Action Pack Partial Templates
- Displaying Error Messages with the Action Pa...
- Action Pack Request Parameters
- Creating an Action Pack Registration Form

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2014 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials