/
sieve_spec.rb
149 lines (117 loc) · 2.65 KB
/
sieve_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
require "spec_helper"
describe "sieve of Eratosthenes" do
# http://golang.org/doc/go_tutorial.html#tmp_353
it "should work using Channel primitives" do
# send the sequence 2,3,4, ... to returned channel
def generate(channels)
ch = channel!(Integer)
channels << ch
go!{ i = 1; loop { ch << i+= 1} }
return ch
end
# filter out input values divisible by *prime*, send rest to returned channel
def filter(in_channel, prime, channels)
out = channel!(Integer)
channels << out
go! do
loop do
i, _ = in_channel.receive
out << i if (i % prime) != 0
end
end
return out
end
def sieve(channels)
out = channel!(Integer)
channels << out
go! do
ch = generate(channels)
loop do
prime, _ = ch.receive
out << prime
ch = filter(ch, prime, channels)
end
end
return out
end
# run the sieve
n = 20
nth = false
channels = []
primes = sieve(channels)
result = []
if nth
n.times { primes.receive }
puts primes.receive[0]
else
loop do
p, _ = primes.receive
if p <= n
result << p
else
break
end
end
end
result.should == [2,3,5,7,11,13,17,19]
channels.each(&:close)
end
it "should work with Ruby blocks" do
# send the sequence 2,3,4, ... to returned channel
generate = Proc.new do |channels|
ch = channel!(Integer)
channels << ch
go! do
i = 1
loop { ch << i+= 1 }
end
ch
end
# filter out input values divisible by *prime*, send rest to returned channel
filtr = Proc.new do |in_channel, prime, channels|
out = channel!(Integer)
channels << out
go! do
loop do
i, _ = in_channel.receive
out << i if (i % prime) != 0
end
end
out
end
sieve = Proc.new do |channels|
out = channel!(Integer)
channels << out
go! do
ch = generate.call(channels)
loop do
prime, _ = ch.receive
out << prime
ch = filtr.call(ch, prime, channels)
end
end
out
end
# run the sieve
n = 20
nth = false
channels = []
primes = sieve.call(channels)
result = []
if nth
n.times { primes.receive }
puts primes.receive[0]
else
loop do
p, _ = primes.receive
if p <= n
result << p
else
break
end
end
end
result.should == [2,3,5,7,11,13,17,19]
channels.each(&:close)
end
end