On Thursday 28 August 2008 12:12:07 Brian R. wrote:
From Beginning Ruby:
def each_vowel(&code_block)
%w{a e i o u}.each { |vowel| code_block.call(vowel) }
end
each_vowel { |vowel| puts vowel }
First, I’d like to show a simplified version of it. I think this works:
def each_vowel
%w{a e i o u}.each { |vowel| yield vowel }
end
In the simplest form, to define a method that takes a code block, you
can
ignore the block until you need it, and then call it with “yield”. This
will
actually execute faster, but it’s not as flexible.
You can also call ‘block_given?’ to find out if you have a block.
So…
It defines a method that takes a code block (is the & necessary?).
Strictly, no.
What does
it mean to have a method that takes a code block?
ALL methods can take a code block. Most of them don’t do anything with
it. You
can verify this:
“foo”.length {|x| raise “THIS BLOCK SHOULD NEVER BE CALLED!!!” }
So, with that in mind, the &foo says that you’re binding whatever code
block
was passed in to a local variable, so you can do things to it.
%w{a e i o u}.each { |vowel| code_block.call(vowel) }
%w{a e i o u}, of course, translates to [‘a’, ‘e’, ‘i’, ‘o’, ‘u’]
The rest is a simple each loop. You could also do this:
[‘a’, ‘e’, ‘i’, ‘o’, ‘u’].each do |vowel|
puts ‘I got a vowel!’
puts vowel
end
That block runs once for each vowel. To make it simpler, you could
disregard
all the less common vowels, and just use ‘e’:
def each_important_vowel(&code_block)
code_block.call(‘e’)
end
If you’re using it like in your example:
each_vowel {|vowel| puts vowel}
The easiest thing to do is to think of the code block as a function in
its own
right. (It’s not, which is one of the more disappointing things about
Ruby,
but we can pretend that it is.)
So, it’s really more like this:
def my_code_block(vowel)
puts vowel
end
%w{a e i o u}.each {|vowel| my_code_block(vowel) }
If you made it through that, I’d like to justify my claim that yielding
isn’t
as flexible as the &block syntax. I’d say, yield when you can, and use
&block
when you need to.
One example would be stored callbacks. I’m not sure what you’ve done
with
classes and objects, so I’ll simplify this:
before_printing_callbacks = []
def before_printing &block
before_printing_callbacks.push(block)
end
Call it a few times, with various arguments…
Then take a look at what’s in that array.
def print_stuff string
before_printing_callbacks.each do |block|
block.call
end
print string
end