Recall how we pass a block to a method:
def dostuff
yield(7)
end
puts dostuff {|x| x + 9}
This code passes the block {|x| x + 9}
to the method
dostuff
which calls the block on 7
Below is an alternative way to accomplish exactly the same thing (try
it!). The
difference, however, is that the block now is now a parameter with a name
code
. Note the syntax of the parameter:
&code
since we are passing the address of the block. Also
note that instead of yield
I now call a method
call
on the code that makes it execute with the parameter
given to call
.
def dostuff(&code)
code.call(7)
end
puts dostuff {|x| x + 9}
This style of passing blocks to a method is very important since it allows you to re-pass the code to method calls inside the method that initially gets the code. This enables recursion with a block being passed as a parameter to the recursive call.
Unfortunately, there does not seem to be a way to pass two code blocks to a function. It is possible to pass another parameter as a lambda-procedure.
Suppose we want to write a class of nested arrays so that we can call methods of Enumerable interface on such arrays. The code below shows the beginning of such an implementation. Your task will be to add more methods to this class.
Enumerable is a module which for the purposes of this problem set is
similar to a Java interface: it gives a list of methods that a class
supports but does not provide an implementation. Note that Ruby does
not mandate that all methods are actually implemented. The
initialize
method stores whatever is passed to it in the
variable @narray
. The intended value is an array of
arbitrary nesting, as shown in the call to new
below. Note that p na
just prints the address of the
object since no to_s
is defined.
class NestedArray
include Enumerable # Enumerable is a module, not a class
# modules are included, not subclassed
def initialize obj
@narray = obj
end
end
# testing the new class
na = NestedArray.new([[6,7],[8],[[9, 6]]])
p na
#p na.each {|z| puts (z + z)} # need to define each for this to work
Now we define an each
method for the NestedArray. The
method is recursive. However, to use recursion, we need to pass the
sub-arrays to the recursive call. The private method
_each
does that, and the public each
just
calls the private one. In Ruby private and public keywords
apply to a group of methods, i.e. all methods defined after
"private" and until "public" are private.
Study the code for the recursive call carefully. Note that
obj
is just a normal array so we can use its
each
method. Likewise you can use other methods of the
sub-arrays in your code so your code would be really not that long.
class NestedArray
# defining each for nested arrays
private
# a private recursive method, iterates over nested arrays
# with the code block in &code
# unfortunately, you can only pass one code parameter
def _each (obj,&code)
obj.each do |x|
if (x.instance_of? Array)
_each(x,&code)
else
code.call(x)
end
end
end
public
# the public each method, calls the recursive one with the
# nested arrays storage as the parameter
def each(&code)
_each(@narray, &code)
end
end
na.each {|y| puts "Here is #{y}"}