stream 0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|