lazy_stream 0.5.1 → 0.5.2
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 +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
|