procs and iterator Blocks The closest thing to a Python function object in Ruby is the proc object, which is an encapsulated block of code.
b = proc{ |x,y| x**2 + y } # same as Proc.new p b.call(3,1) # 10 p b[3,1] # 10 The second form is a shortcut for the call, just as parentheses are for Python functions. A block is used as an iterator in the CLU sense. An iterator in Ruby is not merely a function that iterates through a list of objects. It is a block of code that may be called from within the associated method zero or more times, and is an inherent part of Ruby's design and syntax.
3.times{ |i| puts "#{ i} . Iterator blocks are closures" } ["A","B","C"].collect{ |t| t.downcase! } There are many methods that make use of Ruby iterator blocks, and it is a powerful feature of Ruby. You can make your own methods that may or may not require a block.
def do_after(t,&b) # block is required sleep t b.call end do_after(5){ puts "Are we there yet?" } def mymeth(x) # block not required myblock = proc{ |n| n**2 } if block_given? # check for block print "Your block produces: ", yield(x) else print "My block produces: ", myblock.call(x) end end mymeth(3) # My block produces: 9 mymeth(3){ |x| x**3 } # Your block produces: 27 Be forewarned that the iterator block has a hybrid scope. It is not separate from the surrounding namespace, although it encapsulates it. This means that the enclosing namespace becomes part of the block's binding as well. However, local variables defined for the first time inside a block stay local to that block.
def f(x); x**2; end v = 32; b = 2 g = proc{ |n| puts f(n) + b } # b is used g[3] # 11 p v # 3 (v was changed) p n # undefined Note that the parameter list is merely a placeholder for parallel assignment. This means that if you put an existing variable into that list, it will be changed. Default arguments are not supported. There is an intricate balance in this matter, because blocks are also used for iterators, which remember the previously assigned value. |