Stopping an Iteration


You want to interrupt an iteration from within the code block you passed into it.


The simplest way to interrupt execution is to use break. A break statement will jump out of the closest enclosing loop defined in the current method:

	1.upto(10) do |x|
	 puts x
	 break if x == 3
	# 1
	# 2
	# 3



The break statement is simple but it has several limitations. You can't use break within a code block defined with or (in Ruby 1.9 and up) Kernel#proc. If this is a problem for you, use lambda instead:

	aBlock = do |x|
	 puts x
	 break if x == 3
	 puts x + 2
	# 5
	# 7
	# 3
	# LocalJumpError: break from proc-closure

More seriously, you can't use break to jump out of multiple loops at once. Once a loop has run, there's no way to know whether it completed normally or by using break.

The simplest way around this problem is to enclose the code you want to skip within a catch block with a descriptive symbolic name. You can then throw the corresponding symbol when you want to jump to the end of the catch block. This lets you skip out of any number of nested loops and method calls.

The tHRow/catch syntax isn't exception handlingexceptions use a raise/rescue syntax. This is a special flow control construct designed to replace the use of exceptions for flow control (as sometimes happens in Java programs). It's a bit like an old style global GOTO, capable of suddenly moving execution to a faraway part of your program. It keeps your code more readable than a GOTO, though, because it's restricted: a tHRow can only jump to the end of a corresponding catch block.

The best example of the catch..throw syntax is the Find.find function described in Recipe 6.12. When you pass a code block into Find.find, it yields up every directory and file in a certain directory tree. When your code block is given a directory, it can stop find from recursing into that directory by calling Find.prune, which throws a :prune symbol. Using break would stop the find operation altogether; throwing a symbol lets Find.prune know to just skip one directory.

Here's a simplified view of the Find.find and Find.prune code:

	def find(*paths)
	 paths.each do |p|
	 catch(:prune) do
	 # Process p as a file or directory…
	 # When you call Find.prune you'll end up here.

	def prune
	 throw :prune

When you call Find.prune, execution jumps to immediately after the catch(:prune) block. Find.find then starts processing the next file or directory.

See Also

  • Recipe 6.12, "Walking a Directory Tree"
  • ri Find



Date and Time



Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming


Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration

Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399 © 2008-2020.
If you may any questions please contact us: