Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to stop iteration in a Enumerator::Lazy method?
    primarykey
    data
    text
    <p>I am trying to implement a <code>take_until</code> method for Ruby 2's Enumerator::Lazy class. It should work similar to <code>take_while</code> but instead stop iteration when the yielded block returns true. The result should include the item where the yielded block matches.</p> <p>My question is how do I signal that the end of the iteration is reached? When using regular Enumerators you can raise the StopIteration error in an each method to signal the end of the iterator. But that doesn't seem to work for lazy enum's:</p> <pre><code>class Enumerator::Lazy def take_until Lazy.new(self) do |yielder, *values| yielder &lt;&lt; values raise StopIteration if yield *values end end end (1..Float::INFINITY).lazy.take_until{ |i| i == 5 }.force </code></pre> <p>I also tried to break out of the block to no effect. <a href="http://ruby-doc.org/core-2.0.0/Enumerator/Lazy.html" rel="nofollow">The documentation for Enumerator::Lazy</a> doesn't seem to help either.</p> <p><strong>Why using <code>take_while</code> is not a valid option.</strong></p> <p>The main problem with take_while is that by its nature it will attempt to evaluate one more item than you need. In my application the Enumerator doesn't yield numbers, but messages fetched over the network. Trying to evaluate a message that is not there (yet?) is a blocking action which is highly undesirable. This is illustrated by the following contrived example:</p> <pre><code>enum = Enumerator.new do |y| 5.times do |i| y &lt;&lt; i end sleep end enum.lazy.take_while{ |i| i &lt; 5 }.force </code></pre> <p>To receive the first five items from this enumerator you will need to evaluate the sixth result. This is not as lazy as it could be. In my use case this is undesirable since the process would block.</p> <p><strong>Providing a pure Ruby implementation of <code>take</code> for Enumerator::Lazy</strong></p> <p>The standard library includes a <code>take</code> method that does something similar to what I want. It doesn't use a block as a condition but a number, but it does break out of the the iteration once that number is reached instead of evaluating one more item. Following on from the example above:</p> <pre><code>enum.lazy.take(5).force </code></pre> <p>This does not get to the 6th item and so does not block. Problem is the version in the standard library is implemented in C and I can't seem to figure out how this could be implemented in pure Ruby. A ruby implementation of that method would be an acceptable answer.</p> <p>Thanks in advance!</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload