Skip to content

Commit

Permalink
Add Iterator#auto_rewind? and auto_rewind=
Browse files Browse the repository at this point in the history
If Iterator#auto_rewind? returns true, the iterator is rewinded after Iterator#each
automatically. Otherwise it returns false, the iterator is not rewinded.

Iterator#auto_rewind? default value is true, it is just breaking change.

This feature motivation is to be able to apply Enumerable algorithm to
Iterator. In current implementation, `Iterator#each` works only first
time.
  • Loading branch information
makenowjust committed Dec 29, 2016
1 parent 7a0676b commit 9740817
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 0 deletions.
25 changes: 25 additions & 0 deletions spec/std/iterator_spec.cr
Expand Up @@ -699,4 +699,29 @@ describe Iterator do
iter.rewind.to_a.should eq([1, 2, 2, 3, 3])
end
end

describe "auto_rewind?" do
it "default value is true" do
[1, 2, 3].each.auto_rewind?.should be_true
end

it "rewinds after each" do
iter = [1, 2, 3].each
iter.to_a.should eq([1, 2, 3])
iter.to_a.should eq([1, 2, 3])
end

it "doesn't rewind after each if auto_rewind? is false" do
iter = [1, 2, 3].each
iter.auto_rewind = false
iter.to_a.should eq([1, 2, 3])
iter.to_a.should eq([] of Int32)
end

it "inherits value" do
iter = [1, 2, 3].each
iter.auto_rewind = false
iter.first(2).auto_rewind?.should be_false
end
end
end
34 changes: 34 additions & 0 deletions src/iterator.cr
Expand Up @@ -91,6 +91,12 @@ module Iterator(T)
self
end

# :nodoc:
def auto_rewind?
return @iterator.auto_rewind? if @auto_rewind.nil?
!!@auto_rewind
end

# Invokes `next` on the wrapped iterator and returns `stop` if
# the given value was a Stop. Otherwise, returns the value.
macro wrapped_next
Expand Down Expand Up @@ -151,6 +157,32 @@ module Iterator(T)
# Rewinds the iterator to its original state.
abstract def rewind

# Whether to rewind after `each` and some `Enumerable` methods.
#
# Default value is `true`, so the iterator rewinds after `each` automatically.
#
# ```
# iter = (1..2).each
#
# iter.auto_rewind? # => true
# iter.size # => 2
# iter.size # => 2
#
# iter.auto_rewind = false
# iter.size # => 2
# iter.size # => 0
# ```
def auto_rewind?
@auto_rewind.nil? ? true : @auto_rewind.not_nil!
end

# :ditto:
def auto_rewind=(value : Bool)
@auto_rewind = value
end

@auto_rewind : Bool?

# Returns an iterator that returns elements from the original iterator until
# it is exhausted and then returns the elements of the second iterator.
#
Expand Down Expand Up @@ -383,6 +415,7 @@ module Iterator(T)
break if value.is_a?(Stop)
yield value
end
rewind if auto_rewind?
end

# Returns an iterator that then returns slices of n elements of the initial
Expand Down Expand Up @@ -424,6 +457,7 @@ module Iterator(T)

private struct Flatten(I, T)
include Iterator(T)
include IteratorWrapper

@iterator : I
@stopped : Array(I)
Expand Down

0 comments on commit 9740817

Please sign in to comment.