stream 0.5.5 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01b456afc318137cc9291dd8f7ec664dcc6370225c1fb8cf0a223794d1a18cb7
4
- data.tar.gz: 19824c0406a4e7b253aa682db312f89fea8a1d0c9bd3a3513d2951ffdc3126b2
3
+ metadata.gz: 1a1851af382462908d89f216b7b68c4e12a471bf66c8b95f68a8770bce964d5c
4
+ data.tar.gz: cae0261438776cd1b62c70686ec6a9983b45ecabc2476b37d88b9c6a43868272
5
5
  SHA512:
6
- metadata.gz: c3fdb6526fabfd8ff52d8ea5b195f83a5644515f99444ab589d389ffb08365dea6de40e69e84bd8c9c93155cabcee3fe0a0e2ef0dd1a96403a7dc2035bf80be2
7
- data.tar.gz: 95c2179dca08a24eb24f7aa811be95b4bd1c17ea57e41d218ada55783933cdac30eb958ca61a42294bc719097d98327fe846248bf7f88b47272776fbfcddff07
6
+ metadata.gz: ae065f33f579bde4192dfb75f4fc6dd57f20f40708c1614eb236364e4cf61b5848e11f2fa00e29c54f6b63af37135d8c5dd3782336d02c43b50d18742b29d121
7
+ data.tar.gz: 673f7510857e58e5f31b07edf304cce64a1f999f5433ba7c4305dd0ae4eb27aeb01135ab5be314155b22053a80915e91bfc3451e3860a74da710137bbfedc4ef
data/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## [0.5.6](https://github.com/monora/stream/compare/v0.5.5...v0.5.6) (2026-05-10)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * convert README to Markdown, add copyright, fix badges, clean up ([#16](https://github.com/monora/stream/issues/16)) ([9716019](https://github.com/monora/stream/commit/97160196497cb568ae2558b03d6ac4fc0e267a65))
data/Gemfile.lock CHANGED
@@ -1,23 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stream (0.5.5)
4
+ stream (0.5.6)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- power_assert (2.0.1)
10
- psych (4.0.4)
11
- stringio
12
- rake (13.0.6)
13
- rdoc (6.4.0)
14
- psych (>= 4.0.0)
15
- stringio (3.0.2)
16
- test-unit (3.5.3)
9
+ power_assert (3.0.1)
10
+ rake (13.4.2)
11
+ test-unit (3.7.7)
17
12
  power_assert
18
- webrick (1.7.0)
19
- yard (0.9.28)
20
- webrick (~> 1.7.0)
21
13
 
22
14
  PLATFORMS
23
15
  ruby
@@ -25,10 +17,8 @@ PLATFORMS
25
17
 
26
18
  DEPENDENCIES
27
19
  rake
28
- rdoc
29
20
  stream!
30
21
  test-unit
31
- yard
32
22
 
33
23
  BUNDLED WITH
34
- 2.3.8
24
+ 2.5.22
data/LICENSE CHANGED
@@ -1,3 +1,7 @@
1
+ Copyright (c) 2002-2026 Horst Duchene <monora@gmail.com>
2
+
3
+ stream is distributed under the same license as Ruby.
4
+
1
5
  Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
2
6
  You can redistribute it and/or modify it under either the terms of the
3
7
  2-clause BSDL (see the file BSDL), or the conditions below:
