Module: Stream

Includes:
Enumerable
Included in:
BasicStream
Defined in:
lib/stream.rb,
lib/stream/version.rb

Overview

Module Stream defines an interface for an external Iterator which can move forward and backwards. See README for more information.

The functionality is similar to Smalltalk’s ReadStream.

Defined Under Namespace

Classes: BasicStream, CollectionStream, ConcatenatedStream, EmptyStream, EndOfStreamException, FilteredStream, ImplicitStream, IntervalStream, MappedStream, ReversedStream, WrappedStream

Constant Summary collapse

VERSION =
'0.5.6'

Instance Method Summary collapse

Instance Method Details

#+(other) ⇒ ConcatenatedStream

Create a Stream::ConcatenatedStream by concatenating the receiver and other_stream.

Parameters:

  • other (Stream)

    the stream to append

Returns:

  • (ConcatenatedStream)

    (%w(a b c).create_stream + [4,5].create_stream).to_a

    > [“a”, “b”, “c”, 4, 5]



734
735
736
# File 'lib/stream.rb', line 734

def +(other)
  [self, other].create_stream.concatenate
end

#at_beginning?Boolean

Returns false if the next #backward will return an element.

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


24
25
26
# File 'lib/stream.rb', line 24

def at_beginning?
  raise NotImplementedError
end

#at_end?Boolean

Returns false if the next #forward will return an element.

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


19
20
21
# File 'lib/stream.rb', line 19

def at_end?
  raise NotImplementedError
end

#backwardObject

Move backward one position. Returns the source of current_edge.

Returns:

  • (Object)

    the previous element

Raises:



40
41
42
43
44
# File 'lib/stream.rb', line 40

def backward
  raise EndOfStreamException if at_beginning?

  basic_backward
end

#collect {|element| ... } ⇒ MappedStream

Create a Stream::MappedStream wrapper on self. Instead of returning the stream element on each move, the value of calling mapping is returned instead. See Stream::MappedStream for examples.

Yields:

  • (element)

    mapping block applied to each element

Returns:



706
707
708
# File 'lib/stream.rb', line 706

def collect(&mapping)
  MappedStream.new(self, &mapping)
end

#concatenateObject

Create a Stream::ConcatenatedStream on self, which must be a stream of streams.



712
713
714
# File 'lib/stream.rb', line 712

def concatenate
  ConcatenatedStream.new self
end

#concatenate_collected(&mapping) ⇒ Object

Create a Stream::ConcatenatedStream, concatenated from streams build with the block for each element of self:

s = [1, 2, 3].create_stream.concatenate_collected { |i|
  [i,-i].create_stream
}.
s.to_a ==> [1, -1, 2, -2, 3, -3]


723
724
725
# File 'lib/stream.rb', line 723

def concatenate_collected(&mapping)
  collect(&mapping).concatenate
end

#create_streamObject

create_stream is used for each Enumerable to create a stream for it. A Stream as an Enumerable returns itself.



154
155
156
# File 'lib/stream.rb', line 154

def create_stream
  self
end

#currentObject

Returns the element returned by the last call of #forward. If at_beginning? is true self is returned.



110
111
112
# File 'lib/stream.rb', line 110

def current
  at_beginning? ? self : basic_current
end

#current_edgeObject

