[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Writing a method to handle a code block?

Brian Ross

8/28/2008 5:12:00 PM

[Note: parts of this message were removed to make it a legal post.]

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 }

I am trying to figure out how that works but I'm still having a bit of
trouble. Could someone break it down bit by bit to show what it's doing?

def each_vowel(&code_block)

It defines a method that takes a code block (is the & necessary?). What does
it mean to have a method that takes a code block?

%w{a e i o u}.each { |vowel| code_block.call(vowel) }

Then it takes an array of vowels, which call the each method to pass each
one into the following block through |vowel| as a block argument. The block
arguments are then called by the variable code_block (I don't understand
this).

Brian

6 Answers

Adam Shelly

8/28/2008 5:36:00 PM

0

On 8/28/08, Brian Ross <p.brian.ross@gmail.com> 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 }
>
> I am trying to figure out how that works but I'm still having a bit of
> trouble. Could someone break it down bit by bit to show what it's doing?
>
> def each_vowel(&code_block)
>
> It defines a method that takes a code block (is the & necessary?).

Yes the & is necessary, otherwise when you try to call this method
with `each_vowel {|v|puts v}` you will get an argument error, since
the method will expect a normal object, not a block.

> What does it mean to have a method that takes a code block?

At first approximation you can think of a code block as an anonymous method.
You are writing a method that can take another method as an argument.

>
> %w{a e i o u}.each { |vowel| code_block.call(vowel) }
>
> Then it takes an array of vowels, which call the each method to pass each
> one into the following block through |vowel| as a block argument. The block
> arguments are then called by the variable code_block (I don't understand
> this).

code_block.call(vowel) is calling the method stored in the code_block
variable, and
passing it the argument called vowel. When you call each_vowel like this:

each_vowel {|vowel| puts vowel}

The block with 'puts' is stored as code_block, and run 5 times, once
for each letter in the array:
%w{a e i o u}.each { |vowel| code_block.call(vowel) }

So the end result is that each vowel is printed out.


HTH,
-Adam

Michael Morin

8/28/2008 5:36:00 PM

0

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 }
>
> I am trying to figure out how that works but I'm still having a bit of
> trouble. Could someone break it down bit by bit to show what it's doing?
>
> def each_vowel(&code_block)
>
> It defines a method that takes a code block (is the & necessary?). What does
> it mean to have a method that takes a code block?
>
> %w{a e i o u}.each { |vowel| code_block.call(vowel) }
>
> Then it takes an array of vowels, which call the each method to pass each
> one into the following block through |vowel| as a block argument. The block
> arguments are then called by the variable code_block (I don't understand
> this).
>
> Brian
>

Code (in the form of Proc objects and similar) can be stored in a variable.

>> code = proc { puts "test" }
=> #<Proc:0xb7b03030@(irb):25>
>> code.call
test
=> nil
>>

The &argument to each_vowel is a local variable that stores any block or
closure passed to it using the special method() { syntax }. After that,
calling argument.call is the same as code.call in the previous example.

I got a little turned around in your question, either I'm just not
understanding it or you're using a term wrong. The each method itself
takes a block, the block is everything in the { curly braces }. The
argument to the block is |vowel|, for every vowel in the array, the code
block passed to each is called with that vowel passing it in |vowel|.
That code block then goes an calls the code_block argument, which in
turn contains the code block given when you called each_vowel.

I can see how that explanation gets a little confusing. Two things are
called vowel, there are three things called a "code block," and a few
layers of calls through the code blocks. This example may be simpler.
It duplicated the Fixnum#times method.

>> def this_many_times(n,&block)
>> n.times { block.call }
>> end
=> nil
>> this_many_times(10) { puts "test" }
test
test
test
test
test
test
test
test
test
test
=> 10
>>

--
Michael Morin
Guide to Ruby
http://ruby....
Become an About.com Guide: beaguide.about.com
About.com is part of the New York Times Company

Brian Ross

8/28/2008 7:27:00 PM

0

[Note: parts of this message were removed to make it a legal post.]

On Thu, Aug 28, 2008 at 1:36 PM, Adam Shelly <adam.shelly@gmail.com> wrote:

>
> code_block.call(vowel) is calling the method stored in the code_block
> variable, and
> passing it the argument called vowel. When you call each_vowel like this:
>
> each_vowel {|vowel| puts vowel}
>
> The block with 'puts' is stored as code_block, and run 5 times, once
> for each letter in the array:
> %w{a e i o u}.each { |vowel| code_block.call(vowel) }
>
> So the end result is that each vowel is printed out.
>

Intuitively I'd think that:

each_vowel {|vowel| puts vowel}

would lead to something that looked like:

%w{a e i o u}.each { |vowel| |vowel| puts vowel.call(vowel) }

which is incomprehensible to me. I guess I am trying to really figure out
how it's working so that I can construct my own and really understand it. To
sound like an idiot: I still don't really understand how it's working.

Brian

Brian Ross

8/28/2008 9:40:00 PM

0

[Note: parts of this message were removed to make it a legal post.]

On Thu, Aug 28, 2008 at 3:27 PM, Brian Ross <p.brian.ross@gmail.com> wrote:

> I guess I am trying to really figure out
> how it's working so that I can construct my own and really understand it.
> To
> sound like an idiot: I still don't really understand how it's working.
>

Alternatively, if I just run

puts each_vowel {}

it returns 5 vowels, each on its own line and seems to function the same as:

each_vowel {|vowel| puts vowel}

Maybe my question is, what is the importance of the second |vowel|? Does the
first block argument just get passed to the second block through whichever
block argument is given in the second? Also I'm having trouble with the
documentation for the call method to figure out how it works.

Brian

Adam Shelly

8/29/2008 12:18:00 AM

0

On 8/28/08, Brian Ross <p.brian.ross@gmail.com> wrote:
> On Thu, Aug 28, 2008 at 1:36 PM, Adam Shelly <adam.shelly@gmail.com> wrote:
> >
> > The block with 'puts' is stored as code_block, and run 5 times, once
> > for each letter in the array:
> > %w{a e i o u}.each { |vowel| code_block.call(vowel) }
> >
> > So the end result is that each vowel is printed out.
> >
>
> Intuitively I'd think that:
>
> each_vowel {|vowel| puts vowel}
>
> would lead to something that looked like:
>
> %w{a e i o u}.each { |vowel| |vowel| puts vowel.call(vowel) }
>
> which is incomprehensible to me. I guess I am trying to really figure out
> how it's working so that I can construct my own and really understand it. To
> sound like an idiot: I still don't really understand how it's working.
>
I'm probably not the best explainer... but you are on the right track.
Michael is right that having two things called vowel here can be
confusing. So let's rename the variables - the code will work
exactly the same:

def each_vowel &code_block
%w{a e i o u}.each {|item| code_block.call(item) }
end
each_vowel {|v| puts v}

code_block.call(item) simply executes the block using 'item' in place
of the variable inside the || pipes, so conceptually, this 'expands'
to the following pseudo-code:

%w{a e i o u}.each { |item| {|v=item| puts v}}


> Alternatively, if I just run
> puts each_vowel {}
> it returns 5 vowels, each on its own line and seems to function the same as:
> each_vowel {|vowel| puts vowel}

Something completely different is happening with `puts each_vowel{}`.
Remember that Ruby methods return the result of the last line, which
for each_vowel, is the result of Array.each, which is the array
itself. So after executing an empty block, which does nothing, you
are returning the array and passing that to puts. To see the
difference, compare to :
each_vowel{|v| p v.succ}

-Adam

David Masover

8/29/2008 5:14:00 AM

0

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