Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Mail Systems
Eclipse Documentation

How To Guides
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Problem Solutions




Ruby Programming
Previous Page Home Next Page

Blocks for Transactions

Blocks can be used to define a chunk of code that must be run under some kind of transactional control. For example, you'll often open a file, do something with its contents, and then want to ensure that the file is closed when you finish. Although you can do this using conventional code, there's an argument for making the file responsible for closing itself. We can do this with blocks. A naive implementation (ignoring error handling) might look something like the following.

class File
  def File.openAndProcess(*args)
    f =*args)
    yield f

File.openAndProcess("testfile", "r") do |aFile|   print while aFile.gets end
This is line one
This is line two
This is line three
And so on...

This small example illustrates a number of techniques. The openAndProcess method is a class method---it may be called independent of any particular File object. We want it to take the same arguments as the conventional method, but we don't really care what those arguments are. Instead, we specified the arguments as *args, meaning ``collect the actual parameters passed to the method into an array.'' We then call, passing it *args as a parameter. This expands the array back into individual parameters. The net result is that openAndProcess transparently passes whatever parameters it received to .

Once the file has been opened, openAndProcess calls yield, passing the open file object to the block. When the block returns, the file is closed. In this way, the responsibility for closing an open file has been passed from the user of file objects back to the files themselves.

Finally, this example uses do...end to define a block. The only difference between this notation and using braces to define blocks is precedence: do...end binds lower than ``{...}''. We discuss the impact of this on page 234.

The technique of having files manage their own lifecycle is so useful that the class File supplied with Ruby supports it directly. If has an associated block, then that block will be invoked with a file object, and the file will be closed when the block terminates. This is interesting, as it means that has two different behaviors: when called with a block, it executes the block and closes the file. When called without a block, it returns the file object. This is made possible by the method Kernel::block_given? , which returns true if a block is associated with the current method. Using it, you could implement (again, ignoring error handling) using something like the following.

class File
  def File.myOpen(*args)
    aFile =*args)
    # If there's a block, pass in the file and close
    # the file when it returns
    if block_given?
      yield aFile
      aFile = nil
    return aFile
Ruby Programming
Previous Page Home Next Page

  Published under the terms of the Open Publication License Design by Interspire