[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

next, retry, break?

MenTaLguY

12/9/2005 8:59:00 PM

Okay, I've got a question.

What's the correct way to implement a custom Enumerable#each which
handles next, retry and break correctly?

For example:

def each
while @current_grob
yield @current_grob.create
@current_grob = @current_grob.next_grob
end
end

How do I make next, retry, and break work as expected?

-mental




5 Answers

gabriele renzi

12/9/2005 9:26:00 PM

0

mental@rydia.net ha scritto:
> Okay, I've got a question.
>
> What's the correct way to implement a custom Enumerable#each which
> handles next, retry and break correctly?
>
> For example:
>
> def each
> while @current_grob
> yield @current_grob.create
> @current_grob = @current_grob.next_grob
> end
> end
>
> How do I make next, retry, and break work as expected?
>
> -mental

don't they do it already?
>> Triple = Struct.new :a, :b, :c do
?> def each
>> yield a
>> yield b
>> yield c
>> end
>> end
=> Triple
>> Triple.new(1,2,3).each do |x|
?> if x == 1
>> next
>> elsif x == 2
>> p "2"
>> break
>> end
>> p x
>> end
"2"
=> nil

MenTaLguY

12/9/2005 9:48:00 PM

0

Quoting mental@rydia.net:

> How do I make next, retry, and break work as expected?

Sorry, s/retry/redo/.

-mental


Jacob Fugal

12/9/2005 10:06:00 PM

0

On 12/9/05, mental@rydia.net <mental@rydia.net> wrote:
> Quoting mental@rydia.net:
>
> > How do I make next, retry, and break work as expected?
>
> Sorry, s/retry/redo/.

Like Gabriele said in the other thread, they seem to already...

$ cat test.rb
lukfugl@falcon:~$ cat test.rb
class MyArray
include Enumerable

def initialize( *ary )
@ary = ary
end

def each
@ary.each { |el| yield el }
end
end

def test( ary, *sequence )
puts "### #{ary.class}, #{sequence.inspect} ###"
ary.each do |el|
puts el
case sequence.shift
when :next then next
when :retry then retry
when :redo then redo
when :break then break
end
end
end

ary1 = [ 1, 2, 3, 4, 5 ]
ary2 = MyArray.new( *ary1 )

test( ary1, :next, :retry, :next, :next, :redo, :redo, :break )
test( ary2, :next, :retry, :next, :next, :redo, :redo, :break )

$ ruby test.rb
### Array, [:next, :retry, :next, :next, :redo, :redo, :break] ###
1
2
1
2
3
3
3
### MyArray, [:next, :retry, :next, :next, :redo, :redo, :break] ###
1
2
1
2
3
3
3

Jacob Fugal


Yukihiro Matsumoto

12/10/2005 2:30:00 AM

0

Hi,

In message "Re: next, retry, break?"
on Sat, 10 Dec 2005 05:59:29 +0900, mental@rydia.net writes:

|Okay, I've got a question.
|
|What's the correct way to implement a custom Enumerable#each which
|handles next, retry and break correctly?

Just do it normally. You don't have to do nothing for them.

|For example:
|
| def each
| while @current_grob
| yield @current_grob.create
| @current_grob = @current_grob.next_grob
| end
| end
|
|How do I make next, retry, and break work as expected?

If you want "redo" to work, you have to initialize your @current_grob
at the beginning of the iterating method. Since many expect "each" to
enumerate all the values in the collection, initializing at the top is
a good thing in general.

matz.


MenTaLguY

12/10/2005 5:02:00 AM

0

On Sat, 2005-12-10 at 11:29 +0900, Yukihiro Matsumoto wrote:

> If you want "redo" to work, you have to initialize your @current_grob
> at the beginning of the iterating method. Since many expect "each" to
> enumerate all the values in the collection, initializing at the top is
> a good thing in general.

Thanks...

This is for a stream class, so it would be a "consuming" each like
IO#each. In that case not initializing is okay (it should behave just
like IO#each does). The problem was that I was not advancing the stream
pointer until after the yield -- solved with 'ensure'.

Just to be sure I understand correctly now:

redo: jumps to the start of the block

next: jumps to the end of the block
using the given value (or nil)
as the block's result

retry: unwinds the stack to the call
site of the "closest" yielding
method, calling it again with
the same arguments

break: unwinds the stack to the call
site of the "closest" yielding
method, using the given value
(or nil) as the method's result

Is that right?

If so, what if I want retry or break to unwind further (e.g. because I
am implementing one iterator in terms of another)?

-mental