Module: Stream

Includes:
Enumerable
Included in:
BasicStream
Defined in:
lib/stream.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

Instance Method Summary collapse

Instance Method Details

#+(other) ⇒ Object

Create a Stream::ConcatenatedStream by concatenatating the receiver and other_stream

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


716
717
718
# File 'lib/stream.rb', line 716

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)


22
23
24
# File 'lib/stream.rb', line 22

def at_beginning?
  raise NotImplementedError
end

#at_end?Boolean

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

Returns:

  • (Boolean)

Raises:

  • (NotImplementedError)


17
18
19
# File 'lib/stream.rb', line 17

def at_end?
  raise NotImplementedError
end

#backwardObject

Move backward one position. Returns the source of current_edge. Raises Stream::EndOfStreamException if at_beginning? is true.



36
37
38
39
40
# File 'lib/stream.rb', line 36

def backward
  raise EndOfStreamException if at_beginning?

  basic_backward
end

#collect(&mapping) ⇒ Object

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.



690
691
692
# File 'lib/stream.rb', line 690

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

#concatenateObject

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



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

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]


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

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.



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

def create_stream
  self
end

#currentObject

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



102
103
104
# File 'lib/stream.rb', line 102

def current
  at_beginning? ? self : basic_current
end

#current_edgeObject

Returns the array [#current,#peek].



113
114
115
# File 'lib/stream.rb', line 113

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.



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

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)


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

def empty?
  at_end? and at_beginning?
end

#filtered(&block) ⇒ Object

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



678
679
680
# File 'lib/stream.rb', line 678

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.



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

def first
  set_to_begin
  forward
end

#forwardObject

Move forward one position. Returns the target of current_edge. Raises Stream::EndOfStreamException if at_end? is true.



28
29
30
31
32
# File 'lib/stream.rb', line 28

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.



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

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.



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

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

#move_backward_untilObject

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



92
93
94
95
96
97
98
# File 'lib/stream.rb', line 92

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

#move_forward_untilObject

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.



82
83
84
85
86
87
88
# File 'lib/stream.rb', line 82

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.



108
109
110
# File 'lib/stream.rb', line 108

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]


732
733
734
735
736
737
738
# File 'lib/stream.rb', line 732

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.



746
747
748
# File 'lib/stream.rb', line 746

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

#reverseObject

Create a Stream::ReversedStream wrapper on self.



683
684
685
# File 'lib/stream.rb', line 683

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.



44
45
46
# File 'lib/stream.rb', line 44

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.



50
51
52
# File 'lib/stream.rb', line 50

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.



152
153
154
# File 'lib/stream.rb', line 152

def unwrapped
  self
end