On Thursday 28 August 2008 12:12:07 Brian Ross 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