Returns the array [#current,#peek].



121
122
123
# File 'lib/stream.rb', line 121

def current_edge
  [current, peek]
end

#eachObject

Implements the standard iterator used by module Enumerable, by calling set_to_begin and basic_forward until at_end? is true.



147
148
149
150
# File 'lib/stream.rb', line 147

def each
  set_to_begin
  yield basic_forward until at_end?
end

#empty?Boolean

Returns true if the stream is empty which is equivalent to at_end? and at_beginning? both being true.

Returns:

  • (Boolean)


141
142
143
# File 'lib/stream.rb', line 141

def empty?
  at_end? and at_beginning?
end

#filtered {|element| ... } ⇒ FilteredStream

Return a Stream::FilteredStream which iterates over all my elements satisfying the condition specified by the block.

Yields:

  • (element)

    filter predicate

Returns:



692
693
694
# File 'lib/stream.rb', line 692

def filtered(&block)
  FilteredStream.new(self, &block)
end

#firstObject

Returns the first element of the stream. This is accomplished by calling set_to_begin and #forward, which means a state change.



127
128
129
130
# File 'lib/stream.rb', line 127

def first
  set_to_begin
  forward
end

#forwardObject

Move forward one position. Returns the target of current_edge.

Returns:

  • (Object)

    the next element

Raises:



31
32
33
34
35
# File 'lib/stream.rb', line 31

def forward
  raise EndOfStreamException if at_end?

  basic_forward
end

#lastObject

Returns the last element of the stream. This is accomplished by calling set_to_begin and #backward, which means a state change.



134
135
136
137
# File 'lib/stream.rb', line 134

def last
  set_to_end
  backward
end

#modify(&block) ⇒ Object

Create a Stream::ImplicitStream which wraps the receiver stream by modifying one or more basic methods of the receiver. As an example the method remove_first uses #modify to create an ImplicitStream which filters the first element away.



742
743
744
# File 'lib/stream.rb', line 742

def modify(&block)
  ImplicitStream.new(self, &block)
end

#move_backward_until {|element| ... } ⇒ Object?

Move backward until the boolean block is not false and returns the element found. Returns nil if no object matches.

Yields:

  • (element)

    each element in backward direction

Returns:

  • (Object, nil)

    the first matching element, or nil



100
101
102
103
104
105
106
# File 'lib/stream.rb', line 100

def move_backward_until
  until at_beginning?
    element = basic_backward
    return element if yield(element)
  end
  nil
end

#move_forward_until {|element| ... } ⇒ Object?

Move forward until the boolean block is not false and returns the element found. Returns nil if no object matches.

This is similar to #detect, but starts the search from the current position. #detect, which is inherited from Enumerable uses #each, which implicitly calls #set_to_begin.

Yields:

  • (element)

    each element in forward direction

Returns:

  • (Object, nil)

    the first matching element, or nil



88
89
90
91
92
93
94
# File 'lib/stream.rb', line 88

def move_forward_until
  until at_end?
    element = basic_forward
    return element if yield(element)
  end
  nil
end

#peekObject

Returns the element returned by the last call of #backward. If at_end? is true self is returned.



116
117
118
# File 'lib/stream.rb', line 116

def peek
  at_end? ? self : basic_peek
end

#remove_firstObject

Returns a Stream::ImplicitStream wrapping a Stream::FilteredStream, which eliminates the first element of the receiver.

(1..3).create_stream.remove_first.to_a ==> [2,3]


750
751
752
753
754
755
756
# File 'lib/stream.rb', line 750

def remove_first
  i = 0
  filter = filtered { i += 1; i > 1 }
  filter.modify do |s|
    s.set_to_begin_proc = proc { filter.set_to_begin; i = 0 }
  end
end

#remove_lastObject

Returns a Stream which eliminates the first element of the receiver.

(1..3).create_stream.remove_last.to_a ==> [1,2]

Take a look at the source. The implementation is inefficient but elegant.



764
765
766
# File 'lib/stream.rb', line 764

def remove_last
  reverse.remove_first.reverse # I like this one
end

#reverseObject

Create a Stream::ReversedStream wrapper on self.



697
698
699
# File 'lib/stream.rb', line 697

def reverse
  ReversedStream.new self
end

#set_to_beginObject

Position the stream before its first element, i.e. the next #forward will return the first element.



48
49
50
# File 'lib/stream.rb', line 48

def set_to_begin
  basic_backward until at_beginning?
end

#set_to_endObject

Position the stream behind its last element, i.e. the next #backward will return the last element.



54
55
56
# File 'lib/stream.rb', line 54

def set_to_end
  basic_forward until at_end?
end

#unwrappedObject

A Stream::WrappedStream should return the wrapped stream unwrapped. If the stream is not a wrapper around another stream it simply returns itself.



160
161
162
# File 'lib/stream.rb', line 160

def unwrapped
  self
end