lazy_stream 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +122 -0
- data/Rakefile +6 -0
- data/lib/lazy_stream.rb +10 -9
- data/spec/example_spec.rb +176 -0
- data/spec/lazy_stream_spec.rb +163 -0
- data/spec/spec_helper.rb +7 -0
- metadata +27 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55023408f0cd578d29bf48c769b001f29c3e70dc
|
4
|
+
data.tar.gz: 6de9083f43b08e1c0e448116f553c904c4ee2550
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac332caa2e2b89a8d8818e511761a04d6e61aaa1e0021b34e483218c8ae1d5976f741db6d6e0fd99c6df40d196a8e1c9f302b998fe711aa71642e2f8f90fbc77
|
7
|
+
data.tar.gz: 5b309210ab23fc28c4a2eaf0878b6bca09df7e906768032b00f6e87ece306b103827723fdfb91396cb7adb1b7ed8867fc61f0c68ef76d9f79e5a6d8ba4a71442
|
data/README.md
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
lazy_stream
|
2
|
+
===========
|
3
|
+
|
4
|
+
A Ruby class to represent lazy infinite stream.
|
5
|
+
It is implemented in the same way as the streams in the book [SICP]
|
6
|
+
(http://mitpress.mit.edu/sicp/full-text/sicp/book/node69.html).
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
The library is distributed via [RubyGems](http://rubygems.org/gems/lazy_stream):
|
10
|
+
|
11
|
+
$ gem install lazy_stream
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
A stream is just a delayed list. We do lazy evaluation in Ruby with code blocks.
|
16
|
+
To create a stream:
|
17
|
+
|
18
|
+
``` ruby
|
19
|
+
require 'lazy_stream'
|
20
|
+
|
21
|
+
s = lazy_stream(1) { lazy_stream(2) { lazy_stream(3) } }
|
22
|
+
s.to_a #=> [1, 2, 3]
|
23
|
+
s.first #=> 1
|
24
|
+
s.rest #=> A LazyStream object for the rest of the list [2, 3]
|
25
|
+
lazy_stream #=> An empty LazyStream object
|
26
|
+
```
|
27
|
+
|
28
|
+
lazy_stream is just a shortcut for LazyStream.new.
|
29
|
+
Methods empty?, at, drop, each, map, reduce, select, take are also implemented
|
30
|
+
like Array.
|
31
|
+
|
32
|
+
It becomes powerful when we construct infinite streams like these:
|
33
|
+
|
34
|
+
``` ruby
|
35
|
+
def integers_starting_from(n)
|
36
|
+
lazy_stream(n) { integers_starting_from(n + 1) }
|
37
|
+
end
|
38
|
+
|
39
|
+
integers_starting_from(1).take(10).reduce(&:+) #=> 55
|
40
|
+
|
41
|
+
def fibgen(a, b)
|
42
|
+
lazy_stream(a) { fibgen(b, a + b) }
|
43
|
+
end
|
44
|
+
|
45
|
+
fibgen(0, 1).take(10).to_a #=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
|
46
|
+
|
47
|
+
def sieve(stream)
|
48
|
+
lazy_stream(stream.first) do
|
49
|
+
sieve(stream.rest.select { |x| x % stream.first > 0 })
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def primes
|
54
|
+
sieve(integers_starting_from(2))
|
55
|
+
end
|
56
|
+
|
57
|
+
primes.take(10).to_a #=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
|
58
|
+
```
|
59
|
+
|
60
|
+
Or define streams implicitly:
|
61
|
+
|
62
|
+
``` ruby
|
63
|
+
ones = lazy_stream(1) { ones }
|
64
|
+
ones.take(10).to_a #=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
65
|
+
|
66
|
+
integers = lazy_stream(1) { LazyStream.add(ones, integers) }
|
67
|
+
integers.take(10).to_a #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
68
|
+
|
69
|
+
# fibs is a stream beginning with 0 and 1, such that the rest of the stream can
|
70
|
+
# be generated by adding fibs to itself shifted by one place:
|
71
|
+
# 1 1 2 3 5 8 13 21 ... = fibs.rest
|
72
|
+
# 0 1 1 2 3 5 8 13 ... = fibs
|
73
|
+
# 0 1 1 2 3 5 8 13 21 34 ... = fibs
|
74
|
+
fibs = lazy_stream(0) { lazy_stream(1) { LazyStream.add(fibs.rest, fibs) } }
|
75
|
+
fibs.take(10).to_a #=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
|
76
|
+
```
|
77
|
+
|
78
|
+
More complicated example, approximating *π*, with Euler's transform and the
|
79
|
+
tableau sequence accelerator:
|
80
|
+
|
81
|
+
``` ruby
|
82
|
+
def pi_summands(n)
|
83
|
+
lazy_stream(1.0 / n) { pi_summands(n + 2).map(&:-@) }
|
84
|
+
end
|
85
|
+
|
86
|
+
def pi_stream
|
87
|
+
pi_summands(1).partial_sums.scale(4)
|
88
|
+
end
|
89
|
+
|
90
|
+
def euler_transform(s)
|
91
|
+
lazy_stream(s[2] - ((s[2] - s[1])**2 / (s[0] - 2 * s[1] + s[2]))) do
|
92
|
+
euler_transform(s.rest)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def make_tableau(s, &transform)
|
97
|
+
lazy_stream(s) { make_tableau(transform.call(s), &transform) }
|
98
|
+
end
|
99
|
+
|
100
|
+
def accelerated_sequence(s, &transform)
|
101
|
+
make_tableau(s, &transform).map(&:first)
|
102
|
+
end
|
103
|
+
|
104
|
+
accelerated_sequence(pi_stream, &method(:euler_transform)).take(8).print
|
105
|
+
# 4.0
|
106
|
+
# 3.166666666666667
|
107
|
+
# 3.142105263157895
|
108
|
+
# 3.141599357319005
|
109
|
+
# 3.1415927140337785
|
110
|
+
# 3.1415926539752927
|
111
|
+
# 3.1415926535911765
|
112
|
+
# 3.141592653589778
|
113
|
+
```
|
114
|
+
|
115
|
+
Since the functions are all recursive here, to make them actually work for large
|
116
|
+
data set, we need to enable the
|
117
|
+
[tail call optimization](https://github.com/melvinxie/ruby/blob/master/tco.rb)
|
118
|
+
in Ruby, otherwise you will hit the stack level too deep error soon.
|
119
|
+
|
120
|
+
For more examples, see my
|
121
|
+
[blog post](http://melvinxie.github.io/blog/2013/05/04/ruby-lazy-infinite-stream-in-the-sicp-way/)
|
122
|
+
and [example spec](https://github.com/melvinxie/lazy_stream/blob/master/spec/example_spec.rb).
|
data/Rakefile
ADDED
data/lib/lazy_stream.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
class LazyStream
|
4
|
+
attr_reader :first
|
5
|
+
|
4
6
|
def initialize(first=nil, &proc)
|
5
7
|
@first = first
|
6
8
|
@proc = block_given? ? proc : lambda { LazyStream.new }
|
7
9
|
end
|
8
10
|
|
9
|
-
attr_reader :first
|
10
|
-
|
11
11
|
def rest
|
12
12
|
@rest ||= @proc.call
|
13
13
|
end
|
@@ -17,13 +17,8 @@ class LazyStream
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def [](n)
|
20
|
-
if empty?
|
21
|
-
|
22
|
-
elsif n == 0
|
23
|
-
first
|
24
|
-
else
|
25
|
-
rest[n - 1]
|
26
|
-
end
|
20
|
+
return nil if empty?
|
21
|
+
n == 0 ? first : rest[n - 1]
|
27
22
|
end
|
28
23
|
|
29
24
|
alias_method :at, :[]
|
@@ -106,6 +101,12 @@ class LazyStream
|
|
106
101
|
def self.interleave(s1, s2)
|
107
102
|
s1.empty? ? s2 : LazyStream.new(s1.first) { interleave(s2, s1.rest) }
|
108
103
|
end
|
104
|
+
|
105
|
+
def ==(other)
|
106
|
+
return false if !other.is_a?(LazyStream)
|
107
|
+
return true if empty? && other.empty?
|
108
|
+
first == other.first && rest == other.rest
|
109
|
+
end
|
109
110
|
end
|
110
111
|
|
111
112
|
module Kernel
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe "Example" do
|
4
|
+
def integers_starting_from(n)
|
5
|
+
lazy_stream(n) { integers_starting_from(n + 1) }
|
6
|
+
end
|
7
|
+
|
8
|
+
it "defines integers stream explicitly" do
|
9
|
+
integers = integers_starting_from(1)
|
10
|
+
integers.take(10).to_a.should == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
11
|
+
integers.take(10).reduce(&:+).should == 55
|
12
|
+
no_sevens = integers.select { |i| i % 7 > 0 }
|
13
|
+
no_sevens.take(10).to_a.should == [1, 2, 3, 4, 5, 6, 8, 9, 10, 11]
|
14
|
+
end
|
15
|
+
|
16
|
+
def fibgen(a, b)
|
17
|
+
lazy_stream(a) { fibgen(b, a + b) }
|
18
|
+
end
|
19
|
+
|
20
|
+
it "defines fibonacci stream explicitly" do
|
21
|
+
fibgen(0, 1).take(10).to_a.should == [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
|
22
|
+
end
|
23
|
+
|
24
|
+
def sieve(stream)
|
25
|
+
lazy_stream(stream.first) do
|
26
|
+
sieve(stream.rest.select { |x| x % stream.first > 0 })
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it "defines primes stream with sieve explicitly" do
|
31
|
+
primes = sieve(integers_starting_from(2))
|
32
|
+
primes.take(10).to_a.should == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "defines integers stream implicitly" do
|
36
|
+
ones = lazy_stream(1) { ones }
|
37
|
+
ones.take(10).to_a.should == [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
38
|
+
integers = lazy_stream(1) { LazyStream.add(ones, integers) }
|
39
|
+
integers.take(10).to_a.should == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "defines fibonacci stream implicitly" do
|
43
|
+
# fibs is a stream beginning with 0 and 1, such that the rest of the stream
|
44
|
+
# can be generated by adding fibs to itself shifted by one place:
|
45
|
+
# 1 1 2 3 5 8 13 21 ... = fibs.rest
|
46
|
+
# 0 1 1 2 3 5 8 13 ... = fibs
|
47
|
+
# 0 1 1 2 3 5 8 13 21 34 ... = fibs
|
48
|
+
fibs = lazy_stream(0) { lazy_stream(1) { LazyStream.add(fibs.rest, fibs) } }
|
49
|
+
fibs.take(10).to_a.should == [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
|
50
|
+
end
|
51
|
+
|
52
|
+
def prime?(n)
|
53
|
+
iter = -> ps do
|
54
|
+
if ps.first**2 > n
|
55
|
+
true
|
56
|
+
elsif n % ps.first == 0
|
57
|
+
false
|
58
|
+
else
|
59
|
+
iter.call(ps.rest)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
iter.call(@primes)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "defines primes stream implicitly" do
|
66
|
+
# The reason this definition works is that, at any point, enough of the
|
67
|
+
# primes stream has been generated to test the primality of the numbers we
|
68
|
+
# need to check next.
|
69
|
+
@primes = lazy_stream(2) do
|
70
|
+
integers_starting_from(3).select(&method(:prime?))
|
71
|
+
end
|
72
|
+
@primes.take(10).to_a.should == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
|
73
|
+
end
|
74
|
+
|
75
|
+
def enumerate_interval(low, high)
|
76
|
+
low > high ? lazy_stream :
|
77
|
+
lazy_stream(low) { enumerate_interval(low + 1, high) }
|
78
|
+
end
|
79
|
+
|
80
|
+
def prime_enumerate_interval(low, high)
|
81
|
+
enumerate_interval(low, high).select(&method(:prime?))
|
82
|
+
end
|
83
|
+
|
84
|
+
it "enumerates intervals of primes stream" do
|
85
|
+
@primes = lazy_stream(2) do
|
86
|
+
integers_starting_from(3).select(&method(:prime?))
|
87
|
+
end
|
88
|
+
prime_enumerate_interval(10, 30).to_a.should == [11, 13, 17, 19, 23, 29]
|
89
|
+
prime_enumerate_interval(10000, 40000).reduce(&:+).should == 73434270
|
90
|
+
end
|
91
|
+
|
92
|
+
def sqrt_improve(guess, x)
|
93
|
+
(guess + x / guess) / 2
|
94
|
+
end
|
95
|
+
|
96
|
+
def sqrt_stream(x)
|
97
|
+
guesses = lazy_stream(1.0) do
|
98
|
+
guesses.map { |guess| sqrt_improve(guess, x) }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it "defines sqrt approximation stream" do
|
103
|
+
sqrt_stream(2).take(5).to_a.should ==
|
104
|
+
[1.0, 1.5, 1.4166666666666665, 1.4142156862745097, 1.4142135623746899]
|
105
|
+
end
|
106
|
+
|
107
|
+
def pi_summands(n)
|
108
|
+
lazy_stream(1.0 / n) { pi_summands(n + 2).map(&:-@) }
|
109
|
+
end
|
110
|
+
|
111
|
+
def pi_stream
|
112
|
+
pi_summands(1).partial_sums.scale(4)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "defines pi approximation stream" do
|
116
|
+
pi_stream.take(8).to_a.should ==
|
117
|
+
[4.0, 2.666666666666667, 3.466666666666667, 2.8952380952380956,
|
118
|
+
3.3396825396825403, 2.9760461760461765, 3.2837384837384844,
|
119
|
+
3.017071817071818]
|
120
|
+
end
|
121
|
+
|
122
|
+
def euler_transform(s)
|
123
|
+
lazy_stream(s[2] - ((s[2] - s[1])**2 / (s[0] - 2 * s[1] + s[2]))) do
|
124
|
+
euler_transform(s.rest)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
it "defines pi approximation stream with euler transform" do
|
129
|
+
euler_transform(pi_stream).take(8).to_a.should ==
|
130
|
+
[3.166666666666667, 3.1333333333333337, 3.1452380952380956,
|
131
|
+
3.13968253968254, 3.1427128427128435, 3.1408813408813416,
|
132
|
+
3.142071817071818, 3.1412548236077655]
|
133
|
+
end
|
134
|
+
|
135
|
+
def make_tableau(s, &transform)
|
136
|
+
lazy_stream(s) { make_tableau(transform.call(s), &transform) }
|
137
|
+
end
|
138
|
+
|
139
|
+
def accelerated_sequence(s, &transform)
|
140
|
+
make_tableau(s, &transform).map(&:first)
|
141
|
+
end
|
142
|
+
|
143
|
+
it "defines pi approximation stream with accelerated sequence" do
|
144
|
+
accelerated_sequence(pi_stream, &method(:euler_transform)).take(8).to_a.
|
145
|
+
should == [4.0, 3.166666666666667, 3.142105263157895, 3.141599357319005,
|
146
|
+
3.1415927140337785, 3.1415926539752927, 3.1415926535911765,
|
147
|
+
3.141592653589778]
|
148
|
+
end
|
149
|
+
|
150
|
+
def pairs(s, t)
|
151
|
+
lazy_stream([s.first, t.first]) do
|
152
|
+
LazyStream.interleave(t.rest.map { |x| [s.first, x] },
|
153
|
+
pairs(s.rest, t.rest))
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
it "defines pairs stream" do
|
158
|
+
integers = integers_starting_from(1)
|
159
|
+
pairs(integers, integers).take(5).to_a.should ==
|
160
|
+
[[1, 1], [1, 2], [2, 2], [1, 3], [2, 3]]
|
161
|
+
end
|
162
|
+
|
163
|
+
# integrand is a delayed argument that promises to give result after a loop
|
164
|
+
def integral(integrand, initial, dt)
|
165
|
+
int = lazy_stream(initial) { LazyStream.add(integrand.call.scale(dt), int) }
|
166
|
+
end
|
167
|
+
|
168
|
+
# sets up the delayed integrand with lambda
|
169
|
+
def solve(f, y0, dt)
|
170
|
+
y = integral(lambda { y.map(&f) }, y0, dt)
|
171
|
+
end
|
172
|
+
|
173
|
+
it "solves the differential equation dy / dt = f(y)" do
|
174
|
+
solve(lambda { |y| y }, 1, 0.001)[1000].should == 2.716923932235896
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe LazyStream do
|
4
|
+
it "initializes an empty stream" do
|
5
|
+
empty_stream = LazyStream.new
|
6
|
+
empty_stream.should be_empty
|
7
|
+
end
|
8
|
+
|
9
|
+
it "returns the first element" do
|
10
|
+
stream = LazyStream.new(1)
|
11
|
+
stream.first.should == 1
|
12
|
+
end
|
13
|
+
|
14
|
+
it "has the rest as another lazy stream itself" do
|
15
|
+
stream = LazyStream.new(1) { LazyStream.new(2) }
|
16
|
+
stream.rest.first.should == 2
|
17
|
+
end
|
18
|
+
|
19
|
+
it "caches the rest" do
|
20
|
+
cached = false
|
21
|
+
rest = lambda do
|
22
|
+
if !cached
|
23
|
+
cached = true
|
24
|
+
LazyStream.new(2)
|
25
|
+
else
|
26
|
+
raise Exception, "Did not cache"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
stream = LazyStream.new(1, &rest)
|
30
|
+
stream.rest.first.should == 2
|
31
|
+
stream.rest.first.should == 2
|
32
|
+
end
|
33
|
+
|
34
|
+
it "knows when it's not empty" do
|
35
|
+
LazyStream.new(1).should_not be_empty
|
36
|
+
end
|
37
|
+
|
38
|
+
context "#[]" do
|
39
|
+
it "returns nil when is empty" do
|
40
|
+
LazyStream.new[0].should == nil
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns first for zero index" do
|
44
|
+
LazyStream.new(1)[0].should == 1
|
45
|
+
end
|
46
|
+
|
47
|
+
it "returns from the rest for greater than zero indices" do
|
48
|
+
stream = LazyStream.new(1) { LazyStream.new(2) }
|
49
|
+
stream[1].should == 2
|
50
|
+
end
|
51
|
+
|
52
|
+
it "aliases to [] from at" do
|
53
|
+
stream = LazyStream.new(1) { LazyStream.new(2) }
|
54
|
+
stream.at(1).should == 2
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "#drop" do
|
59
|
+
it "returns the stream when it's empty" do
|
60
|
+
stream = LazyStream.new
|
61
|
+
stream.drop(10).should == stream
|
62
|
+
end
|
63
|
+
|
64
|
+
it "returns itself when nothing has been dropped" do
|
65
|
+
stream = LazyStream.new(1)
|
66
|
+
stream.drop(0).should == stream
|
67
|
+
end
|
68
|
+
|
69
|
+
it "returns the rest after dropping the first element" do
|
70
|
+
stream = LazyStream.new(1) { LazyStream.new(2) }
|
71
|
+
stream.drop(1).should == LazyStream.new(2)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "#each" do
|
76
|
+
it "iterates through all elements in stream" do
|
77
|
+
stream = LazyStream.new(1) { LazyStream.new(2) }
|
78
|
+
elements = []
|
79
|
+
stream.each { |element| elements << element }
|
80
|
+
elements.should == [1, 2]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "#map" do
|
85
|
+
it "maps the elements one at a time" do
|
86
|
+
stream = LazyStream.new(1) { LazyStream.new(2) }
|
87
|
+
mapped = stream.map do |item|
|
88
|
+
item * 2
|
89
|
+
end
|
90
|
+
mapped.should == LazyStream.new(2) { LazyStream.new(4) }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context "#select" do
|
95
|
+
it "returns self if stream is empty" do
|
96
|
+
stream = LazyStream.new
|
97
|
+
selected = stream.select { |element| element % 2 == 0 }
|
98
|
+
selected.should == stream
|
99
|
+
end
|
100
|
+
|
101
|
+
it "selects first when it only applies to it" do
|
102
|
+
stream = LazyStream.new(2) { LazyStream.new(1) }
|
103
|
+
selected = stream.select { |element| element % 2 == 0 }
|
104
|
+
selected == LazyStream.new(2)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "selects as longs as predicate applies" do
|
108
|
+
stream = LazyStream.new(2) { LazyStream.new(4) }
|
109
|
+
selected = stream.select { |element| element % 2 == 0 }
|
110
|
+
selected.should == stream
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "#take" do
|
115
|
+
it "returns an empty steam if stream is empty" do
|
116
|
+
stream = LazyStream.new
|
117
|
+
stream.take(10).should be_empty
|
118
|
+
end
|
119
|
+
|
120
|
+
it "returns empty stream if n is less than one" do
|
121
|
+
stream = LazyStream.new(1)
|
122
|
+
stream.take(0).should == LazyStream.new
|
123
|
+
end
|
124
|
+
|
125
|
+
it "returns the first element for n equals 1" do
|
126
|
+
stream = LazyStream.new(2)
|
127
|
+
stream.take(1).should == stream
|
128
|
+
end
|
129
|
+
|
130
|
+
it "returns first & rest from rest when n is greater than 1" do
|
131
|
+
stream = LazyStream.new(1) { LazyStream.new(2) }
|
132
|
+
stream.take(2).should == stream
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context "#==" do
|
137
|
+
it "is not equal with something other than LazyStream" do
|
138
|
+
LazyStream.new.should_not == 2
|
139
|
+
end
|
140
|
+
|
141
|
+
it "is equal when both empty" do
|
142
|
+
LazyStream.new.should == LazyStream.new
|
143
|
+
end
|
144
|
+
|
145
|
+
it "is equal when they both have single same element" do
|
146
|
+
LazyStream.new(1).should == LazyStream.new(1)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "is not equal when they have different first" do
|
150
|
+
LazyStream.new(1).should_not == LazyStream.new(2)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "is equal when first and rest are equal" do
|
154
|
+
stream = LazyStream.new(1) { LazyStream.new(2) }
|
155
|
+
stream.should == LazyStream.new(1) { LazyStream.new(2) }
|
156
|
+
end
|
157
|
+
|
158
|
+
it "is not equal when rests are not equal" do
|
159
|
+
stream = LazyStream.new(1) { LazyStream.new(2) }
|
160
|
+
stream.should_not == LazyStream.new(1) { LazyStream.new(3) }
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lazy_stream
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mingmin Xie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-05-
|
12
|
-
dependencies:
|
11
|
+
date: 2013-05-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
description: Ruby infinite lazy stream
|
14
28
|
email: melvinxie@gmail.com
|
15
29
|
executables: []
|
@@ -17,6 +31,11 @@ extensions: []
|
|
17
31
|
extra_rdoc_files: []
|
18
32
|
files:
|
19
33
|
- lib/lazy_stream.rb
|
34
|
+
- Rakefile
|
35
|
+
- README.md
|
36
|
+
- spec/example_spec.rb
|
37
|
+
- spec/lazy_stream_spec.rb
|
38
|
+
- spec/spec_helper.rb
|
20
39
|
homepage: https://github.com/melvinxie/lazy_stream
|
21
40
|
licenses:
|
22
41
|
- MIT
|
@@ -37,8 +56,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
37
56
|
version: '0'
|
38
57
|
requirements: []
|
39
58
|
rubyforge_project:
|
40
|
-
rubygems_version: 2.0.
|
59
|
+
rubygems_version: 2.0.0
|
41
60
|
signing_key:
|
42
61
|
specification_version: 4
|
43
62
|
summary: lazy_stream
|
44
|
-
test_files:
|
63
|
+
test_files:
|
64
|
+
- spec/example_spec.rb
|
65
|
+
- spec/lazy_stream_spec.rb
|
66
|
+
- spec/spec_helper.rb
|