stream 0.5
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.
- data/README +174 -0
- data/Rakefile +161 -0
- data/examples/examples.rb +51 -0
- data/examples/streamtester.rb +59 -0
- data/install.rb +24 -0
- data/lib/generator2stream.rb +22 -0
- data/lib/stream.rb +585 -0
- data/test/bm.rb +49 -0
- data/test/testgenerator.rb +24 -0
- data/test/teststream.rb +177 -0
- metadata +64 -0
data/README
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
= Extended External Iterators (forward and backward)
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
Module Stream defines an interface for external iterators. A stream can be
|
6
|
+
seen as an iterator on a sequence of objects x1,...,xn. The state of the
|
7
|
+
stream is uniquely determined by the following methods:
|
8
|
+
|
9
|
+
* at_beginning?
|
10
|
+
* at_end?
|
11
|
+
* current
|
12
|
+
* peek
|
13
|
+
|
14
|
+
State changes are done with the following operations:
|
15
|
+
|
16
|
+
* set_to_begin
|
17
|
+
* set_to_end
|
18
|
+
* forward
|
19
|
+
* backward
|
20
|
+
|
21
|
+
With the help of the method current_edge the state of a stream s can be
|
22
|
+
exactly defined
|
23
|
+
|
24
|
+
s.current_edge == [s.current, s.peek]
|
25
|
+
|
26
|
+
If s a stream on [x1,...,xn]. Consider the edges [xi,xi+1] i=1,...,n and
|
27
|
+
[x0,x1] and [xn,xn+1] (x0 and xn are helper elements to define the boundary
|
28
|
+
conditions). Then if s is non empty, the following conditions must be true:
|
29
|
+
|
30
|
+
s.at_beginning? <=> s.current_edge == [x0,x1]
|
31
|
+
s.at_end? <=> s.current_edge == [xn,xn+1]
|
32
|
+
s.isEmpty? <=> s.at_beginning? && s.at_end? <=> s.current_edge == [x0,x1] <=> n = 0
|
33
|
+
s.set_to_end => s.at_end?
|
34
|
+
s.set_to_begin => s.at_beginning?
|
35
|
+
|
36
|
+
If 0 <= i < n and s.current_edge == [xi, xi+1] , then:
|
37
|
+
|
38
|
+
[s.forward, s.current_edge] == [xi+1, [xi+1, xi+2]]
|
39
|
+
|
40
|
+
If 1 <= i < n and s.current_edge == [xi, xi+1] , then:
|
41
|
+
|
42
|
+
[s.backward, s.current_edge] == [xi, [xi-1, xi]]
|
43
|
+
|
44
|
+
The result of peek is the same as of forward without changing state. The result of
|
45
|
+
current is the same as of backward without changing state.
|
46
|
+
|
47
|
+
Module Stream includes Enumerable implementing #each in the obvious way.
|
48
|
+
|
49
|
+
Not every stream needs to implement #backward and #at_beginning? thus being
|
50
|
+
not reversable. If they are reversable peek can easily be implemented using
|
51
|
+
forward and backward, as is done in module Stream. If a stream is not
|
52
|
+
reversable all derived streams provided by the stream module (filter,
|
53
|
+
mapping, concatenation) can be used anyway. Explicit or implicit (via peek or
|
54
|
+
current) uses of backward would throw a NotImplementedError.
|
55
|
+
|
56
|
+
Classes implementing the stream interface must implement the following methods:
|
57
|
+
|
58
|
+
* basic_forward
|
59
|
+
* basic_backward
|
60
|
+
|
61
|
+
* at_end?
|
62
|
+
* at_beginning?
|
63
|
+
|
64
|
+
The methods set_to_end and set_to_begin are by default implemented as:
|
65
|
+
|
66
|
+
set_to_end : until at_end?; do basic_forward end
|
67
|
+
set_to_begin : until at_beginning?; do basic_backward end
|
68
|
+
|
69
|
+
The methods forward and backward are by default implemented as:
|
70
|
+
|
71
|
+
forward: raise EndOfStreamException if at_end?; basic_forward.
|
72
|
+
backward: raise EndOfStreamException if at_beginning?; basic_backward
|
73
|
+
|
74
|
+
Thus subclasses must only implement *four* methods. Efficiency sometimes
|
75
|
+
demands better implementations.
|
76
|
+
|
77
|
+
There are several concrete classes implementing the stream interface:
|
78
|
+
|
79
|
+
* Stream::EmptyStream (boring)
|
80
|
+
* Stream::CollectionStream created by the method Array#create_stream
|
81
|
+
* Stream::FilteredStream created by the method Stream#filtered
|
82
|
+
* Stream::ReversedStream created by the method Stream#reverse
|
83
|
+
* Stream::ConcatenatedStream created by the method Stream#concatenate
|
84
|
+
* Stream::ImplicitStream using closures for the basic methods to implement
|
85
|
+
|
86
|
+
== Download
|
87
|
+
|
88
|
+
The latest version of stream.rb can be found at
|
89
|
+
|
90
|
+
* http://rubyforge.org/frs/?group_id=110
|
91
|
+
|
92
|
+
== Installation
|
93
|
+
|
94
|
+
=== Normal Installation
|
95
|
+
|
96
|
+
You can install stream with the following command.
|
97
|
+
|
98
|
+
% ruby install.rb
|
99
|
+
|
100
|
+
from its distribution directory.
|
101
|
+
|
102
|
+
=== GEM Installation
|
103
|
+
|
104
|
+
Download the GEM file and install it with ..
|
105
|
+
|
106
|
+
gem -i stream-VERSION.gem
|
107
|
+
|
108
|
+
Use the correct version number for VERSION (e.g. 0.5). You may need
|
109
|
+
root privileges to install.
|
110
|
+
|
111
|
+
== See also
|
112
|
+
|
113
|
+
* Streams in Smalltalk: http://wiki.cs.uiuc.edu/PatternStories/FunWithStreams
|
114
|
+
* Simon Strandgaards iterator.rb[http://aeditor.rubyforge.org/iterator/files/iterator_rb.html]
|
115
|
+
* IterationStyles: http://www.rubygarden.org/ruby?IterationStyles
|
116
|
+
|
117
|
+
== Examples
|
118
|
+
|
119
|
+
g = ('a'..'f').create_stream
|
120
|
+
h = (1..10).create_stream
|
121
|
+
i = (10..20).create_stream
|
122
|
+
|
123
|
+
until g.at_end? || h.at_end? || i.at_end?
|
124
|
+
p [g.forward, h.forward, i.forward]
|
125
|
+
end
|
126
|
+
|
127
|
+
def filestream fname
|
128
|
+
Stream::ImplicitStream.new { |s|
|
129
|
+
f = open(fname)
|
130
|
+
s.at_end_proc = proc {f.eof?}
|
131
|
+
s.forward_proc = proc {f.readline}
|
132
|
+
# Need not implement backward moving to use the framework
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
(filestream("/etc/passwd") + ('a'..'f').create_stream + filestream("/etc/group")).each do |l|
|
137
|
+
puts l
|
138
|
+
end
|
139
|
+
|
140
|
+
puts "\nTwo filtered collection streams concatenated and reversed:\n\n"
|
141
|
+
|
142
|
+
def newstream; (1..6).create_stream; end
|
143
|
+
s = newstream.filtered { |x| x % 2 == 0 } + newstream.filtered { |x| x % 2 != 0 }
|
144
|
+
s = s.reverse
|
145
|
+
puts "Contents : #{s.to_a.join ' '}"
|
146
|
+
puts "At end? : #{s.at_end?}"
|
147
|
+
puts "At beginning? : #{s.at_beginning?}"
|
148
|
+
puts "2xBackwards : #{s.backward} #{s.backward}"
|
149
|
+
puts "Forward : #{s.forward}"
|
150
|
+
puts "Peek : #{s.peek}"
|
151
|
+
puts "Current : #{s.current}"
|
152
|
+
puts "set_to_begin : Peek=#{s.set_to_begin;s.peek}"
|
153
|
+
|
154
|
+
# an infinite stream (do not use set_to_end!)
|
155
|
+
def randomStream
|
156
|
+
Stream::ImplicitStream.new { |s|
|
157
|
+
s.set_to_begin_proc = proc {srand 1234}
|
158
|
+
s.at_end_proc = proc {false}
|
159
|
+
s.forward_proc = proc {rand}
|
160
|
+
}
|
161
|
+
end
|
162
|
+
s = randomStream.filtered { |x| x >= 0.5 }.collect { |x| sprintf("%5.2f ",x*100) }
|
163
|
+
puts "5 random numbers: #{(1..5).collect {|x| s.forward}}\n" # =>
|
164
|
+
|
165
|
+
5 random numbers: 74.05 94.80 87.87 86.07 83.70
|
166
|
+
|
167
|
+
== Other Stuff
|
168
|
+
|
169
|
+
$Revision: 1.1.1.1 $
|
170
|
+
$Date: 2004/05/13 23:30:03 $
|
171
|
+
|
172
|
+
Author:: Horst Duchene <hd.at.clr@hduchene.de>
|
173
|
+
License:: Copyright (c) 2001, 2004 Horst Duchene
|
174
|
+
Released under the same license as Ruby
|
data/Rakefile
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
# Rakefile for -*- ruby -*-
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rubygems'
|
5
|
+
rescue Exception
|
6
|
+
nil
|
7
|
+
end
|
8
|
+
require 'rake/clean'
|
9
|
+
require 'rake/testtask'
|
10
|
+
require 'rake/gempackagetask'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
|
13
|
+
# Determine the current version of the software
|
14
|
+
|
15
|
+
if `ruby -Ilib -rstream -e'puts STREAM_VERSION'` =~ /\S+$/
|
16
|
+
PKG_VERSION = $&
|
17
|
+
else
|
18
|
+
PKG_VERSION = "0.0.0"
|
19
|
+
end
|
20
|
+
|
21
|
+
SRC_RB = FileList['lib/*.rb']
|
22
|
+
|
23
|
+
# The default task is run if rake is given no explicit arguments.
|
24
|
+
|
25
|
+
desc "Default Task"
|
26
|
+
task :default => :test
|
27
|
+
|
28
|
+
# Define a test task.
|
29
|
+
|
30
|
+
Rake::TestTask.new { |t|
|
31
|
+
#t.libs << "tests"
|
32
|
+
#t.pattern = 'tests/Test*.rb'
|
33
|
+
t.verbose = true
|
34
|
+
}
|
35
|
+
|
36
|
+
task :test
|
37
|
+
|
38
|
+
# Define a test that will run all the test targets.
|
39
|
+
desc "Run all test targets"
|
40
|
+
task :testall => [:test ]
|
41
|
+
|
42
|
+
# Install stream using the standard install.rb script.
|
43
|
+
|
44
|
+
desc "Install the application"
|
45
|
+
task :install do
|
46
|
+
ruby "install.rb"
|
47
|
+
end
|
48
|
+
|
49
|
+
# Create a task to build the RDOC documentation tree.
|
50
|
+
|
51
|
+
rd = Rake::RDocTask.new("rdoc") { |rdoc|
|
52
|
+
rdoc.rdoc_dir = 'html'
|
53
|
+
# rdoc.template = 'kilmer'
|
54
|
+
# rdoc.template = 'css2'
|
55
|
+
rdoc.title = "Stream - Extended External Iterators"
|
56
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
57
|
+
rdoc.rdoc_files.include('README')
|
58
|
+
rdoc.rdoc_files.include('lib/*.rb', 'doc/**/*.rdoc')
|
59
|
+
}
|
60
|
+
|
61
|
+
# ====================================================================
|
62
|
+
# Create a task that will package the stream software into distributable
|
63
|
+
# tar, zip and gem files.
|
64
|
+
|
65
|
+
PKG_FILES = FileList[
|
66
|
+
'install.rb',
|
67
|
+
'[A-Z]*',
|
68
|
+
'lib/**/*.rb',
|
69
|
+
'test/**/*.rb',
|
70
|
+
'examples/**/*'
|
71
|
+
]
|
72
|
+
|
73
|
+
if ! defined?(Gem)
|
74
|
+
puts "Package Target requires RubyGEMs"
|
75
|
+
else
|
76
|
+
spec = Gem::Specification.new do |s|
|
77
|
+
|
78
|
+
#### Basic information.
|
79
|
+
|
80
|
+
s.name = 'stream'
|
81
|
+
s.version = PKG_VERSION
|
82
|
+
s.summary = "Stream - Extended External Iterators"
|
83
|
+
s.description = <<-EOF
|
84
|
+
Module Stream defines an interface for external iterators.
|
85
|
+
EOF
|
86
|
+
|
87
|
+
#### Dependencies and requirements.
|
88
|
+
|
89
|
+
#s.add_dependency('log4r', '> 1.0.4')
|
90
|
+
#s.requirements << ""
|
91
|
+
|
92
|
+
#### Which files are to be included in this gem? Everything! (Except CVS directories.)
|
93
|
+
|
94
|
+
s.files = PKG_FILES.to_a
|
95
|
+
|
96
|
+
#### C code extensions.
|
97
|
+
|
98
|
+
#s.extensions << "ext/rmagic/extconf.rb"
|
99
|
+
|
100
|
+
#### Load-time details: library and application (you will need one or both).
|
101
|
+
|
102
|
+
s.require_path = 'lib' # Use these for libraries.
|
103
|
+
s.autorequire = 'stream'
|
104
|
+
|
105
|
+
#### Documentation and testing.
|
106
|
+
|
107
|
+
s.has_rdoc = true
|
108
|
+
#s.test_suite_file = "test/rmagic-tests.rb"
|
109
|
+
|
110
|
+
#### Author and project details.
|
111
|
+
s.author = "Horst Duchene"
|
112
|
+
s.email = "hd.at.clr@hduchene.de"
|
113
|
+
s.homepage = "http://rgl.rubyforge.org"
|
114
|
+
s.rubyforge_project = "rgl"
|
115
|
+
end
|
116
|
+
|
117
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
118
|
+
pkg.need_zip = true
|
119
|
+
pkg.need_tar = true
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Misc tasks =========================================================
|
124
|
+
|
125
|
+
def count_lines(filename)
|
126
|
+
lines = 0
|
127
|
+
codelines = 0
|
128
|
+
open(filename) { |f|
|
129
|
+
f.each do |line|
|
130
|
+
lines += 1
|
131
|
+
next if line =~ /^\s*$/
|
132
|
+
next if line =~ /^\s*#/
|
133
|
+
codelines += 1
|
134
|
+
end
|
135
|
+
}
|
136
|
+
[lines, codelines]
|
137
|
+
end
|
138
|
+
|
139
|
+
def show_line(msg, lines, loc)
|
140
|
+
printf "%6s %6s %s\n", lines.to_s, loc.to_s, msg
|
141
|
+
end
|
142
|
+
|
143
|
+
desc "Count lines in the main files"
|
144
|
+
task :lines do
|
145
|
+
total_lines = 0
|
146
|
+
total_code = 0
|
147
|
+
show_line("File Name", "LINES", "LOC")
|
148
|
+
SRC_RB.each do |fn|
|
149
|
+
lines, codelines = count_lines(fn)
|
150
|
+
show_line(fn, lines, codelines)
|
151
|
+
total_lines += lines
|
152
|
+
total_code += codelines
|
153
|
+
end
|
154
|
+
show_line("TOTAL", total_lines, total_code)
|
155
|
+
end
|
156
|
+
|
157
|
+
ARCHIVEDIR = '/mnt/flash'
|
158
|
+
|
159
|
+
task :archive => [:package] do
|
160
|
+
cp FileList["pkg/*.tgz", "pkg/*.zip", "pkg/*.gem"], ARCHIVEDIR
|
161
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'stream'
|
2
|
+
|
3
|
+
# Example from knu's Generator.rb
|
4
|
+
g = ('a'..'f').create_stream
|
5
|
+
h = (1..10).create_stream
|
6
|
+
i = (10..20).create_stream
|
7
|
+
|
8
|
+
until g.at_end? || h.at_end? || i.at_end?
|
9
|
+
p [g.forward, h.forward, i.forward]
|
10
|
+
end
|
11
|
+
|
12
|
+
puts "Concatenate Filestreams and collection stream:\n"
|
13
|
+
|
14
|
+
def fs fname
|
15
|
+
Stream::ImplicitStream.new { |s|
|
16
|
+
f = open(fname)
|
17
|
+
s.at_end_proc = proc {f.eof?}
|
18
|
+
s.forward_proc = proc {f.readline}
|
19
|
+
# Need not implement backward moving to use the framework
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
(fs("/etc/passwd") + ('a'..'f').create_stream + fs("/etc/group")).each do |l|
|
24
|
+
puts l
|
25
|
+
end
|
26
|
+
|
27
|
+
puts "\nTwo filtered collection streams concatenated and reversed:\n\n"
|
28
|
+
|
29
|
+
def newstream; (1..6).create_stream; end
|
30
|
+
s = newstream.filtered { |x| x % 2 == 0 } \
|
31
|
+
+ newstream.filtered { |x| x % 2 != 0 }
|
32
|
+
s = s.reverse
|
33
|
+
puts "Contents : #{s.to_a.join ' '}"
|
34
|
+
puts "At end? : #{s.at_end?}"
|
35
|
+
puts "At beginning? : #{s.at_beginning?}"
|
36
|
+
puts "2xBackwards : #{s.backward} #{s.backward}"
|
37
|
+
puts "Forward : #{s.forward}"
|
38
|
+
puts "Peek : #{s.peek}"
|
39
|
+
puts "Current : #{s.current}"
|
40
|
+
puts "set_to_begin : Peek=#{s.set_to_begin;s.peek}"
|
41
|
+
|
42
|
+
# an infinite stream (do not use set_to_end!)
|
43
|
+
def randomStream
|
44
|
+
Stream::ImplicitStream.new { |s|
|
45
|
+
s.set_to_begin_proc = proc {srand 1234}
|
46
|
+
s.at_end_proc = proc {false}
|
47
|
+
s.forward_proc = proc {rand}
|
48
|
+
}
|
49
|
+
end
|
50
|
+
s = randomStream.filtered { |x| x >= 0.5 }.collect { |x| sprintf("%5.2f ",x*100) }
|
51
|
+
puts "5 random numbers: #{(1..5).collect {|x| s.forward}}\n"
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#
|
2
|
+
# Simple stream test interface based on Ruby-FLTK
|
3
|
+
# See: (http://ruby-fltk.sourceforge.net/)
|
4
|
+
#
|
5
|
+
require 'fltk'
|
6
|
+
require 'stream'
|
7
|
+
|
8
|
+
class StreamTester < Fltk::Window
|
9
|
+
include Stream
|
10
|
+
def initialize (s)
|
11
|
+
super(200,200)
|
12
|
+
@stream = s
|
13
|
+
|
14
|
+
pack = Fltk::Pack.new(200,200) {
|
15
|
+
%w{set_to_begin set_to_end forward backward at_end? at_beginning? current_edge entries inspect}.each { |m|
|
16
|
+
Fltk::Button.new(50,20,m) {|w,data|
|
17
|
+
@output.value(sendMsg(m))
|
18
|
+
puts sendMsg(m)
|
19
|
+
}
|
20
|
+
}
|
21
|
+
@output= Fltk::Input.new(200, 20)
|
22
|
+
@output.deactivate
|
23
|
+
}
|
24
|
+
pack.packtype = Fltk::VERTICAL
|
25
|
+
self.add(pack)
|
26
|
+
self.show
|
27
|
+
end
|
28
|
+
|
29
|
+
def sendMsg(m)
|
30
|
+
begin
|
31
|
+
@stream.send(m).inspect
|
32
|
+
rescue EndOfStreamException => msg
|
33
|
+
msg
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Stream
|
39
|
+
def openTester
|
40
|
+
StreamTester.new(self)
|
41
|
+
Fltk::run()
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
if $0 == __FILE__
|
46
|
+
def newstream; (1..6).create_stream; end
|
47
|
+
s = newstream.filtered { |x| x % 2 == 0 } \
|
48
|
+
+ newstream.filtered { |x| x % 2 != 0 }
|
49
|
+
s.reverse.openTester
|
50
|
+
|
51
|
+
# an infinite stream (do not use set_to_end!)
|
52
|
+
randomStream =
|
53
|
+
Stream::ImplicitStream.new { |s|
|
54
|
+
s.set_to_begin_proc = proc {srand 1234}
|
55
|
+
s.at_end_proc = proc {false}
|
56
|
+
s.forward_proc = proc {rand}
|
57
|
+
}
|
58
|
+
randomStream.filtered { |x| x >= 0.5 }.collect { |x| x*100 }.openTester
|
59
|
+
end
|
data/install.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rbconfig'
|
4
|
+
require 'ftools'
|
5
|
+
require 'find'
|
6
|
+
|
7
|
+
SRC_BASE = 'lib'
|
8
|
+
INSTDIR = File.join Config::CONFIG['sitedir']
|
9
|
+
|
10
|
+
def install
|
11
|
+
begin
|
12
|
+
pwd = Dir.pwd
|
13
|
+
Dir.chdir(SRC_BASE)
|
14
|
+
Dir['*.rb'].each do |file|
|
15
|
+
dst = File.join( INSTDIR, file )
|
16
|
+
File.install(file, dst, 0644, true)
|
17
|
+
end
|
18
|
+
Dir.chdir(pwd)
|
19
|
+
rescue
|
20
|
+
puts $!
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
install
|