[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Re: how to add an iterator to a class?

7stud 7stud

9/24/2007 4:23:00 AM

Mike Steiner wrote:
>
> So my question is: How do I replace GetArray with something more
> elegant,
> that gives MyArray a method named .each that I can call directly?
>

each() is an "iterator". An iterator is a method that uses a "yield
statement". A yield statement acts similar to a method call, and looks
like this:

yield some_val

yield calls the block and sends it the argument specified to the right
of 'yield'. The method that contains the yield statement, i.e. each(),
halts and waits for the block to finish executing, and then execution
continues in the method. That interaction is very similar to a method
that calls another method:

def greet
sleep(2)
puts "hello"
sleep(5)
end

def start
greet

x = 10
puts x
end

start

If you run that code, you'll see that the method start() waits for
greet() to finish executing before it outputs 10. yield works
similarly: execution does not continue in the method that contains the
yield statement, e.g. each(), until the block that the yield statement
called finishes executing.

So, you need to define a method called each, and inside each you are
going to use a yield statement that sends values to a block. What
values? The values are the elements of your array. Since you are
generally going to need to yield more than one value, i.e. your array
will have more than one element in it, you can put your yield statement
inside a loop:


class MyArray
def initialize
@a = Array.new
end
def push( item )
@a.push( item )
end

def each
count = 0
while elmt = @a[count]
yield elmt
count += 1
end
end

end

arr = MyArray.new
arr.push(1)
arr.push(2)
arr.push(3)

arr.each{|elmt| puts elmt +2}
--
Posted via http://www.ruby-....

2 Answers

7stud 7stud

9/24/2007 4:52:00 AM

0

Here's a super simple example of an iterator:

def test
yield
yield
yield

puts "all done in test"
end


test {puts "hello"; sleep(2)}

In that example, test() calls the block but does not send it any
arguments--just like you can call a method and not send it any
arguments. Note that the block is not defined to accept any arguments.

When the first yield statement is encountered, the block is called. How
does the yield statement know what block to call? yield calls the block
specified to the right of the test method call. What if you call test
and don't specify a block?

r4test.rb:2:in `test': no block given (LocalJumpError)
from r4test.rb:9

After the first yield statement in test is encountered, execution halts
at the point of the first yield statement until the block outputs
"hello" and finishes sleeping. Then execution continues in test. The
next line in test is another yield statement, so the block is called
again, and execution halts in test until the block finishes. The same
thing happens a third time. Finally, test outputs its terminating
message.

Blocks can also return values to a yield statement--just like a method
can return a value to a method call, e.g.


def get_calc
10 * 2
end

def do_homework
answer = get_calc #return value replaces the method call in the
code
puts answer
end

do_homework


Here is how a block returns a value to a yield statement:

def test
result = yield 10 #catch the value returned by the block in a
variable

puts result
end


test {10 * 2}
--
Posted via http://www.ruby-....

7stud 7stud

9/24/2007 4:59:00 AM

0

7stud -- wrote:
>
> Here is how a block returns a value to a yield statement:
>
> def test
> result = yield 10 #catch the value returned by the block in a
> variable
>
> puts result
> end
>
>
> test {10 * 2}

Whoops. That should be:

def test
result = yield 10

puts result
end


test {|num| num * 2} #block is defined to accept an arg

--
Posted via http://www.ruby-....