Ninju-streams 1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,23 @@
1
+ == Description
2
+
3
+ Streams is designed to be a lightweight streams processing library written in Ruby. I intend to keep this very small (infact, it's unlikely to change at all), and have added most common methods to make it immediately useable.
4
+
5
+ == Example
6
+
7
+ require 'streams'
8
+
9
+ class Stream
10
+ def sieve
11
+ Stream.new( head ) { tail.select { | n | n % head > 0 }.sieve }
12
+ end
13
+ end
14
+
15
+ module Math
16
+ PRIMES = 2.enumerate.sieve
17
+ end
18
+
19
+ >> Math::PRIMES.at( 30 )
20
+ => 127
21
+
22
+ >> Math::PRIMES.select { | n | n > 100 }.take( 50 )
23
+ => [101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379]
@@ -0,0 +1,32 @@
1
+ require "rubygems"
2
+ require "rake"
3
+ require "echoe"
4
+
5
+ Echoe.new( "streams", "1.0" ) do | p |
6
+ p.description = ""
7
+ p.url = "http://github.com/Ninju/streams"
8
+ p.author = "Alex Watt"
9
+ p.email = "alex.watt@me.com"
10
+ p.ignore_pattern = []
11
+ p.development_dependencies = []
12
+ end
13
+
14
+ task :default => "spec:run"
15
+
16
+
17
+ namespace :spec do
18
+ task :run do
19
+ system( "spec spec/" )
20
+ end
21
+
22
+ task :doc do
23
+ system( "spec spec/ --format specdoc" )
24
+ end
25
+
26
+ task :coverage do
27
+ system( "rcov spec/*_spec.rb" )
28
+ system( "open coverage/index.html" )
29
+ end
30
+ end
31
+
32
+ task :spec => "spec:run"
@@ -0,0 +1,156 @@
1
+ class Stream
2
+ attr_reader :head, :delayed_tail
3
+
4
+ def initialize( head = nil, &block )
5
+ @head = head
6
+ @delayed_tail = block || head && Proc.new { Stream.new }
7
+ end
8
+
9
+ def tail
10
+ @tail ||= delayed_tail && delayed_tail.call
11
+ end
12
+
13
+ def empty?
14
+ head.nil?
15
+ end
16
+
17
+ def size
18
+ return 0 if empty?
19
+ 1 + tail.size
20
+ end
21
+
22
+ def each( &block )
23
+ return if empty?
24
+ block.call( head )
25
+ tail.each( &block )
26
+ end
27
+
28
+ def map( &block )
29
+ return self if empty?
30
+ Stream.new( block.call( head ) ) { tail.map( &block ) }
31
+ end
32
+
33
+ def select( &block )
34
+ return self if empty?
35
+
36
+ if block.call( head )
37
+ return Stream.new( head ) { tail.select( &block ) }
38
+ end
39
+
40
+ tail.select( &block )
41
+ end
42
+
43
+ def reject( &block )
44
+ select do | element |
45
+ !block.call( element )
46
+ end
47
+ end
48
+
49
+ def merge( other )
50
+ return self if other.empty?
51
+ return other if self.empty?
52
+ Stream.new( head + other.head ) { tail.merge( other.tail ) }
53
+ end
54
+
55
+ def append( other )
56
+ return self if other.empty?
57
+ return other if empty?
58
+ Stream.new( head ) { tail.append( other ) }
59
+ end
60
+
61
+ def take( n )
62
+ return Stream.new if empty? || n.zero?
63
+ return Stream.new( head ) if n == 1
64
+ Stream.new( head ) { tail.take( n - 1 ) }
65
+ end
66
+
67
+ def at( n )
68
+ raise ArgumentError, "Index out of bounds" if empty? && n >= 0
69
+ return head if n.zero?
70
+ tail.at( n - 1 )
71
+ end
72
+
73
+ def drop( n )
74
+ return self if n.zero?
75
+ return Stream.new if empty?
76
+ tail.drop( n - 1 )
77
+ end
78
+
79
+ def uniq
80
+ return self if empty?
81
+ Stream.new( head ) { tail.select { | element | element != head }.uniq }
82
+ end
83
+
84
+ def last
85
+ return nil if empty?
86
+ return head if tail.empty?
87
+ tail.last
88
+ end
89
+
90
+ def to_a
91
+ return [] if empty?
92
+ [ head ] + tail.to_a
93
+ end
94
+
95
+ def join( separator = "" )
96
+ return "" if empty?
97
+ return head.to_s if tail.empty?
98
+ head.to_s + separator + tail.join( separator )
99
+ end
100
+
101
+ def inspect
102
+ "[" + join( ", " ) + "]"
103
+ end
104
+
105
+ def include?( element )
106
+ return false if empty?
107
+ head == element || tail.include?( element )
108
+ end
109
+
110
+ def ==( other )
111
+ head == other.head && tail == other.tail
112
+ end
113
+
114
+ def take_while( &block )
115
+ if block.call( head )
116
+ Stream.new( head ) { tail.take_while( &block ) }
117
+ else
118
+ Stream.new
119
+ end
120
+ end
121
+
122
+ def all?( &block )
123
+ return true if empty?
124
+ block.call( head ) && tail.all?( &block )
125
+ end
126
+
127
+ def any?( &block )
128
+ return false if empty?
129
+ block.call( head ) || tail.any?( &block )
130
+ end
131
+ end
132
+
133
+ class Array
134
+ def to_stream
135
+ return Stream.new if empty?
136
+ Stream.new( first ) { self[ 1..-1 ].to_stream }
137
+ end
138
+ end
139
+
140
+ class Integer
141
+ def enumerate( step = 1, &block )
142
+ if block_given?
143
+ return Stream.new( self ) { block.call( self ).enumerate( &block ) }
144
+ end
145
+ Stream.new( self ) { ( self + step ).enumerate( step ) }
146
+ end
147
+
148
+ def enumerate_to( value, step = 1, &block )
149
+ return Stream.new if ( step >= 0 && self > value ) || ( step < 0 && self < value )
150
+ if block_given?
151
+ return Stream.new( self ) { block.call( self ).enumerate_to( value, &block ) }
152
+ end
153
+
154
+ Stream.new( self ) { ( self + step ).enumerate_to( value, step ) }
155
+ end
156
+ end
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require 'mocha'
4
+
5
+ Spec::Runner.configure do |config|
6
+ config.mock_with :mocha
7
+ end
@@ -0,0 +1,430 @@
1
+ require File.join( File.dirname(__FILE__), *%w[spec_helper] )
2
+ require 'streams'
3
+
4
+ describe Stream do
5
+ it "should create a new instance" do
6
+ Proc.new { Stream.new }.should_not raise_error
7
+ end
8
+
9
+ describe "basic" do
10
+ before do
11
+ @empty_stream = Stream.new
12
+ @stream = Stream.new( 43 ) { @empty_stream }
13
+ end
14
+
15
+ it "should return the head" do
16
+ @stream.head.should == 43
17
+ end
18
+
19
+ it "should return the tail" do
20
+ @stream.tail.should == @empty_stream
21
+ end
22
+
23
+ it "should call the delayed tail" do
24
+ @stream.delayed_tail.expects( :call ).once.returns( @empty_stream )
25
+ @stream.tail
26
+ end
27
+
28
+ it "should store the delayed tail in a block" do
29
+ @stream.delayed_tail.is_a?( Proc ).should be_true
30
+ end
31
+
32
+ it "should not be empty" do
33
+ @stream.should_not be_empty
34
+ end
35
+
36
+ it "should have the correct size" do
37
+ @stream.size.should == 1 + @stream.tail.size
38
+ end
39
+ end
40
+
41
+ describe "stream with head and without tail" do
42
+ before do
43
+ @stream = Stream.new( 42 )
44
+ end
45
+
46
+ it "should return the empty stream" do
47
+ @stream.tail.should be_empty
48
+ end
49
+
50
+ it "should return a stream" do
51
+ @stream.tail.is_a?( Stream ).should be_true
52
+ end
53
+ end
54
+
55
+ describe "the empty stream" do
56
+ before do
57
+ @empty_stream = Stream.new
58
+ end
59
+
60
+ it "should be empty" do
61
+ @empty_stream.should be_empty
62
+ end
63
+
64
+ it "should have zero size" do
65
+ @empty_stream.size.should == 0
66
+ end
67
+
68
+ it "should return nil if you access the tail" do
69
+ @empty_stream.tail.should be_nil
70
+ end
71
+ end
72
+
73
+ describe "infinite stream" do
74
+ before do
75
+ @stream = Stream.new( 1 ) { @stream }
76
+ end
77
+
78
+ it "should return itself" do
79
+ @stream.stubs( :inspect ).returns( nil )
80
+ @stream.tail.should === @stream
81
+ end
82
+ end
83
+
84
+ describe "basic stream behaviour: " do
85
+ before do
86
+ @stream = Stream.new( 1 ) { Stream.new( 2 ) { Stream.new( 3 ) } }
87
+ end
88
+
89
+ describe "Stream#each" do
90
+ it "should loop through each element" do
91
+ array = []
92
+ @stream.each do | element |
93
+ array << element
94
+ end
95
+
96
+ @stream.to_a.should == array
97
+ end
98
+ end
99
+
100
+ describe "Stream#map" do
101
+ it "should add 1 to each element" do
102
+ add_one = Proc.new { | n | n + 1 }
103
+ new_stream = @stream.map( &add_one )
104
+
105
+ new_stream.head.should == add_one.call( @stream.head )
106
+ new_stream.tail.should == @stream.tail.map( &add_one )
107
+ end
108
+ end
109
+
110
+ describe "Stream#select" do
111
+ it "should select elements that return true when the predicate is applied to the element" do
112
+ even = Proc.new { | n | ( n % 2 ).zero? }
113
+
114
+ odd_starting_stream = @stream
115
+ odd_starting_filtered_stream = odd_starting_stream.select( &even )
116
+
117
+ odd_starting_filtered_stream.head.should_not == odd_starting_stream.head
118
+ odd_starting_filtered_stream.should == odd_starting_stream.tail.select( &even )
119
+
120
+ even_starting_stream = Stream.new( 0 ) { odd_starting_stream }
121
+ even_starting_filtered_stream = even_starting_stream.select( &even )
122
+
123
+ even_starting_filtered_stream.head.should == even_starting_stream.head
124
+ even_starting_filtered_stream.tail.should == even_starting_stream.tail.select( &even )
125
+ end
126
+ end
127
+
128
+ describe "Stream#take" do
129
+ it "should return a stream composed of the first N elements" do
130
+ first_two = @stream.take( 2 )
131
+ first_two.head.should == @stream.head
132
+ first_two.tail.should == @stream.tail.take( 1 )
133
+ end
134
+
135
+ it "should return an empty stream if the stream is empty" do
136
+ Stream.new.take( 100 ).should == Stream.new
137
+ end
138
+
139
+ it "should return the empty stream is N is zero" do
140
+ @stream.take( 0 ).should == Stream.new
141
+ end
142
+ end
143
+
144
+ describe "Stream#at" do
145
+ it "should raise an ArgumentError if the index is out of bounds" do
146
+ Proc.new { Stream.new.at( 50 ) }.should raise_error( ArgumentError )
147
+ end
148
+
149
+ it "should raise an ArgumentError if there are no elements in the stream" do
150
+ Proc.new { Stream.new.at( 0 ) }.should raise_error( ArgumentError )
151
+ end
152
+
153
+ it "should return the element at the Nth position" do
154
+ @stream.at( 1 ).should == 2
155
+ end
156
+ end
157
+
158
+ describe "Stream#drop" do
159
+ it "should remove the first n elements from the array" do
160
+ @stream.drop( 1 ).should == @stream.tail
161
+ end
162
+
163
+ it "should return the empty stream if the amount of elements to drop is greater than the size of the stream" do
164
+ Stream.new.drop( 1 ).should == Stream.new
165
+ end
166
+ end
167
+
168
+ describe "Stream#last" do
169
+ it "should return the last element" do
170
+ @stream.last.should == 3
171
+ end
172
+
173
+ it "should return nil if the stream is empty" do
174
+ Stream.new.last.should be_nil
175
+ end
176
+ end
177
+
178
+ describe "Stream#uniq" do
179
+ before do
180
+ @stream = Stream.new( 1 ) { Stream.new( 2 ) { Stream.new( 2 ) { Stream.new( 1 ) } } }
181
+ end
182
+
183
+ it "should remove duplicate elements" do
184
+ @stream.uniq.should == Stream.new( 1 ) { Stream.new( 2 ) }
185
+ end
186
+ end
187
+
188
+ describe "Stream#==(other)" do
189
+ before do
190
+ @other_stream = @stream.dup
191
+ end
192
+
193
+ it "should return false if the elements are different" do
194
+ Stream.new.should_not == @stream
195
+ end
196
+
197
+ it "should return true if they have the same elements" do
198
+ @stream.should == @other_stream
199
+ end
200
+ end
201
+
202
+ describe "Stream#reject" do
203
+ it "should remove elements which return true when the predicate is applied to the element" do
204
+ even = Proc.new { | n | ( n % 2 ).zero? }
205
+ odd_starting_stream = @stream
206
+ even_starting_stream = Stream.new( 0 ) { odd_starting_stream }
207
+
208
+ even_starting_filtered_stream = even_starting_stream.reject( &even )
209
+ even_starting_filtered_stream.head.should_not == even_starting_stream.head
210
+ even_starting_filtered_stream.should == even_starting_stream.tail.reject( &even )
211
+
212
+ odd_starting_filtered_stream = odd_starting_stream.reject( &even )
213
+ odd_starting_filtered_stream.head.should == odd_starting_stream.head
214
+ odd_starting_filtered_stream.tail.should == odd_starting_stream.tail.reject( &even )
215
+ end
216
+ end
217
+
218
+ describe "Stream#merge" do
219
+ before do
220
+ @ones = Stream.new( 1 ) { Stream.new( 1 ) }
221
+ @twos = Stream.new( 2 ) { Stream.new( 2 ) }
222
+ end
223
+
224
+ it "should merge the streams by summing each pairing element and constructing a new stream" do
225
+ threes = @ones.merge( @twos )
226
+ threes.head.should == @ones.head + @twos.head
227
+
228
+ threes.tail.should == @ones.tail.merge( @twos.tail )
229
+ end
230
+
231
+ it "should return the mergee if the merger is empty" do
232
+ Stream.new.merge( @ones ).should == @ones
233
+ end
234
+
235
+ it "should return the merger if the mergee is empty" do
236
+ @ones.merge( Stream.new ).should == @ones
237
+ end
238
+ end
239
+
240
+ describe "Stream#take_while( &block )" do
241
+ it "should return a stream of the elements to the point where block.call( element ) is false" do
242
+ @stream.take_while { | n | n == 1 }.should == Stream.new( 1 )
243
+ end
244
+ end
245
+
246
+ describe "Stream#append" do
247
+ before do
248
+ @ones = Stream.new( 1 ) { Stream.new( 1 ) }
249
+ @twos = Stream.new( 2 ) { Stream.new( 2 ) }
250
+ end
251
+
252
+ it "should append the streams" do
253
+ appended_stream = @ones.append( @twos )
254
+ appended_stream.head.should == @ones.head
255
+ appended_stream.tail.should == @ones.tail.append( @twos )
256
+ end
257
+
258
+ it "should return the appendee if the appender is empty" do
259
+ Stream.new.append( @ones ).should == @ones
260
+ end
261
+
262
+ it "should return the appender if the appendee is empty" do
263
+ @ones.append( Stream.new ).should == @ones
264
+ end
265
+ end
266
+
267
+ describe "Stream#include?" do
268
+ it "should return false if the object is not an element in the stream" do
269
+ Stream.new.should_not include( "Hello, world!" )
270
+ end
271
+
272
+ it "should return true if the object is an element in the stream" do
273
+ @stream.should include( 1 )
274
+ end
275
+ end
276
+
277
+ describe "Stream#to_a" do
278
+ it "should return the elements of the stream as an array" do
279
+ @stream.to_a.should == [ 1, 2, 3 ]
280
+ end
281
+
282
+ it "should return an empty array if the stream is empty" do
283
+ Stream.new.to_a.should == []
284
+ end
285
+ end
286
+
287
+ describe "Stream#join" do
288
+ it "should be an empty string if the stream is empty" do
289
+ Stream.new.join.should == ""
290
+ end
291
+
292
+ it "should print the head as a string if there is only one element" do
293
+ Stream.new( 1 ).join.should == 1.to_s
294
+ end
295
+
296
+ it "should join the elements by the separator" do
297
+ @stream.join( ", " ).should == "1, 2, 3"
298
+ end
299
+ end
300
+
301
+ describe "Stream#any?( &block )" do
302
+ it "should return false if the stream is empty" do
303
+ Stream.new.any? { | n | true }.should be_false
304
+ end
305
+
306
+ it "should return true if any of the elements return true when passed to the block" do
307
+ @stream.any? { | n | n == 2 }.should be_true
308
+ end
309
+
310
+ it "should return false if none of the elements return true when passed to the block" do
311
+ @stream.any? { | n | n < -500 }.should be_false
312
+ end
313
+ end
314
+
315
+ describe "Stream#all?( &block )" do
316
+ it "should return true if the stream is empty" do
317
+ Stream.new.all? { | element | false }.should be_true
318
+ end
319
+
320
+ it "should return true if all the elements return true when the block is applied to the element" do
321
+ @stream.all? { | n | n > 0 }.should be_true
322
+ end
323
+
324
+ it "should return false if any of the elements return false when the block is applied to the element" do
325
+ @stream.all? { | n | n != 2 }.should be_false
326
+ end
327
+ end
328
+
329
+ describe "Stream#inspect" do
330
+ it "should show [].to_s if the stream is empty" do
331
+ Stream.new.inspect.should == "[]"
332
+ end
333
+
334
+ it "should show the elements in an array - stream.to_s.inspect" do
335
+ @stream.inspect.should == "[1, 2, 3]"
336
+ end
337
+ end
338
+
339
+ it "should cache the tail" do
340
+ @stream.delayed_tail.expects( :call ).with.once.returns( @stream )
341
+ 2.times { @stream.tail }
342
+ end
343
+ end
344
+ end
345
+
346
+ describe Array, "Stream helpers" do
347
+ before do
348
+ @array = [ 1, 2, 3 ]
349
+ end
350
+
351
+ describe "Array#to_stream" do
352
+ it "should convert the array to a stream" do
353
+ @array.to_stream.should be_kind_of( Stream )
354
+ end
355
+
356
+ it "should fill the stream with the correct elements" do
357
+ stream = @array.to_stream
358
+ @array.first.should == stream.head
359
+ @array[ 1..-1 ].to_stream.should == stream.tail
360
+ end
361
+
362
+ it "should return an empty stream if the array is empty" do
363
+ [].to_stream.should == Stream.new
364
+ end
365
+ end
366
+ end
367
+
368
+ describe Integer, "Stream helpers" do
369
+ describe "Integer#enumerate( step = 1, &block )" do
370
+ it "should create an infinite stream of the natural numbers" do
371
+ natural_numbers = 0.enumerate
372
+ natural_numbers.head.should == 0
373
+ natural_numbers.tail.head.should == 1
374
+ natural_numbers.at( 30 ).should == 30
375
+ end
376
+
377
+ it "should return a stream" do
378
+ 2.enumerate.should be_kind_of( Stream )
379
+ end
380
+
381
+ it "should create an infinite stream with the difference between each element being the step passed" do
382
+ multiples_of_5 = 0.enumerate( 5 )
383
+ multiples_of_5.head.should == 0
384
+ multiples_of_5.at( 5 ).should == 25
385
+ multiples_of_5.at( 10 ).should == 50
386
+ end
387
+
388
+ it "should create an infinite stream with the difference between element being the difference between the proc applied to each element" do
389
+ powers_of_2 = 1.enumerate { | n | n * 2 }
390
+ powers_of_2.head.should == 1
391
+ powers_of_2.at( 2 ).should == 4
392
+ powers_of_2.at( 4 ).should == 16
393
+ end
394
+
395
+ it "should generate the next number based on the block rather than the step" do
396
+ multiples_of_10 = 0.enumerate( 5 ) { | n | n + 10 }
397
+ multiples_of_10.at( 0 ).should == 0
398
+ multiples_of_10.at( 1 ).should == 10
399
+ multiples_of_10.at( 2 ).should == 20
400
+ end
401
+ end
402
+
403
+ describe "Integer#enumerate_to( value, step = 1, &block )" do
404
+ it "should return a stream" do
405
+ 0.enumerate_to( 100 ).should be_kind_of( Stream )
406
+ end
407
+
408
+ it "should not contain an element less than value if the step is negative" do
409
+ 100.enumerate_to( 0, -3 ).any? { | n | n < 0 }.should_not be_true
410
+ end
411
+
412
+ it "should not contain an element greater than value if the step is positive" do
413
+ 0.enumerate_to( 100, 3 ).any? { | n | n > 100 }.should_not be_true
414
+ end
415
+
416
+ it "should generate the next number based on the block rather than the step" do
417
+ stream = 0.enumerate_to( 100, 3 ) { | n | n + 11 }
418
+ stream.head.should == 0
419
+ stream.at( 1 ).should == 11
420
+ stream.at( 2 ).should == 22
421
+ end
422
+
423
+ it "should generate the next number based on the proc passed" do
424
+ stream = 0.enumerate_to( 100 ) { | n | n + 11 }
425
+ stream.head == 0
426
+ stream.at( 1 ).should == 11
427
+ stream.at( 2 ).should == 22
428
+ end
429
+ end
430
+ end
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{streams}
5
+ s.version = "1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Alex Watt"]
9
+ s.date = %q{2009-02-12}
10
+ s.description = %q{}
11
+ s.email = %q{alex.watt@me.com}
12
+ s.extra_rdoc_files = ["lib/streams.rb", "README"]
13
+ s.files = ["lib/streams.rb", "Rakefile", "README", "spec/spec_helper.rb", "spec/streams_spec.rb", "Manifest", "streams.gemspec"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://github.com/Ninju/streams}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Streams", "--main", "README"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{streams}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{}
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 2
25
+
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
+ else
28
+ end
29
+ else
30
+ end
31
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: Ninju-streams
3
+ version: !ruby/object:Gem::Version
4
+ version: "1.0"
5
+ platform: ruby
6
+ authors:
7
+ - Alex Watt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-12 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: ""
17
+ email: alex.watt@me.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - lib/streams.rb
24
+ - README
25
+ files:
26
+ - lib/streams.rb
27
+ - Rakefile
28
+ - README
29
+ - spec/spec_helper.rb
30
+ - spec/streams_spec.rb
31
+ - Manifest
32
+ - streams.gemspec
33
+ has_rdoc: true
34
+ homepage: http://github.com/Ninju/streams
35
+ post_install_message:
36
+ rdoc_options:
37
+ - --line-numbers
38
+ - --inline-source
39
+ - --title
40
+ - Streams
41
+ - --main
42
+ - README
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "1.2"
56
+ version:
57
+ requirements: []
58
+
59
+ rubyforge_project: streams
60
+ rubygems_version: 1.2.0
61
+ signing_key:
62
+ specification_version: 2
63
+ summary: ""
64
+ test_files: []
65
+