data/README.md ADDED
@@ -0,0 +1,209 @@
1
+ [![Build Status](https://github.com/monora/stream/actions/workflows/ruby.yml/badge.svg)](https://github.com/monora/stream/actions/workflows/ruby.yml)
2
+ [![Version](https://img.shields.io/gem/v/stream.svg)](https://rubygems.org/gems/stream)
3
+
4
+ # Extended External Iterators (forward and backward)
5
+
6
+ ## Description
7
+
8
+ Module `Stream` defines an interface for [external
9
+ iterators](https://wiki.c2.com/?ExternalIterator). A stream can be seen
10
+ as an iterator on a sequence of objects `x1,...,xn`. The state of the
11
+ stream is uniquely determined by the following methods:
12
+
13
+ * `at_beginning?`
14
+ * `at_end?`
15
+ * `current`
16
+ * `peek`
17
+
18
+ State changes are done with the following operations:
19
+
20
+ * `set_to_begin`
21
+ * `set_to_end`
22
+ * `forward`
23
+ * `backward`
24
+
25
+ With the help of the method `current_edge` the state of a stream `s` can be
26
+ exactly defined
27
+
28
+ ```
29
+ s.current_edge == [s.current, s.peek]
30
+ ```
31
+
32
+ If `s` a stream on `[x1,...,xn]`. Consider the edges `[xi,xi+1]` i=1,...,n
33
+ and `[x0,x1]` and `[xn,xn+1]` (x0 and xn+1 are helper elements to define
34
+ the boundary conditions). Then if `s` is non empty, the following
35
+ conditions must be true:
36
+
37
+ ```
38
+ s.at_beginning? <=> s.current_edge == [x0,x1]
39
+ s.at_end? <=> s.current_edge == [xn,xn+1]
40
+ s.empty? <=> s.at_beginning? && s.at_end? <=> s.current_edge == [x0,x1] <=> n = 0
41
+ s.set_to_end => s.at_end?
42
+ s.set_to_begin => s.at_beginning?
43
+ ```
44
+
45
+ If `0 <= i < n` and `s.current_edge == [xi, xi+1]`, then:
46
+
47
+ ```
48
+ [s.forward, s.current_edge] == [xi+1, [xi+1, xi+2]]
49
+ ```
50
+
51
+ If `1 <= i < n` and `s.current_edge == [xi, xi+1]`, then:
52
+
53
+ ```
54
+ [s.backward, s.current_edge] == [xi, [xi-1, xi]]
55
+ ```
56
+
57
+ The result of `peek` is the same as of `forward` without changing state. The result of
58
+ `current` is the same as of `backward` without changing state.
59
+
60
+ Module `Stream` includes `Enumerable` implementing `each` in the obvious way.
61
+
62
+ Not every stream needs to implement `backward` and `at_beginning?`
63
+ thus being not reversable. If they are reversable `peek` can easily be
64
+ implemented using `forward` and `backward`, as is done in module
65
+ `Stream`. If a stream is not reversable all derived streams provided
66
+ by the stream module (filter, mapping, concatenation) can be used
67
+ anyway. Explicit or implicit (via `peek` or `current`) uses of `backward`
68
+ would throw a `NotImplementedError`.
69
+
70
+ Classes implementing the stream interface must implement the following
71
+ methods:
72
+
73
+ * `basic_forward`
74
+ * `basic_backward`
75
+ * `at_end?`
76
+ * `at_beginning?`
77
+
78
+ The methods `set_to_end` and `set_to_begin` are by default implemented as:
79
+
80
+ ```
81
+ set_to_end : until at_end?; do basic_forward end
82
+ set_to_begin : until at_beginning?; do basic_backward end
83
+ ```
84
+
85
+ The methods `forward` and `backward` are by default implemented as:
86
+
87
+ ```
88
+ forward: raise EndOfStreamException if at_end?; basic_forward.
89
+ backward: raise EndOfStreamException if at_beginning?; basic_backward
90
+ ```
91
+
92
+ Thus subclasses must only implement **four** methods. Efficiency sometimes
93
+ demands better implementations.
94
+
95
+ There are several concrete classes implementing the stream interface:
96
+
97
+ * `Stream::EmptyStream` (boring)
98
+ * `Stream::CollectionStream` created by the method `Array#create_stream`
99
+ * `Stream::FilteredStream` created by the method `Stream#filtered`
100
+ * `Stream::ReversedStream` created by the method `Stream#reverse`
101
+ * `Stream::ConcatenatedStream` created by the method `Stream#concatenate`
102
+ * `Stream::ImplicitStream` using closures for the basic methods to implement
103
+
104
+ ## Installation
105
+
106
+ ```bash
107
+ gem install stream
108
+ ```
109
+
110
+ or download the latest sources from the git repository
111
+ <https://github.com/monora/stream>.
112
+
113
+ ## Examples
114
+
115
+ ### Iterate over three streams
116
+
117
+ ```ruby
118
+ g = ('a'..'f').create_stream
119
+ h = (1..10).create_stream
120
+ i = (10..20).create_stream
121
+
122
+ until g.at_end? || h.at_end? || i.at_end?
123
+ p [g.forward, h.forward, i.forward]
124
+ end
125
+ ```
126
+
127
+ Output:
128
+
129
+ ```
130
+ ["a", 1, 10]
131
+ ["b", 2, 11]
132
+ ["c", 3, 12]
133
+ ["d", 4, 13]
134
+ ["e", 5, 14]
135
+ ["f", 6, 15]
136
+ ```
137
+
138
+ ### Concatenate file streams
139
+
140
+ ```ruby
141
+ def filestream fname
142
+ Stream::ImplicitStream.new { |s|
143
+ f = open(fname)
144
+ s.at_end_proc = proc {f.eof?}
145
+ s.forward_proc = proc {f.readline}
146
+ # Need not implement backward moving to use the framework
147
+ }
148
+ end
149
+
150
+ (filestream("/etc/passwd") + ('a'..'f').create_stream + filestream("/etc/group")).each do |l|
151
+ puts l
152
+ end
153
+ ```
154
+
155
+ ### Two filtered collection streams concatenated and reversed
156
+
157
+ ```ruby
158
+ def newstream; (1..6).create_stream; end
159
+ s = newstream.filtered { |x| x % 2 == 0 } + newstream.filtered { |x| x % 2 != 0 }
160
+ s = s.reverse
161
+ puts "Contents : #{s.to_a.join ' '}"
162
+ puts "At end? : #{s.at_end?}"
163
+ puts "At beginning? : #{s.at_beginning?}"
164
+ puts "2xBackwards : #{s.backward} #{s.backward}"
165
+ puts "Forward : #{s.forward}"
166
+ puts "Peek : #{s.peek}"
167
+ puts "Current : #{s.current}"
168
+ puts "set_to_begin : Peek=#{s.set_to_begin;s.peek}"
169
+ ```
170
+
171
+ Output:
172
+
173
+ ```
174
+ Contents : 5 3 1 6 4 2
175
+ At end? : true
176
+ At beginning? : false
177
+ 2xBackwards : 2 4
178
+ Forward : 4
179
+ Peek : 2
180
+ Current : 4
181
+ set_to_begin : Peek=5
182
+ ```
183
+
184
+ ### An infinite stream (do not use `set_to_end`!)
185
+
186
+ ```ruby
187
+ def randomStream
188
+ Stream::ImplicitStream.new { |s|
189
+ s.set_to_begin_proc = proc {srand 1234}
190
+ s.at_end_proc = proc {false}
191
+ s.forward_proc = proc {rand}
192
+ }
193
+ end
194
+ s = randomStream.filtered { |x| x >= 0.5 }.collect { |x| sprintf("%5.2f",x*100) }
195
+ puts "5 random numbers: #{(1..5).collect {|x| s.forward}}\n"
196
+ ```
197
+
198
+ Output:
199
+
200
+ ```
201
+ 5 random numbers: ["62.21", "78.54", "78.00", "80.19", "95.81"]
202
+ ```
203
+
204
+ ## Copying
205
+
206
+ stream is Copyright (c) 2002-2026 by Horst Duchene.
207
+
208
+ It is free software, and may be redistributed under the terms specified
209
+ in the [LICENSE](LICENSE) file.
data/Rakefile CHANGED
@@ -1,25 +1,12 @@
1
1
  # Rakefile for stream -*- ruby -*-
2
2
 
3
- require 'rubygems'
4
3
  require 'bundler/setup'
5
- require 'rubygems/package_task'
6
4
 
7
5
  require 'rake/testtask'
8
- require 'rake/clean'
9
- require 'yard'
10
-
11
- $:.unshift File.join(File.dirname(__FILE__), 'lib')
12
- require 'stream' # require module to STREAM_VERSION
13
-
14
- SRC_RB = FileList['lib/*.rb']
15
-
16
- # The default task is run if rake is given no explicit arguments.
17
6
 
18
7
  desc "Default Task"
19
8
  task :default => :test
20
9
 
21
- # Define a test task.
22
-
23
10
  Rake::TestTask.new do |t|
24
11
  t.libs << 'test'
25
12
  t.pattern = 'test/test*.rb'
@@ -28,23 +15,4 @@ end
28
15
 
29
16
  task :test
30
17
 
31
- # Define a test that will run all the test targets.
32
- desc "Run all test targets"
33
- task :testall => [:test ]
34
-
35
- # Git tagging
36
-
37
- desc "Commit all changes as a new version commit. Tag the commit with v<version> tag"
38
- task :tag do
39
- puts "Committing and tagging version #{STREAM_VERSION}"
40
- `git commit -am 'Version #{STREAM_VERSION}'`
41
- `git tag 'v#{STREAM_VERSION}'`
42
- end
43
-
44
- # Documentation
45
-
46
- YARD::Rake::YardocTask.new
47
-
48
- # Tasks for building and installing Stream gem.
49
-
50
18
  Bundler::GemHelper.install_tasks
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stream
4
+ VERSION = '0.5.6'
5
+ end
data/lib/stream.rb CHANGED
@@ -1,4 +1,6 @@
1
- STREAM_VERSION = '0.5.5'.freeze
1
+ # frozen_string_literal: true
2
+
3
+ require 'stream/version'
2
4
 
3
5
  ##
4
6
  # Module Stream defines an interface for an external Iterator which
@@ -24,15 +26,17 @@ module Stream
24
26
  end
25
27
 
26
28
  # Move forward one position. Returns the _target_ of current_edge.
27
- # Raises Stream::EndOfStreamException if at_end? is true.
29
+ # @raise [EndOfStreamException] if at_end? is true
30
+ # @return [Object] the next element
28
31
  def forward
29
32
  raise EndOfStreamException if at_end?
30
33
 
31
34
  basic_forward
32
35
  end
33
36
 
34
- # Move backward one position. Returns the _source_ of current_edge. Raises
35
- # Stream::EndOfStreamException if at_beginning? is true.
37
+ # Move backward one position. Returns the _source_ of current_edge.
38
+ # @raise [EndOfStreamException] if at_beginning? is true
39
+ # @return [Object] the previous element
36
40
  def backward
37
41
  raise EndOfStreamException if at_beginning?
38
42
 
@@ -79,6 +83,8 @@ module Stream
79
83
  # This is similar to #detect, but starts the search from the
80
84
  # current position. #detect, which is inherited from Enumerable uses
81
85
  # #each, which implicitly calls #set_to_begin.
86
+ # @yield [element] each element in forward direction
87
+ # @return [Object, nil] the first matching element, or nil
82
88
  def move_forward_until
83
89
  until at_end?
84
90
  element = basic_forward
@@ -89,6 +95,8 @@ module Stream
89
95
 
90
96
  # Move backward until the boolean block is not false and returns the element
91
97
  # found. Returns nil if no object matches.
98
+ # @yield [element] each element in backward direction
99
+ # @return [Object, nil] the first matching element, or nil
92
100
  def move_backward_until
93
101
  until at_beginning?
94
102
  element = basic_backward
@@ -192,6 +200,7 @@ module Stream
192
200
  attr_reader :pos
193
201
 
194
202
  # Creates a new CollectionStream for the indexable sequence _seq_.
203
+ # @param seq [Array] an integer-indexed collection
195
204
  def initialize(seq)
196
205
  @seq = seq
197
206
  set_to_begin
@@ -252,6 +261,7 @@ module Stream
252
261
 
253
262
  # Create a new IntervalStream with upper bound _stop_. stop - 1 is the last
254
263
  # element. By default _stop_ is zero which means that the stream is empty.
264
+ # @param stop [Integer] exclusive upper bound; stream yields 0..stop-1
255
265
  def initialize(stop = 0)
256
266
  @stop = stop - 1
257
267
  set_to_begin
@@ -617,6 +627,8 @@ module Stream
617
627
  #
618
628
  # If a block is given to new, than it is called with the new ImplicitStream
619
629
  # stream as parameter letting the client overwriting the default blocks.
630
+ # @param other_stream [Stream, nil] optional stream to wrap
631
+ # @yield [self] the new ImplicitStream instance for customization
620
632
  def initialize(other_stream = nil)
621
633
  # Initialize with defaults
622
634
  @at_beginning_proc = proc { true }
@@ -674,7 +686,9 @@ module Stream
674
686
 
675
687
  ##
676
688
  # Return a Stream::FilteredStream which iterates over all my elements
677
- # satisfying the condition specified by the block.
689
+ # satisfying the condition specified by the block.
690
+ # @yield [element] filter predicate
691
+ # @return [FilteredStream]
678
692
  def filtered(&block)
679
693
  FilteredStream.new(self, &block)
680
694
  end
@@ -687,6 +701,8 @@ module Stream
687
701
  # Create a Stream::MappedStream wrapper on self. Instead of returning the
688
702
  # stream element on each move, the value of calling _mapping_ is returned
689
703
  # instead. See Stream::MappedStream for examples.
704
+ # @yield [element] mapping block applied to each element
705
+ # @return [MappedStream]
690
706
  def collect(&mapping)
691
707
  MappedStream.new(self, &mapping)
692
708
  end
@@ -708,8 +724,10 @@ module Stream
708
724
  collect(&mapping).concatenate
709
725
  end
710
726
 
711
- # Create a Stream::ConcatenatedStream by concatenatating the receiver and
712
- # _other_stream_
727
+ # Create a Stream::ConcatenatedStream by concatenating the receiver and
728
+ # _other_stream_.
729
+ # @param other [Stream] the stream to append
730
+ # @return [ConcatenatedStream]
713
731
  #
714
732
  # (%w(a b c).create_stream + [4,5].create_stream).to_a
715
733
  # ==> ["a", "b", "c", 4, 5]
data/test/test_helper.rb CHANGED
@@ -1,2 +1 @@
1
- require 'rubygems'
2
1
  require 'test/unit'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stream
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.5
4
+ version: 0.5.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Horst Duchene
8
- autorequire: stream
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-29 00:00:00.000000000 Z
11
+ date: 2026-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -24,34 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: yard
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: rdoc
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
27
  - !ruby/object:Gem::Dependency
56
28
  name: test-unit
57
29
  requirement: !ruby/object:Gem::Requirement
@@ -70,17 +42,18 @@ description: Module Stream defines an interface for external iterators.
70
42
  email: monora@gmail.com
71
43
  executables: []
72
44
  extensions: []
73
- extra_rdoc_files:
74
- - README.rdoc
45
+ extra_rdoc_files: []
75
46
  files:
47
+ - CHANGELOG.md
76
48
  - Gemfile
77
49
  - Gemfile.lock
78
50
  - LICENSE
79
- - README.rdoc
51
+ - README.md
80
52
  - Rakefile
81
53
  - examples/examples.rb
82
54
  - examples/streamtester.rb
83
55
  - lib/stream.rb
56
+ - lib/stream/version.rb
84
57
  - test/test_helper.rb
85
58
  - test/teststream.rb
86
59
  homepage: https://github.com/monora/stream
@@ -88,12 +61,7 @@ licenses:
88
61
  - ruby
89
62
  metadata: {}
90
63
  post_install_message:
91
- rdoc_options:
92
- - "--title"
93
- - stream - Extended External Iterators
94
- - "--main"
95
- - README.rdoc
96
- - "--line-numbers"
64
+ rdoc_options: []
97
65
  require_paths:
98
66
  - lib
99
67
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -107,7 +75,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
75
  - !ruby/object:Gem::Version
108
76
  version: '0'
109
77
  requirements: []
110
- rubygems_version: 3.2.3
78
+ rubygems_version: 3.5.22
111
79
  signing_key:
112
80
  specification_version: 4
113
81
  summary: stream - Extended External Iterators
data/README.rdoc DELETED
@@ -1,180 +0,0 @@
1
- {<img src="https://github.com/monora/stream/actions/workflows/ruby.yml/badge.svg" alt="Build Status" />}[https://github.com/monora/stream/actions/workflows/ruby.yml]
2
-
3
- = Extended External Iterators (forward and backward)
4
-
5
- == Description
6
-
7
- Module +Stream+ defines an interface for {external
8
- iterators}[https://wiki.c2.com/?ExternalIterator]. A stream can be seen
9
- as an iterator on a sequence of objects +x1,...,xn+. The state of the
10
- stream is uniquely determined by the following methods:
11
-
12
- * at_beginning?
13
- * at_end?
14
- * current
15
- * peek
16
-
17
- State changes are done with the following operations:
18
-
19
- * set_to_begin
20
- * set_to_end
21
- * forward
22
- * backward
23
-
24
- With the help of the method +current_edge+ the state of a stream +s+ can be
25
- exactly defined
26
-
27
- s.current_edge == [s.current, s.peek]
28
-
29
- If +s+ a stream on [x1,...,xn]. Consider the edges [xi,xi+1] i=1,...,n
30
- and [x0,x1] and [xn,xn+1] (x0 and xn+1 are helper elements to define
31
- the boundary conditions). Then if +s+ is non empty, the following
32
- conditions must be true:
33
-
34
- s.at_beginning? <=> s.current_edge == [x0,x1]
35
- s.at_end? <=> s.current_edge == [xn,xn+1]
36
- s.isEmpty? <=> s.at_beginning? && s.at_end? <=> s.current_edge == [x0,x1] <=> n = 0
37
- s.set_to_end => s.at_end?
38
- s.set_to_begin => s.at_beginning?
39
-
40
- If 0 <= i < n and s.current_edge == [xi, xi+1] , then:
41
-
42
- [s.forward, s.current_edge] == [xi+1, [xi+1, xi+2]]
43
-
44
- If 1 <= i < n and s.current_edge == [xi, xi+1] , then:
45
-
46
- [s.backward, s.current_edge] == [xi, [xi-1, xi]]
47
-
48
- The result of peek is the same as of forward without changing state. The result of
49
- current is the same as of backward without changing state.
50
-
51
- Module +Stream+ includes +Enumerable+ implementing +each+ in the obvious way.
52
-
53
- Not every stream needs to implement +backward+ and +at_beginning?+
54
- thus being not reversable. If they are reversable peek can easily be
55
- implemented using +forward+ and +backward+, as is done in module
56
- +Stream+. If a stream is not reversable all derived streams provided
57
- by the stream module (filter, mapping, concatenation) can be used
58
- anyway. Explicit or implicit (via peek or current) uses of backward
59
- would throw a +NotImplementedError+.
60
-
61
- Classes implementing the stream interface must implement the following
62
- methods:
63
-
64
- * basic_forward
65
- * basic_backward
66
-
67
- * at_end?
68
- * at_beginning?
69
-
70
- The methods +set_to_end+ and +set_to_begin+ are by default implemented
71
- as:
72
-
73
- set_to_end : until at_end?; do basic_forward end
74
- set_to_begin : until at_beginning?; do basic_backward end
75
-
76
- The methods +forward+ and +backward+ are by default implemented as:
77
-
78
- forward: raise EndOfStreamException if at_end?; basic_forward.
79
- backward: raise EndOfStreamException if at_beginning?; basic_backward
80
-
81
- Thus subclasses must only implement *four* methods. Efficiency sometimes
82
- demands better implementations.
83
-
84
- There are several concrete classes implementing the stream interface:
85
-
86
- * +Stream::EmptyStream+ (boring)
87
- * +Stream::CollectionStream+ created by the method +Array#create_stream+
88
- * +Stream::FilteredStream+ created by the method +Stream#filtered+
89
- * +Stream::ReversedStream+ created by the method +Stream#reverse+
90
- * +Stream::ConcatenatedStream+ created by the method +Stream#concatenate+
91
- * +Stream::ImplicitStream+ using closures for the basic methods to implement
92
-
93
- == Installation
94
-
95
- gem install stream
96
-
97
- or download the latest sources from the git repository
98
- https://github.com/monora/stream.
99
-
100
- == Examples
101
-
102
- === Iterate over three streams
103
-
104
- g = ('a'..'f').create_stream
105
- h = (1..10).create_stream
106
- i = (10..20).create_stream
107
-
108
- until g.at_end? || h.at_end? || i.at_end?
109
- p [g.forward, h.forward, i.forward]
110
- end
111
-
112
- Output:
113
-
114
- ["a", 1, 10]
115
- ["b", 2, 11]
116
- ["c", 3, 12]
117
- ["d", 4, 13]
118
- ["e", 5, 14]
119
- ["f", 6, 15]
120
-
121
- === Concatenate file streams
122
-
123
- def filestream fname
124
- Stream::ImplicitStream.new { |s|
125
- f = open(fname)
126
- s.at_end_proc = proc {f.eof?}
127
- s.forward_proc = proc {f.readline}
128
- # Need not implement backward moving to use the framework
129
- }
130
- end
131
-
132
- (filestream("/etc/passwd") + ('a'..'f').create_stream + filestream("/etc/group")).each do |l|
133
- puts l
134
- end
135
-
136
- === Two filtered collection streams concatenated and reversed
137
-
138
- def newstream; (1..6).create_stream; end
139
- s = newstream.filtered { |x| x % 2 == 0 } + newstream.filtered { |x| x % 2 != 0 }
140
- s = s.reverse
141
- puts "Contents : #{s.to_a.join ' '}"
142
- puts "At end? : #{s.at_end?}"
143
- puts "At beginning? : #{s.at_beginning?}"
144
- puts "2xBackwards : #{s.backward} #{s.backward}"
145
- puts "Forward : #{s.forward}"
146
- puts "Peek : #{s.peek}"
147
- puts "Current : #{s.current}"
148
- puts "set_to_begin : Peek=#{s.set_to_begin;s.peek}"
149
-
150
- Output:
151
-
152
- Contents : 5 3 1 6 4 2
153
- At end? : true
154
- At beginning? : false
155
- 2xBackwards : 2 4
156
- Forward : 4
157
- Peek : 2
158
- Current : 4
159
- set_to_begin : Peek=5
160
-
161
- === An infinite stream (do not use +set_to_end+!)
162
-
163
- def randomStream
164
- Stream::ImplicitStream.new { |s|
165
- s.set_to_begin_proc = proc {srand 1234}
166
- s.at_end_proc = proc {false}
167
- s.forward_proc = proc {rand}
168
- }
169
- end
170
- s = randomStream.filtered { |x| x >= 0.5 }.collect { |x| sprintf("%5.2f",x*100) }
171
- puts "5 random numbers: #{(1..5).collect {|x| s.forward}}\n"
172
-
173
- Output:
174
-
175
- 5 random numbers: ["62.21", "78.54", "78.00", "80.19", "95.81"]
176
-
177
- == License
178
-
179
- Author:: Horst Duchene
180
- License:: Copyright (c) 2001, 2013, 2016, 2020, 2022 Horst Duchene (Released under the same license as Ruby (see LICENSE))