Blocks as Closures: Using Outside Variables Within a Code Block

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#collect can't access number directly, but it's passed a block that can access it, since number was 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 simulate inject or collect 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 simulates Enumerable#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]

The accumulator variable is not within the scope of Array#reverse_each, but it is within the scope of the block.


Strings

Numbers

Date and Time

Arrays

Hashes

Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming

XML and HTML

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

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net