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
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com

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

  




 

 

Ruby Programming
Previous Page Home Next Page

Making Blocks More Dynamic

We've already seen how you can associate a block with a method call.

listBones("aardvark") do |aBone|
  # ...
end

Normally, this is perfectly good enough---you associate a fixed block of code with a method, in the same way you'd have a chunk of code after an if or while statement.

Sometimes, however, you'd like to be more flexible. For example, we may be teaching math skills.[Of course, Andy and Dave would have to learn math skills first. Conrad Schneiker reminded us that there are three kinds of people: those who can count and those who can't.] The student could ask for an n-plus table or an n-times table. If the student asked for a 2-times table, we'd output 2, 4, 6, 8, and so on. (This code does not check its inputs for errors.)

print "(t)imes or (p)lus: "
times = gets
print "number: "
number = gets.to_i

if times =~ /^t/   puts((1..10).collect { |n| n*number }.join(", ")) else   puts((1..10).collect { |n| n+number }.join(", ")) end
produces:
(t)imes or (p)lus: t
number: 2
2, 4, 6, 8, 10, 12, 14, 16, 18, 20

This works, but it's ugly, with virtually identical code on each branch of the if statement. If would be nice if we could factor out the block that does the calculation.

print "(t)imes or (p)lus: "
times = gets
print "number: "
number = gets.to_i

if times =~ /^t/   calc = proc { |n| n*number } else   calc = proc { |n| n+number } end puts((1..10).collect(&calc).join(", "))
produces:
(t)imes or (p)lus: t
number: 2
2, 4, 6, 8, 10, 12, 14, 16, 18, 20

If the last argument to a method is preceded by an ampersand, Ruby assumes that it is a Proc object. It removes it from the parameter list, converts the Proc object into a block, and associates it with the method.

This technique can also be used to add some syntactic sugar to block usage. For example, you sometimes want to take an iterator and store each value it yields into an array. We'll reuse our Fibonacci number generator from page 40.

a = []
fibUpTo(20) { |val| a << val } nil
a.inspect "[1, 1, 2, 3, 5, 8, 13]"

This works, but our intention isn't quite as transparent as we may like. Instead, we'll define a method called into, which returns the block that fills the array. (Notice at the same time that the block returned really is a closure---it references the parameter anArray even after method into has returned.)

def into(anArray)
  return proc { |val| anArray << val }
end
fibUpTo 20, &into(a = [])
a.inspect "[1, 1, 2, 3, 5, 8, 13]"

Ruby Programming
Previous Page Home Next Page

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