Home arrow Ruby-on-Rails arrow Page 3 - Exploring Iteration
RUBY-ON-RAILS

Exploring Iteration


In this final part of a three-part series on code blocks and iteration, you'll learn how to stop an iteration, how to hide setup and clean up, and more. This article 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 / 1
March 15, 2007
TABLE OF CONTENTS:
  1. · Exploring Iteration
  2. · 7.9 Looping Through Multiple Iterables in Parallel
  3. · 7.10 Hiding Setup and Cleanup in a Block Method
  4. · 7.11 Coupling Systems Loosely with Callbacks

print this article
SEARCH DEVARTICLES

TOOLS YOU CAN USE

advertisement
Exploring Iteration - 7.10 Hiding Setup and Cleanup in a Block Method
(Page 3 of 4 )

Problem

You have a setup method that always needs to run before custom code, or a cleanup method that needs to run afterwards. You don’t trust the person writing the code (possibly yourself) to remember to call the setup and cleanup methods.

Solution

Create a method that runs the setup code, yields to a code block (which contains the custom code), then runs the cleanup code. To make sure the cleanup code always runs, even if the custom code throws an exception, use a begin/finally block.

  def between_setup_and_cleanup
    setup
    begin
    
yield
    finally
      cleanup
    end
  end

Here’s a concrete example. It adds a DOCTYPE and an HTML tag to the beginning of an HTML document. At the end, it closes the HTML tag it opened earlier. This saves you a little bit of work when you’re generating HTML files.

  def write_html(out, doctype=nil)
    doctype ||= %{<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   
"http://www.w3.org/TR/html4/loose.dtd">}
    out.puts doctype
    out.puts '<html>'
    begin
     
yield out
    ensure
      out.puts '</html>'
    end
  end

  write_html($stdout) do |out|
   
out.puts '<h1>Sorry, the Web is closed.</h1>'
  end
  # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  # "http://www.w3.org/TR/html4/loose.dtd">
  # <html>
  # <h1>Sorry, the Web is closed.</h1>
  # </html>

Discussion

This useful technique shows up most often when there are scarce resources (such as file handles or database connections) that must be closed when you’re done with them, lest they all get used up. A language that makes the programmer remember these resources tends to leak those resources, because programmers are lazy. Ruby makes it easy to be lazy and still do the right thing.

You’ve probably used this technique already, with the theKernel#openandFile#openmethods for opening files on disk. These methods accept a code block that manipulates an already open file. They open the file, call your code block, and close the file once you’re done:

  open('output.txt', 'w') do |out|
    out.puts 'Sorry, the filesystem is also closed.'
  end

Ruby’s standardcgimodule takes thewrite_htmlexample to its logical conclusion.* You can construct an entire HTML document by nesting blocks inside each other. Here’s a small Ruby CGI that outputs much the same document as thewrite_htmlexample above.

  #!/usr/bin/ruby

  # closed_cgi.rb

  require 'cgi'
  c = CGI.new("html4")
 

  c.out do
    c.html do
      c.h1 { 'Sorry, the Web is closed.' }
    end
  end

Note the multiple levels of blocks: the block passed intoCGI#outsimply callsCGI#htmlto generate the DOCTYPE and the<html>tags. The<html>tags contain the result of a call toCGI#h1, which encloses some plain text in<h1>tags. The program produces this output:

  Content-Type: text/html
  Content-Length: 137

  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
   "http://www.w3.org/TR/html4/strict.dtd">
  <HTML><h1>Sorry, the Web is closed.
</H1></HTML>

TheXmlMarkup class in Ruby’sbuildergem works the same way: you can write Ruby code that resembles the structure of the document it creates:

  require 'rubygems'
  require 'builder'
  xml = Builder::XmlMarkup.new.message('type' => 'apology') do |b|
   
b.content('Sorry, Web Services are closed.')
  end
  puts xml
  # <message type="apology">
  #  <content>Sorry, Web Services are closed.</content>
  # </message>

See Also

  1. Recipe 6.13, “Locking a File,” uses this technique to create a method that locks a file, and automatically unlocks it when you’re done using it
  2. Recipe 11.9, “Creating and Modifying XML Documents”
  3. Recipe 20.11, “Avoiding Deadlock,” uses this technique to have your thread lock multiple resources in the right order, and unlock them when you’re done using them


blog comments powered by Disqus
RUBY-ON-RAILS ARTICLES

- 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
- Ruby on Rails Templates and Layouts
- Action Pack Controller Creation
- Writing an Action Pack Controller

Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 



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