lazylist 0.3.1 → 0.3.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.
- data/CHANGES +4 -0
- data/{GPL → COPYING} +0 -0
- data/{README.en → README} +15 -3
- data/Rakefile +36 -33
- data/VERSION +1 -1
- data/doc-main.txt +121 -0
- data/examples/examples.rb +7 -2
- data/examples/hamming.rb +0 -1
- data/examples/pi.rb +0 -1
- data/examples/sieve.rb +0 -1
- data/install.rb +0 -1
- data/lazylist.gemspec +23 -0
- data/lib/lazylist.rb +13 -181
- data/lib/lazylist/enumerable.rb +17 -4
- data/lib/lazylist/enumerator_queue.rb +35 -0
- data/lib/lazylist/thread_queue.rb +61 -0
- data/lib/lazylist/version.rb +1 -1
- data/make_doc.rb +1 -2
- data/tests/runner.rb +6 -4
- data/tests/test.rb +88 -88
- data/tests/test_enumerable.rb +10 -1
- metadata +68 -64
data/CHANGES
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
2009-07-23 * 0.3.2 * Some cleanup.
|
2
|
+
* Build a gemspec file.
|
3
|
+
* Added end_list method to end a lazy list during the
|
4
|
+
evaluation of a filter predicate.
|
1
5
|
2007-11-27 * 0.3.1 * Comron Sattari <comron@gmail.com> reported a bug
|
2
6
|
concerning false values in a lazy list. This problem
|
3
7
|
should be corrected now.
|
data/{GPL → COPYING}
RENAMED
File without changes
|
data/{README.en → README}
RENAMED
@@ -5,15 +5,27 @@ Just type into the command line as root:
|
|
5
5
|
|
6
6
|
# ruby install.rb
|
7
7
|
|
8
|
+
Or if you prefer to use rake, try:
|
9
|
+
|
10
|
+
# rake install
|
11
|
+
|
12
|
+
Or if you want to use rubygems just type this and rubygems fetches the gem and
|
13
|
+
installs it for you:
|
14
|
+
|
15
|
+
# gem install lazylist
|
16
|
+
|
8
17
|
Documentation
|
9
18
|
=============
|
10
19
|
|
11
20
|
The API documentatin of this library is can be produced by typing:
|
12
21
|
$ ruby make_doc.rb
|
13
22
|
|
23
|
+
Or with rake:
|
24
|
+
$ rake doc
|
25
|
+
|
14
26
|
You should also look into the files in the examples directory to get an idea
|
15
|
-
how this library is used. It is also interesting to examine
|
16
|
-
reason.
|
27
|
+
how this library is used. It is also interesting to examine the tests directory
|
28
|
+
for this reason.
|
17
29
|
|
18
30
|
Author
|
19
31
|
======
|
@@ -23,5 +35,5 @@ Florian Frank <flori@ping.de>
|
|
23
35
|
License
|
24
36
|
=======
|
25
37
|
|
26
|
-
GNU General Public License (GPL)
|
38
|
+
GNU General Public License (GPL), Version 2
|
27
39
|
|
data/Rakefile
CHANGED
@@ -1,25 +1,15 @@
|
|
1
|
-
# vim: set et sw=2 ts=2:
|
2
|
-
|
3
1
|
begin
|
4
2
|
require 'rake/gempackagetask'
|
5
3
|
rescue LoadError
|
6
4
|
end
|
5
|
+
require 'rake/clean'
|
7
6
|
require 'rbconfig'
|
8
7
|
include Config
|
9
8
|
|
10
9
|
PKG_NAME = 'lazylist'
|
11
10
|
PKG_VERSION = File.read('VERSION').chomp
|
12
11
|
PKG_FILES = FileList['**/*'].exclude(/^(doc|CVS|pkg|coverage)/)
|
13
|
-
|
14
|
-
desc "Run unit tests"
|
15
|
-
task :test do
|
16
|
-
ruby %{-Ilib tests/runner.rb}
|
17
|
-
end
|
18
|
-
|
19
|
-
desc "Testing library with coverage"
|
20
|
-
task :coverage do
|
21
|
-
sh 'rcov -x tests -Ilib tests/runner.rb'
|
22
|
-
end
|
12
|
+
CLEAN.include 'coverage', 'doc'
|
23
13
|
|
24
14
|
desc "Installing library"
|
25
15
|
task :install do
|
@@ -31,39 +21,51 @@ task :doc do
|
|
31
21
|
ruby 'make_doc.rb'
|
32
22
|
end
|
33
23
|
|
34
|
-
desc "
|
35
|
-
task :
|
36
|
-
|
37
|
-
|
24
|
+
desc "Run unit tests"
|
25
|
+
task :test do
|
26
|
+
ruby %{-Ilib tests/runner.rb}
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Testing library with coverage"
|
30
|
+
task :coverage do
|
31
|
+
sh 'rcov -x tests -Ilib tests/runner.rb'
|
38
32
|
end
|
39
33
|
|
40
34
|
if defined? Gem
|
41
|
-
|
42
|
-
|
43
|
-
|
35
|
+
spec_src =<<GEM
|
36
|
+
# -*- encoding: utf-8 -*-
|
37
|
+
Gem::Specification.new do |s|
|
38
|
+
s.name = '#{PKG_NAME}'
|
39
|
+
s.version = '#{PKG_VERSION}'
|
44
40
|
s.summary = "Implementation of lazy lists for Ruby"
|
45
41
|
s.description = ""
|
46
42
|
|
47
|
-
s.add_dependency('dslkit', '
|
43
|
+
s.add_dependency('dslkit', '~> 0.2')
|
48
44
|
|
49
|
-
s.files = PKG_FILES
|
45
|
+
s.files = #{PKG_FILES.to_a.sort.inspect}
|
50
46
|
|
51
47
|
s.require_path = 'lib'
|
52
48
|
|
53
49
|
s.has_rdoc = true
|
54
|
-
s.extra_rdoc_files
|
55
|
-
s.rdoc_options <<
|
56
|
-
|
57
|
-
'--main' << 'LazyList' <<
|
58
|
-
'--line-numbers'
|
59
|
-
s.test_files << 'tests/test.rb'
|
50
|
+
s.extra_rdoc_files << 'doc-main.txt'
|
51
|
+
s.rdoc_options << '--main' << 'doc-main.txt'
|
52
|
+
s.test_files << 'tests/runner.rb'
|
60
53
|
|
61
54
|
s.author = "Florian Frank"
|
62
55
|
s.email = "flori@ping.de"
|
63
|
-
s.homepage = "http
|
64
|
-
s.rubyforge_project = "
|
56
|
+
s.homepage = "http://#{PKG_NAME}.rubyforge.org"
|
57
|
+
s.rubyforge_project = "#{PKG_NAME}"
|
58
|
+
end
|
59
|
+
GEM
|
60
|
+
|
61
|
+
desc 'Create a gemspec file'
|
62
|
+
task :gemspec do
|
63
|
+
File.open("#{PKG_NAME}.gemspec", 'w') do |f|
|
64
|
+
f.puts spec_src
|
65
|
+
end
|
65
66
|
end
|
66
67
|
|
68
|
+
spec = eval(spec_src)
|
67
69
|
Rake::GemPackageTask.new(spec) do |pkg|
|
68
70
|
pkg.need_tar = true
|
69
71
|
pkg.package_files += PKG_FILES
|
@@ -73,7 +75,7 @@ end
|
|
73
75
|
desc m = "Writing version information for #{PKG_VERSION}"
|
74
76
|
task :version do
|
75
77
|
puts m
|
76
|
-
File.open(File.join('lib',
|
78
|
+
File.open(File.join('lib', PKG_NAME, 'version.rb'), 'w') do |v|
|
77
79
|
v.puts <<EOT
|
78
80
|
class LazyList
|
79
81
|
# LazyList version
|
@@ -87,7 +89,8 @@ EOT
|
|
87
89
|
end
|
88
90
|
end
|
89
91
|
|
90
|
-
|
92
|
+
desc "Default"
|
93
|
+
task :default => [ :version, :gemspec, :test ]
|
91
94
|
|
92
|
-
|
93
|
-
|
95
|
+
desc "Prepare a release"
|
96
|
+
task :release => [ :clean, :version, :gemspec, :package ]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.2
|
data/doc-main.txt
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
== LazyList - Implementation of lazy lists for Ruby
|
2
|
+
|
3
|
+
=== Description
|
4
|
+
|
5
|
+
This class implements lazy lists (or streams) for Ruby. Such lists avoid the
|
6
|
+
computation of values which aren't needed for some computation. So it's
|
7
|
+
possible to define infinite lists with a limited amount of memory. A value
|
8
|
+
that hasn't been used yet is calculated on the fly and saved into the list.
|
9
|
+
A value which is used for a second time is computed only once and just read
|
10
|
+
out of memory for the second usage.
|
11
|
+
|
12
|
+
=== Author
|
13
|
+
|
14
|
+
Florian Frank mailto:flori@ping.de
|
15
|
+
|
16
|
+
=== License
|
17
|
+
|
18
|
+
This is free software; you can redistribute it and/or modify it under the
|
19
|
+
terms of the GNU General Public License Version 2 as published by the Free
|
20
|
+
Software Foundation: www.gnu.org/copyleft/gpl.html
|
21
|
+
|
22
|
+
=== Download
|
23
|
+
|
24
|
+
The latest version of this library can be downloaded at
|
25
|
+
|
26
|
+
* http://rubyforge.org/frs?group_id=394
|
27
|
+
|
28
|
+
The homepage of this library is located at
|
29
|
+
|
30
|
+
* http://lazylist.rubyforge.org
|
31
|
+
|
32
|
+
=== Example
|
33
|
+
|
34
|
+
To compute the square numbers with a lazy list you can define one as
|
35
|
+
|
36
|
+
sq = LazyList.tabulate(1) { |x| x * x }
|
37
|
+
|
38
|
+
or in the much nicer list builder syntax:
|
39
|
+
|
40
|
+
sq = list { x * x }.where :x => 1..Infinity
|
41
|
+
|
42
|
+
Now it's possible to get the first 10 square numbers by calling
|
43
|
+
LazyList#take
|
44
|
+
|
45
|
+
sq.take(10)
|
46
|
+
===>[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
|
47
|
+
|
48
|
+
To compute the first 10 square numbers and do something with them you can
|
49
|
+
call the each method with:
|
50
|
+
|
51
|
+
sq.each(10) { |x| puts x }
|
52
|
+
|
53
|
+
To compute every square number and do something with them you can call the
|
54
|
+
"each" method without an argument:
|
55
|
+
|
56
|
+
sq.each { |x| puts x }
|
57
|
+
|
58
|
+
Notice that calls to each without an argument will not return if applied to
|
59
|
+
infinite lazy lists.
|
60
|
+
|
61
|
+
You can also use indices on lazy lists to get the values at a certain range:
|
62
|
+
|
63
|
+
sq[ 0..9 ] or sq[0, 10]
|
64
|
+
===>[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
|
65
|
+
|
66
|
+
To spare memory it's possible to throw away every element after it was
|
67
|
+
fetched:
|
68
|
+
|
69
|
+
sq.take!(1) => [1]
|
70
|
+
sq.take!(1) => [4]
|
71
|
+
|
72
|
+
Of course it's also possible to compute more complex lists like the Fibonacci
|
73
|
+
sequence:
|
74
|
+
|
75
|
+
fib = LazyList.tabulate(0) { |x| x < 2 ? 1 : fib[x-2] + fib[x-1] }
|
76
|
+
|
77
|
+
fib[100] => 573147844013817084101
|
78
|
+
computes the 99th Fibonacci number. (We always start with index 0.)
|
79
|
+
fib[101] => 927372692193078999176
|
80
|
+
computes the 100th Fibonacci number. The already computed values are reused
|
81
|
+
to compute this result. That's a very transparent way to get memoization for
|
82
|
+
sequences that require heavy computation.
|
83
|
+
|
84
|
+
You can also use the zip method to create fib:
|
85
|
+
|
86
|
+
fib = list(1, 1) { fib.zip(fib.drop) { |a, b| a + b } }
|
87
|
+
|
88
|
+
Another way to create the Fibonacci sequence with the build method is this:
|
89
|
+
|
90
|
+
fib = list(1, 1) { build { a + b }.where(:a => fib, :b => fib.drop(1)) }
|
91
|
+
|
92
|
+
You can create lazy lists that are based on arbitrary Enumerables, so can for
|
93
|
+
example wrap your passwd file in one pretty easily:
|
94
|
+
|
95
|
+
pw = LazyList[ File.new("/etc/passwd") ]
|
96
|
+
|
97
|
+
Call grep to find the users root and flori:
|
98
|
+
pw.grep /^(root|flori):/ => ["root:x:0:0:...\n",... ]
|
99
|
+
|
100
|
+
In this case the whole passwd file is slurped into the memory. If
|
101
|
+
you use
|
102
|
+
pw.find { |x| x =~ /^root:/ } => "root:x:0:0:root:/root:/bin/bash\n"
|
103
|
+
instead, only every line until the root line is loaded into the memory.
|
104
|
+
|
105
|
+
To create more complex lazy lists, you can build them from already existing
|
106
|
+
lazy lists.
|
107
|
+
|
108
|
+
Natural numbers:
|
109
|
+
naturals = LazyList.from(1)
|
110
|
+
|
111
|
+
Odd Numbers > 100:
|
112
|
+
odds = list { x }.where(:x => naturals) { x % 2 === 1 && x > 100 }
|
113
|
+
|
114
|
+
Alternative definition of square numbers:
|
115
|
+
squares = build { odds[0, x].inject(0) { |s, y| s + y } }.where :x => naturals
|
116
|
+
|
117
|
+
=== References
|
118
|
+
|
119
|
+
A very good introduction into lazy lists can be found in the scheme bible
|
120
|
+
Structure and Interpretation of Computer Programs (SICP)
|
121
|
+
[http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-24.html#%25_sec_3.5]
|
data/examples/examples.rb
CHANGED
@@ -84,13 +84,18 @@ p me[66]
|
|
84
84
|
puts me.length
|
85
85
|
puts
|
86
86
|
|
87
|
-
|
87
|
+
|
88
88
|
p PI.take(10)
|
89
89
|
|
90
90
|
def window(l, n, m = 0)
|
91
91
|
list([ l.take(n) * '', m ]) { window(l.drop, n, m + 1) }
|
92
92
|
end
|
93
|
+
|
94
|
+
w = window(PI, 6)
|
95
|
+
index = w.find { |(x, i)| x == '999999' and break i }
|
96
|
+
puts "Found Feynman point #{PI.take_span(index, 6)} at #{index}!"
|
97
|
+
|
98
|
+
puts "Proof that PI is the number of the beast"
|
93
99
|
w = window(PI, 3)
|
94
100
|
index = w.find { |(x, i)| x == '666' and break i }
|
95
101
|
puts "Found #{PI.take_span(index, 3)} at #{index}!"
|
96
|
-
# vim: set et sw=2 ts=2:
|
data/examples/hamming.rb
CHANGED
data/examples/pi.rb
CHANGED
data/examples/sieve.rb
CHANGED
data/install.rb
CHANGED
data/lazylist.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.name = 'lazylist'
|
4
|
+
s.version = '0.3.2'
|
5
|
+
s.summary = "Implementation of lazy lists for Ruby"
|
6
|
+
s.description = ""
|
7
|
+
|
8
|
+
s.add_dependency('dslkit', '~> 0.2')
|
9
|
+
|
10
|
+
s.files = ["CHANGES", "COPYING", "README", "Rakefile", "VERSION", "examples", "examples/examples.rb", "examples/hamming.rb", "examples/pi.rb", "examples/sieve.rb", "install.rb", "lazylist.gemspec", "lib", "lib/lazylist", "lib/lazylist.rb", "lib/lazylist/enumerable.rb", "lib/lazylist/enumerator_queue.rb", "lib/lazylist/list_builder.rb", "lib/lazylist/thread_queue.rb", "lib/lazylist/version.rb", "make_doc.rb", "tests", "tests/runner.rb", "tests/test.rb", "tests/test_enumerable.rb"]
|
11
|
+
|
12
|
+
s.require_path = 'lib'
|
13
|
+
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.extra_rdoc_files << 'doc-main.txt'
|
16
|
+
s.rdoc_options << '--main' << 'doc-main.txt'
|
17
|
+
s.test_files << 'tests/runner.rb'
|
18
|
+
|
19
|
+
s.author = "Florian Frank"
|
20
|
+
s.email = "flori@ping.de"
|
21
|
+
s.homepage = "http://lazylist.rubyforge.org"
|
22
|
+
s.rubyforge_project = "lazylist"
|
23
|
+
end
|
data/lib/lazylist.rb
CHANGED
@@ -1,125 +1,3 @@
|
|
1
|
-
# = lazylist.rb - Implementation of lazy lists for Ruby
|
2
|
-
#
|
3
|
-
# == Description
|
4
|
-
#
|
5
|
-
# This class implements lazy lists (or streams) for Ruby. Such lists avoid the
|
6
|
-
# computation of values which aren't needed for some computation. So it's
|
7
|
-
# possible to define infinite lists with a limited amount of memory. A value
|
8
|
-
# that hasn't been used yet is calculated on the fly and saved into the list.
|
9
|
-
# A value which is used for a second time is computed only once and just read
|
10
|
-
# out of memory for the second usage.
|
11
|
-
#
|
12
|
-
# == Author
|
13
|
-
#
|
14
|
-
# Florian Frank mailto:flori@ping.de
|
15
|
-
#
|
16
|
-
# == License
|
17
|
-
#
|
18
|
-
# This is free software; you can redistribute it and/or modify it under the
|
19
|
-
# terms of the GNU General Public License Version 2 as published by the Free
|
20
|
-
# Software Foundation: www.gnu.org/copyleft/gpl.html
|
21
|
-
#
|
22
|
-
# == Download
|
23
|
-
#
|
24
|
-
# The latest version of this library can be downloaded at
|
25
|
-
#
|
26
|
-
# * http://rubyforge.org/frs?group_id=394
|
27
|
-
#
|
28
|
-
# The homepage of this library is located at
|
29
|
-
#
|
30
|
-
# * http://lazylist.rubyforge.org
|
31
|
-
#
|
32
|
-
# == Example
|
33
|
-
#
|
34
|
-
# To compute the square numbers with a lazy list you can define one as
|
35
|
-
#
|
36
|
-
# sq = LazyList.tabulate(1) { |x| x * x }
|
37
|
-
#
|
38
|
-
# or in the much nicer list builder syntax:
|
39
|
-
#
|
40
|
-
# sq = list { x * x }.where :x => 1..Infinity
|
41
|
-
#
|
42
|
-
# Now it's possible to get the first 10 square numbers by calling
|
43
|
-
# LazyList#take
|
44
|
-
#
|
45
|
-
# sq.take(10)
|
46
|
-
# ==>[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
|
47
|
-
#
|
48
|
-
# To compute the first 10 square numbers and do something with them you can
|
49
|
-
# call the each method with:
|
50
|
-
#
|
51
|
-
# sq.each(10) { |x| puts x }
|
52
|
-
#
|
53
|
-
# To compute every square number and do something with them you can call the
|
54
|
-
# "each" method without an argument:
|
55
|
-
#
|
56
|
-
# sq.each { |x| puts x }
|
57
|
-
#
|
58
|
-
# Notice that calls to each without an argument will not return if applied to
|
59
|
-
# infinite lazy lists.
|
60
|
-
#
|
61
|
-
# You can also use indices on lazy lists to get the values at a certain range:
|
62
|
-
#
|
63
|
-
# sq[ 0..9 ] or sq[0, 10]
|
64
|
-
# ==>[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
|
65
|
-
#
|
66
|
-
# To spare memory it's possible to throw away every element after it was
|
67
|
-
# fetched:
|
68
|
-
#
|
69
|
-
# sq.take!(1) => [1]
|
70
|
-
# sq.take!(1) => [4]
|
71
|
-
#
|
72
|
-
# Of course it's also possible to compute more complex lists like the Fibonacci
|
73
|
-
# sequence:
|
74
|
-
#
|
75
|
-
# fib = LazyList.tabulate(0) { |x| x < 2 ? 1 : fib[x-2] + fib[x-1] }
|
76
|
-
#
|
77
|
-
# fib[100] => 573147844013817084101
|
78
|
-
# computes the 99th Fibonacci number. (We always start with index 0.)
|
79
|
-
# fib[101] => 927372692193078999176
|
80
|
-
# computes the 100th Fibonacci number. The already computed values are reused
|
81
|
-
# to compute this result. That's a very transparent way to get memoization for
|
82
|
-
# sequences that require heavy computation.
|
83
|
-
#
|
84
|
-
# You can also use the zip method to create fib:
|
85
|
-
#
|
86
|
-
# fib = list(1, 1) { fib.zip(fib.drop) { |a, b| a + b } }
|
87
|
-
#
|
88
|
-
# Another way to create the Fibonacci sequence with the build method is this:
|
89
|
-
#
|
90
|
-
# fib = list(1, 1) { build { a + b }.where(:a => fib, :b => fib.drop(1)) }
|
91
|
-
#
|
92
|
-
# You can create lazy lists that are based on arbitrary Enumerables, so can for
|
93
|
-
# example wrap your passwd file in one pretty easily:
|
94
|
-
#
|
95
|
-
# pw = LazyList[ File.new("/etc/passwd") ]
|
96
|
-
#
|
97
|
-
# Call grep to find the users root and flori:
|
98
|
-
# pw.grep /^(root|flori):/ => ["root:x:0:0:...\n",... ]
|
99
|
-
#
|
100
|
-
# In this case the whole passwd file is slurped into the memory. If
|
101
|
-
# you use
|
102
|
-
# pw.find { |x| x =~ /^root:/ } => "root:x:0:0:root:/root:/bin/bash\n"
|
103
|
-
# instead, only every line until the root line is loaded into the memory.
|
104
|
-
#
|
105
|
-
# To create more complex lazy lists, you can build them from already existing
|
106
|
-
# lazy lists.
|
107
|
-
#
|
108
|
-
# Natural numbers:
|
109
|
-
# naturals = LazyList.from(1)
|
110
|
-
#
|
111
|
-
# Odd Numbers > 100:
|
112
|
-
# odds = list { x }.where(:x => naturals) { x % 2 == 1 && x > 100 }
|
113
|
-
#
|
114
|
-
# Alternative definition of square numbers:
|
115
|
-
# squares = build { odds[0, x].inject(0) { |s, y| s + y } }.where :x => naturals
|
116
|
-
#
|
117
|
-
# == References
|
118
|
-
#
|
119
|
-
# A very good introduction into lazy lists can be found in the scheme bible
|
120
|
-
# Structure and Interpretation of Computer Programs (SICP)
|
121
|
-
# [http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-24.html#%25_sec_3.5]
|
122
|
-
#
|
123
1
|
class LazyList
|
124
2
|
require 'dslkit'
|
125
3
|
require 'lazylist/list_builder'
|
@@ -131,64 +9,10 @@ class LazyList
|
|
131
9
|
# Exceptions raised by the LazyList implementation.
|
132
10
|
class Exception < ::StandardError; end
|
133
11
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
# Creates an ReadQueue object from an enumerable.
|
139
|
-
def initialize(enumerable)
|
140
|
-
@data = []
|
141
|
-
@producer = Thread.new do
|
142
|
-
Thread.stop
|
143
|
-
begin
|
144
|
-
enumerable.each do |value|
|
145
|
-
old, Thread.critical = Thread.critical, true
|
146
|
-
begin
|
147
|
-
@data << value
|
148
|
-
@consumer.wakeup
|
149
|
-
Thread.stop
|
150
|
-
ensure
|
151
|
-
Thread.critical = old
|
152
|
-
end
|
153
|
-
end
|
154
|
-
rescue => e
|
155
|
-
@consumer.raise e
|
156
|
-
ensure
|
157
|
-
@consumer.wakeup
|
158
|
-
end
|
159
|
-
end
|
160
|
-
Thread.pass until @producer.stop?
|
161
|
-
end
|
162
|
-
|
163
|
-
# Extracts the top element from the queue or nil if the queue is
|
164
|
-
# empty.
|
165
|
-
def shift
|
166
|
-
if empty?
|
167
|
-
nil
|
168
|
-
else
|
169
|
-
@data.shift
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
alias pop shift # for backwards compatibility
|
174
|
-
|
175
|
-
# Returns true if the queue is empty.
|
176
|
-
def empty?
|
177
|
-
if @data.empty?
|
178
|
-
old, Thread.critical = Thread.critical, true
|
179
|
-
begin
|
180
|
-
@consumer = Thread.current
|
181
|
-
@producer.wakeup
|
182
|
-
Thread.stop
|
183
|
-
rescue ThreadError
|
184
|
-
;
|
185
|
-
ensure
|
186
|
-
@consumer = nil
|
187
|
-
Thread.critical = old
|
188
|
-
end
|
189
|
-
end
|
190
|
-
@data.empty?
|
191
|
-
end
|
12
|
+
if defined?(::Enumerator)
|
13
|
+
require 'lazylist/enumerator_queue.rb'
|
14
|
+
else
|
15
|
+
require 'lazylist/thread_queue.rb'
|
192
16
|
end
|
193
17
|
|
194
18
|
Promise = DSLKit::BlankSlate.with :inspect, :to_s # :nodoc:
|
@@ -615,6 +439,8 @@ class LazyList
|
|
615
439
|
result
|
616
440
|
end
|
617
441
|
|
442
|
+
alias first take
|
443
|
+
|
618
444
|
# Takes the _range_ indexes of elements from this lazylist and returns them
|
619
445
|
# as an array.
|
620
446
|
def take_range(range)
|
@@ -648,6 +474,12 @@ class LazyList
|
|
648
474
|
each!(n) { }
|
649
475
|
end
|
650
476
|
|
477
|
+
# Return the last +n+ elements of the lazy list. This is only sensible if the
|
478
|
+
# lazy list is finite of course.
|
479
|
+
def last(n = 1)
|
480
|
+
to_a.last n
|
481
|
+
end
|
482
|
+
|
651
483
|
# Returns the size. This is only sensible if the lazy list is finite
|
652
484
|
# of course.
|
653
485
|
def size
|
@@ -825,6 +657,6 @@ class LazyList
|
|
825
657
|
end
|
826
658
|
|
827
659
|
include LazyList::ObjectMethods
|
660
|
+
include LazyList::Enumerable::ObjectMethods
|
828
661
|
end
|
829
662
|
end
|
830
|
-
# vim: set et sw=2 ts=2:
|
data/lib/lazylist/enumerable.rb
CHANGED
@@ -80,11 +80,16 @@ class LazyList
|
|
80
80
|
def select(&block)
|
81
81
|
block = All unless block
|
82
82
|
s = self
|
83
|
-
|
84
|
-
s
|
83
|
+
ended = catch(:end_list) do
|
84
|
+
until s.empty? or block[s.head]
|
85
|
+
s = s.tail
|
86
|
+
end
|
87
|
+
end
|
88
|
+
if s.empty? or ended == :end_list
|
89
|
+
empty
|
90
|
+
else
|
91
|
+
self.class.new(delay { s.head }) { s.tail.select(&block) }
|
85
92
|
end
|
86
|
-
return empty if s.empty?
|
87
|
-
self.class.new(delay { s.head }) { s.tail.select(&block) }
|
88
93
|
end
|
89
94
|
alias find_all select
|
90
95
|
|
@@ -108,5 +113,13 @@ class LazyList
|
|
108
113
|
warn "method 'mapper' is obsolete - use 'map'"
|
109
114
|
map(&f)
|
110
115
|
end
|
116
|
+
|
117
|
+
module ObjectMethods
|
118
|
+
# This method can be used to end a list in a predicate that is used to
|
119
|
+
# filter the lazy list via the select, reject, or partition method.
|
120
|
+
def end_list
|
121
|
+
throw :end_list, :end_list
|
122
|
+
end
|
123
|
+
end
|
111
124
|
end
|
112
125
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class LazyList
|
2
|
+
# ReadQueue is the implementation of an read-only queue that only supports
|
3
|
+
# #shift and #empty? methods. It's used as a wrapper to encapsulate
|
4
|
+
# enumerables in lazy lists.
|
5
|
+
class ReadQueue
|
6
|
+
# Creates an ReadQueue object from an enumerable.
|
7
|
+
def initialize(enumerable)
|
8
|
+
@enum = enumerable.to_enum
|
9
|
+
@empty = false
|
10
|
+
shift
|
11
|
+
end
|
12
|
+
|
13
|
+
# Extracts the top element from the queue or nil if the queue is empty.
|
14
|
+
def shift
|
15
|
+
if @empty
|
16
|
+
nil
|
17
|
+
else
|
18
|
+
result = @next
|
19
|
+
@next = @enum.next
|
20
|
+
result
|
21
|
+
end
|
22
|
+
rescue StopIteration
|
23
|
+
@next = nil
|
24
|
+
@empty = true
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
alias pop shift # for backwards compatibility
|
29
|
+
|
30
|
+
# Returns true if the queue is empty.
|
31
|
+
def empty?
|
32
|
+
!@next and @empty
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class LazyList
|
2
|
+
# ReadQueue is the implementation of an read-only queue that only supports
|
3
|
+
# #shift and #empty? methods. It's used as a wrapper to encapsulate
|
4
|
+
# enumerables in lazy lists.
|
5
|
+
class ReadQueue
|
6
|
+
# Creates an ReadQueue object from an enumerable.
|
7
|
+
def initialize(enumerable)
|
8
|
+
@data = []
|
9
|
+
@producer = Thread.new do
|
10
|
+
Thread.stop
|
11
|
+
begin
|
12
|
+
enumerable.each do |value|
|
13
|
+
old, Thread.critical = Thread.critical, true
|
14
|
+
begin
|
15
|
+
@data << value
|
16
|
+
@consumer.wakeup
|
17
|
+
Thread.stop
|
18
|
+
ensure
|
19
|
+
Thread.critical = old
|
20
|
+
end
|
21
|
+
end
|
22
|
+
rescue => e
|
23
|
+
@consumer.raise e
|
24
|
+
ensure
|
25
|
+
@consumer.wakeup
|
26
|
+
end
|
27
|
+
end
|
28
|
+
Thread.pass until @producer.stop?
|
29
|
+
end
|
30
|
+
|
31
|
+
# Extracts the top element from the queue or nil if the queue is
|
32
|
+
# empty.
|
33
|
+
def shift
|
34
|
+
if empty?
|
35
|
+
nil
|
36
|
+
else
|
37
|
+
@data.shift
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
alias pop shift # for backwards compatibility
|
42
|
+
|
43
|
+
# Returns true if the queue is empty.
|
44
|
+
def empty?
|
45
|
+
if @data.empty?
|
46
|
+
old, Thread.critical = Thread.critical, true
|
47
|
+
begin
|
48
|
+
@consumer = Thread.current
|
49
|
+
@producer.wakeup
|
50
|
+
Thread.stop
|
51
|
+
rescue ThreadError
|
52
|
+
;
|
53
|
+
ensure
|
54
|
+
@consumer = nil
|
55
|
+
Thread.critical = old
|
56
|
+
end
|
57
|
+
end
|
58
|
+
@data.empty?
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/lazylist/version.rb
CHANGED
data/make_doc.rb
CHANGED
data/tests/runner.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
require '
|
3
|
+
begin
|
4
|
+
require 'rubygems'
|
5
|
+
rescue LoadError
|
6
|
+
end
|
7
|
+
|
5
8
|
$:.unshift File.expand_path(File.dirname($0))
|
9
|
+
$:.unshift 'lib'
|
6
10
|
$:.unshift 'tests'
|
7
11
|
require 'test'
|
8
12
|
require 'test_enumerable'
|
@@ -14,5 +18,3 @@ class TS_AllTests
|
|
14
18
|
suite << TC_LazyEnumerable.suite
|
15
19
|
end
|
16
20
|
end
|
17
|
-
Test::Unit::UI::Console::TestRunner.run(TS_AllTests)
|
18
|
-
# vim: set et sw=2 ts=2:
|
data/tests/test.rb
CHANGED
@@ -82,40 +82,40 @@ class TC_LazyList < Test::Unit::TestCase
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def test_select
|
85
|
-
assert_equal 1, @odd[0]
|
86
|
-
assert_equal 3, @odd[1]
|
87
|
-
assert_equal 5, @odd[2]
|
85
|
+
assert_equal 1, @odd[0]
|
86
|
+
assert_equal 3, @odd[1]
|
87
|
+
assert_equal 5, @odd[2]
|
88
88
|
assert_equal [3, 5, 7], @odd.take_range(1..3)
|
89
89
|
assert_equal [3, 5, 7, 9], @odd.take_span(1, 4)
|
90
|
-
assert_equal
|
91
|
-
assert_equal
|
90
|
+
assert_equal((1..19).select(&@oddp), @odd[0, 10].to_a)
|
91
|
+
assert_equal((1..10).to_a, @natural[0, 10].to_a)
|
92
92
|
assert_equal [ 1 ] * 10, @ones[0, 10].to_a
|
93
93
|
ends_with_a = @strings.select { |x| x[-1] == ?a }
|
94
94
|
assert_equal ends_with_a[0, 27].to_a,
|
95
|
-
[ "a", ("a".."z").map { |x| x + "a" } ].flatten
|
95
|
+
[ "a", ("a".."z").map { |x| x + "a" } ].flatten
|
96
96
|
end
|
97
97
|
|
98
98
|
def test_map
|
99
99
|
id = @natural.map
|
100
|
-
assert_equal 1, id[0]
|
101
|
-
assert_equal 2, id[1]
|
102
|
-
assert_equal 3, id[2]
|
103
|
-
assert_equal
|
104
|
-
assert_equal
|
100
|
+
assert_equal 1, id[0]
|
101
|
+
assert_equal 2, id[1]
|
102
|
+
assert_equal 3, id[2]
|
103
|
+
assert_equal((1..10).to_a, id[0, 10].to_a)
|
104
|
+
assert_equal((1..10).to_a, @natural[0, 10].to_a)
|
105
105
|
squaredf = lambda { |x| x ** 2 }
|
106
106
|
squared = @natural.map(&squaredf)
|
107
|
-
assert_equal 1, squared[0]
|
108
|
-
assert_equal 4, squared[1]
|
109
|
-
assert_equal 9, squared[2]
|
110
|
-
assert_equal
|
111
|
-
assert_equal
|
112
|
-
strangef = lambda { |x| x * (x
|
107
|
+
assert_equal 1, squared[0]
|
108
|
+
assert_equal 4, squared[1]
|
109
|
+
assert_equal 9, squared[2]
|
110
|
+
assert_equal((1..10).map(&squaredf), squared[0, 10].to_a)
|
111
|
+
assert_equal((1..10).to_a, @natural[0, 10].to_a)
|
112
|
+
strangef = lambda { |x| x * (x.unpack('c').first - 'a'.unpack('c').first + 1) }
|
113
113
|
strange = @strings.map(&strangef)
|
114
|
-
assert_equal "a", strange[0]
|
115
|
-
assert_equal "bb", strange[1]
|
116
|
-
assert_equal "ccc", strange[2]
|
117
|
-
assert_equal
|
118
|
-
assert_equal
|
114
|
+
assert_equal "a", strange[0]
|
115
|
+
assert_equal "bb", strange[1]
|
116
|
+
assert_equal "ccc", strange[2]
|
117
|
+
assert_equal(("a".."z").map(&strangef), strange[0, 26].to_a)
|
118
|
+
assert_equal(("a".."z").to_a, @strings[0, 26].to_a)
|
119
119
|
end
|
120
120
|
|
121
121
|
def test_index
|
@@ -123,23 +123,23 @@ class TC_LazyList < Test::Unit::TestCase
|
|
123
123
|
assert_equal nil, Empty[0]
|
124
124
|
assert_equal nil, Empty[1]
|
125
125
|
assert @natural.cached?
|
126
|
-
assert_equal nil, @natural[-1]
|
127
|
-
assert_equal nil, @natural[-1]
|
128
|
-
assert_equal 1, @natural[0]
|
129
|
-
assert_equal 1, @natural[0]
|
130
|
-
assert_equal 2, @natural[1]
|
131
|
-
assert_equal 2, @natural[1]
|
132
|
-
assert_equal nil, @natural[-1, 10]
|
133
|
-
assert_equal
|
134
|
-
assert_equal
|
135
|
-
assert_equal
|
136
|
-
assert_equal
|
137
|
-
assert_equal
|
138
|
-
assert_equal
|
139
|
-
assert_equal
|
140
|
-
assert_equal
|
141
|
-
assert_equal
|
142
|
-
assert_equal
|
126
|
+
assert_equal nil, @natural[-1]
|
127
|
+
assert_equal nil, @natural[-1]
|
128
|
+
assert_equal 1, @natural[0]
|
129
|
+
assert_equal 1, @natural[0]
|
130
|
+
assert_equal 2, @natural[1]
|
131
|
+
assert_equal 2, @natural[1]
|
132
|
+
assert_equal nil, @natural[-1, 10]
|
133
|
+
assert_equal((1..10).to_a, @natural[0, 10].to_a)
|
134
|
+
assert_equal((6..15).to_a, @natural[5, 10].to_a)
|
135
|
+
assert_equal((1..1).to_a, @natural[0..0].to_a)
|
136
|
+
assert_equal((1..0).to_a, @natural[0..-1].to_a)
|
137
|
+
assert_equal((1...1).to_a, @natural[0...0].to_a)
|
138
|
+
assert_equal((1...0).to_a, @natural[0...-1].to_a)
|
139
|
+
assert_equal((1..10).to_a, @natural[0..9].to_a)
|
140
|
+
assert_equal((6..15).to_a, @natural[5..14].to_a)
|
141
|
+
assert_equal((1..10).to_a, @natural[0...10].to_a)
|
142
|
+
assert_equal((6..15).to_a, @natural[5...15].to_a)
|
143
143
|
end
|
144
144
|
|
145
145
|
def test_index_without_cache
|
@@ -149,25 +149,25 @@ class TC_LazyList < Test::Unit::TestCase
|
|
149
149
|
assert_equal nil, Empty[1]
|
150
150
|
@natural.cached = false
|
151
151
|
assert !@natural.cached?
|
152
|
-
assert_equal nil, @natural[-1]
|
153
|
-
assert_equal nil, @natural[-1]
|
154
|
-
assert_equal 1, @natural[0]
|
155
|
-
assert_equal 1, @natural[0]
|
156
|
-
assert_equal 2, @natural[1]
|
157
|
-
assert_equal 2, @natural[1]
|
158
|
-
assert_equal nil, @natural[-1, 10]
|
152
|
+
assert_equal nil, @natural[-1]
|
153
|
+
assert_equal nil, @natural[-1]
|
154
|
+
assert_equal 1, @natural[0]
|
155
|
+
assert_equal 1, @natural[0]
|
156
|
+
assert_equal 2, @natural[1]
|
157
|
+
assert_equal 2, @natural[1]
|
158
|
+
assert_equal nil, @natural[-1, 10]
|
159
159
|
end
|
160
160
|
|
161
161
|
def test_merge
|
162
162
|
natural = @even.merge(@odd)
|
163
|
-
assert_equal @natural[0, 10].to_a, natural[0, 10].to_a
|
163
|
+
assert_equal @natural[0, 10].to_a, natural[0, 10].to_a
|
164
164
|
natural = @odd.merge(@even)
|
165
|
-
assert_equal @natural[0, 10].to_a, natural[0, 10].to_a
|
165
|
+
assert_equal @natural[0, 10].to_a, natural[0, 10].to_a
|
166
166
|
double_list = @natural.merge(@natural) { |a,b| a <= b }
|
167
|
-
assert double_list[0, 10].to_a, (1..5).map { |x| [x, x] }.flatten
|
167
|
+
assert double_list[0, 10].to_a, (1..5).map { |x| [x, x] }.flatten
|
168
168
|
odd2 = @natural.select(&@oddp).drop(1)
|
169
169
|
some = @even.merge(odd2)
|
170
|
-
assert_equal @natural[1, 9].to_a, some[0, 9].to_a
|
170
|
+
assert_equal @natural[1, 9].to_a, some[0, 9].to_a
|
171
171
|
more_ones = @ones.merge(@ones)
|
172
172
|
assert_equal [1] * 10, more_ones.take(10)
|
173
173
|
end
|
@@ -183,17 +183,19 @@ class TC_LazyList < Test::Unit::TestCase
|
|
183
183
|
assert_equal [ 3, 5 ], @odd.take!(2)
|
184
184
|
assert_equal [ 7, 9, 11 ], @odd.take(3)
|
185
185
|
assert_equal [ 7, 9, 11 ], @odd.drop(0).take(3)
|
186
|
-
assert_equal [ 7, 9, 11 ], @odd.take(3)
|
187
|
-
assert_equal [ 9, 11, 13 ], @odd.drop(1).take(3)
|
188
|
-
assert_equal [ 7, 9, 11 ], @odd.take(3)
|
189
|
-
assert_equal [ 11, 13, 15 ], @odd.drop(2).take(3)
|
190
|
-
assert_equal [ 7, 9, 11 ], @odd.take(3)
|
186
|
+
assert_equal [ 7, 9, 11 ], @odd.take(3)
|
187
|
+
assert_equal [ 9, 11, 13 ], @odd.drop(1).take(3)
|
188
|
+
assert_equal [ 7, 9, 11 ], @odd.take(3)
|
189
|
+
assert_equal [ 11, 13, 15 ], @odd.drop(2).take(3)
|
190
|
+
assert_equal [ 7, 9, 11 ], @odd.take(3)
|
191
191
|
@odd.drop!(0)
|
192
|
-
assert_equal [ 7, 9, 11 ], @odd.take(3)
|
192
|
+
assert_equal [ 7, 9, 11 ], @odd.take(3)
|
193
193
|
@odd.drop!(1)
|
194
|
-
assert_equal [ 9, 11, 13 ], @odd.take(3)
|
194
|
+
assert_equal [ 9, 11, 13 ], @odd.take(3)
|
195
195
|
@odd.drop!(2)
|
196
|
-
assert_equal [ 13, 15, 17 ], @odd.take(3)
|
196
|
+
assert_equal [ 13, 15, 17 ], @odd.take(3)
|
197
|
+
assert_equal [ 13, 15, 17 ], @odd.first(3)
|
198
|
+
assert_equal [ 8, 9, 10 ], @finite10.last(3)
|
197
199
|
end
|
198
200
|
|
199
201
|
def test_io
|
@@ -209,30 +211,29 @@ class TC_LazyList < Test::Unit::TestCase
|
|
209
211
|
end
|
210
212
|
@tempfile10.close
|
211
213
|
@tempfile10_list = LazyList[File.new(@tempfile10.path)]
|
212
|
-
assert_equal 0, @tempfile0_list.size
|
213
|
-
assert_equal [], @tempfile0_list.to_a
|
214
|
-
assert_equal 10, @tempfile10_list.size
|
215
|
-
assert_equal
|
216
|
-
@tempfile10_list.to_a
|
214
|
+
assert_equal 0, @tempfile0_list.size
|
215
|
+
assert_equal [], @tempfile0_list.to_a
|
216
|
+
assert_equal 10, @tempfile10_list.size
|
217
|
+
assert_equal((1..10).map { |x| x.to_s + "\n" }, @tempfile10_list.to_a)
|
217
218
|
temp = LazyList.io(File.new(@tempfile0.path)) do |io|
|
218
219
|
io.readline
|
219
220
|
end
|
220
221
|
content = temp.inject([]) { |c, line| c << line }
|
221
|
-
assert_equal [], content
|
222
|
+
assert_equal [], content
|
222
223
|
temp = LazyList.io(File.new(@tempfile10.path)) do |io|
|
223
224
|
io.readline
|
224
225
|
end
|
225
226
|
content = temp.inject([]) { |c, line| c << line }
|
226
|
-
assert_equal
|
227
|
+
assert_equal((1..10).map { |x| x.to_s + "\n" }, content)
|
227
228
|
end
|
228
229
|
|
229
230
|
def test_construct_ref
|
230
231
|
assert_equal Empty, LazyList[0, -1]
|
231
232
|
assert_equal [0], LazyList[0, 1].to_a
|
232
|
-
assert_equal
|
233
|
+
assert_equal((0..9).to_a, LazyList[0, 10].to_a)
|
233
234
|
assert_equal Empty, LazyList[0..-1]
|
234
235
|
assert_equal [0], LazyList[0..0].to_a
|
235
|
-
assert_equal
|
236
|
+
assert_equal((0..9).to_a, LazyList[0..9].to_a)
|
236
237
|
end
|
237
238
|
|
238
239
|
def test_iterate
|
@@ -243,10 +244,10 @@ class TC_LazyList < Test::Unit::TestCase
|
|
243
244
|
5 * x + 1
|
244
245
|
end
|
245
246
|
end
|
246
|
-
assert_equal nil, f[-1]
|
247
|
-
assert_equal 5, f[0]
|
248
|
-
assert_equal 26, f[1]
|
249
|
-
assert_equal [5, 26, 13, 66, 33, 166, 83, 416], f[0, 8].to_a
|
247
|
+
assert_equal nil, f[-1]
|
248
|
+
assert_equal 5, f[0]
|
249
|
+
assert_equal 26, f[1]
|
250
|
+
assert_equal [5, 26, 13, 66, 33, 166, 83, 416], f[0, 8].to_a
|
250
251
|
a196 = LazyList.iterate(35) { |x| x + x.to_s.reverse.to_i }
|
251
252
|
assert_equal [35, 88, 176, 847, 1595, 7546, 14003, 44044, 88088, 176176],
|
252
253
|
a196.take(10)
|
@@ -254,24 +255,24 @@ class TC_LazyList < Test::Unit::TestCase
|
|
254
255
|
|
255
256
|
def test_inspect
|
256
257
|
l = LazyList[1..11]
|
257
|
-
assert_equal "[]", Empty.inspect
|
258
|
-
assert_equal "[... ]", l.inspect
|
258
|
+
assert_equal "[]", Empty.inspect
|
259
|
+
assert_equal "[... ]", l.inspect
|
259
260
|
l[0]
|
260
|
-
assert_equal "[1,... ]", l.inspect
|
261
|
+
assert_equal "[1,... ]", l.inspect
|
261
262
|
l[1]
|
262
|
-
assert_equal "[1, 2,... ]", l.inspect
|
263
|
+
assert_equal "[1, 2,... ]", l.inspect
|
263
264
|
l[2]
|
264
|
-
assert_equal "[1, 2, 3,... ]", l.inspect
|
265
|
+
assert_equal "[1, 2, 3,... ]", l.inspect
|
265
266
|
l[9]
|
266
|
-
assert_equal "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10,... ]", l.inspect
|
267
|
+
assert_equal "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10,... ]", l.inspect
|
267
268
|
l.to_a
|
268
|
-
assert_equal "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]", l.inspect
|
269
|
+
assert_equal "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]", l.inspect
|
269
270
|
end
|
270
271
|
|
271
272
|
def test_zip
|
272
273
|
combined = @natural.zip(@ones) { |x, y| x + y }
|
273
|
-
assert_equal
|
274
|
-
assert_equal
|
274
|
+
assert_equal((12..21).to_a, combined[10,10].to_a)
|
275
|
+
assert_equal((2..11).to_a, combined[0,10].to_a)
|
275
276
|
end
|
276
277
|
|
277
278
|
def from(n = 0)
|
@@ -304,10 +305,10 @@ class TC_LazyList < Test::Unit::TestCase
|
|
304
305
|
assert_equal Empty, @natural.sublist(-1)
|
305
306
|
assert_equal Empty, @natural.sublist(0)
|
306
307
|
assert_equal [1], @natural.sublist(1).to_a
|
307
|
-
assert_equal
|
308
|
-
assert_equal
|
309
|
-
assert_equal
|
310
|
-
assert_equal
|
308
|
+
assert_equal((1..10).to_a, @natural.sublist(10).to_a)
|
309
|
+
assert_equal((6..15).to_a, @natural[5, 10].to_a)
|
310
|
+
assert_equal((6..15).to_a, @natural[5..14].to_a)
|
311
|
+
assert_equal((6..14).to_a, @natural[5...14].to_a)
|
311
312
|
assert_equal nil, @natural.sublist(10)[10]
|
312
313
|
assert_equal 10, @natural.sublist(10)[9]
|
313
314
|
end
|
@@ -364,7 +365,7 @@ class TC_LazyList < Test::Unit::TestCase
|
|
364
365
|
assert_equal list, list * list
|
365
366
|
assert_equal list, list * list(1)
|
366
367
|
assert_equal list, list(1) * list
|
367
|
-
assert_equal list, list.cartesian_product
|
368
|
+
assert_equal list, list.cartesian_product
|
368
369
|
assert_equal [ [1, 1], [1, 2], [2, 1], [2, 2], [3, 1], [3, 2] ],
|
369
370
|
f.cartesian_product(g).to_a
|
370
371
|
assert_equal [[1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 2, 2], [2, 1, 1], [2, 1,
|
@@ -372,9 +373,9 @@ class TC_LazyList < Test::Unit::TestCase
|
|
372
373
|
assert_equal [1, 2, 2, 4, 2, 4, 4, 8],
|
373
374
|
g.cartesian_product(g, g, &lambda { |x,y,z| x * y * z }).to_a
|
374
375
|
assert_equal g.map { |x| x * x }, g.cartesian_product { |x| x * x }
|
375
|
-
l = list { [ x, y ] }.where :x => g, :y => g
|
376
|
+
l = list { [ x, y ] }.where :x => g, :y => g
|
376
377
|
assert_equal [ [ 1, 1 ], [ 1, 2 ], [ 2, 1 ], [ 2, 2 ] ], l.to_a.sort
|
377
|
-
l = list { [ x, y ] }.where :x => f, :y => g
|
378
|
+
l = list { [ x, y ] }.where :x => f, :y => g
|
378
379
|
assert_equal [ [ 1, 1 ], [ 1, 2 ], [ 2, 1 ], [ 2, 2 ], [ 3, 1 ], [ 3, 2 ] ], l.to_a.sort
|
379
380
|
l = list { [ x, y ] }.where(:x => f, :y => f) { x > y }
|
380
381
|
assert_equal [ [ 2, 1 ], [ 3, 1 ], [ 3, 2 ] ], l.to_a.sort
|
@@ -386,4 +387,3 @@ class TC_LazyList < Test::Unit::TestCase
|
|
386
387
|
assert_equal [ 7, 11, 8, 15, 12, 16, 9, 19, 17, 21, 13, 20, 22, 10, 18, 14 ].sort, test.to_a.sort
|
387
388
|
end
|
388
389
|
end
|
389
|
-
# vim: set et sw=2 ts=2:
|
data/tests/test_enumerable.rb
CHANGED
@@ -91,5 +91,14 @@ class TC_LazyEnumerable < Test::Unit::TestCase
|
|
91
91
|
assert_equal [2, 4], even.take(5)
|
92
92
|
assert_equal [1, 3, 5], odd.take(5)
|
93
93
|
end
|
94
|
+
|
95
|
+
def test_select
|
96
|
+
fib = list(1, 1) { build { a + b }.where(:a => fib, :b => fib.drop(1)) }
|
97
|
+
fib_small = fib.select { |x| x <= 4_000_000 or end_list }
|
98
|
+
even_fib_small = fib_small.select { |x| x % 2 == 0 }
|
99
|
+
assert_equal [ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 ], fib_small.first(10)
|
100
|
+
assert_equal [ 2, 8, 34, 144, 610, 2584, 10946, 46368, 196418, 832040 ], even_fib_small.first(10)
|
101
|
+
assert_equal [ 2, 8, 34, 144, 610, 2584, 10946, 46368, 196418, 832040, 3524578 ], even_fib_small.first(11)
|
102
|
+
assert_equal [ 2, 8, 34, 144, 610, 2584, 10946, 46368, 196418, 832040, 3524578 ], even_fib_small.first(12)
|
103
|
+
end
|
94
104
|
end
|
95
|
-
# vim: set et sw=2 ts=2:
|
metadata
CHANGED
@@ -1,82 +1,86 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.4
|
3
|
-
specification_version: 1
|
4
2
|
name: lazylist
|
5
3
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.3.
|
7
|
-
date: 2007-11-27 00:00:00 +01:00
|
8
|
-
summary: Implementation of lazy lists for Ruby
|
9
|
-
require_paths:
|
10
|
-
- lib
|
11
|
-
email: flori@ping.de
|
12
|
-
homepage: http://lazylist.rubyforge.org
|
13
|
-
rubyforge_project: lazylist
|
14
|
-
description: ""
|
15
|
-
autorequire:
|
16
|
-
default_executable:
|
17
|
-
bindir: bin
|
18
|
-
has_rdoc: true
|
19
|
-
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.0.0
|
24
|
-
version:
|
4
|
+
version: 0.3.2
|
25
5
|
platform: ruby
|
26
|
-
signing_key:
|
27
|
-
cert_chain:
|
28
|
-
post_install_message:
|
29
6
|
authors:
|
30
7
|
- Florian Frank
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-25 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: dslkit
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0.2"
|
24
|
+
version:
|
25
|
+
description: ""
|
26
|
+
email: flori@ping.de
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- doc-main.txt
|
31
33
|
files:
|
34
|
+
- CHANGES
|
35
|
+
- COPYING
|
36
|
+
- README
|
37
|
+
- Rakefile
|
38
|
+
- VERSION
|
39
|
+
- examples/examples.rb
|
40
|
+
- examples/hamming.rb
|
41
|
+
- examples/pi.rb
|
42
|
+
- examples/sieve.rb
|
32
43
|
- install.rb
|
33
|
-
-
|
34
|
-
- lib/lazylist
|
35
|
-
- lib/lazylist/list_builder.rb
|
44
|
+
- lazylist.gemspec
|
45
|
+
- lib/lazylist.rb
|
36
46
|
- lib/lazylist/enumerable.rb
|
47
|
+
- lib/lazylist/enumerator_queue.rb
|
48
|
+
- lib/lazylist/list_builder.rb
|
49
|
+
- lib/lazylist/thread_queue.rb
|
37
50
|
- lib/lazylist/version.rb
|
38
|
-
- lib/lazylist.rb
|
39
51
|
- make_doc.rb
|
40
|
-
- CHANGES
|
41
|
-
- README.en
|
42
|
-
- VERSION
|
43
|
-
- tests
|
44
52
|
- tests/runner.rb
|
45
53
|
- tests/test.rb
|
46
54
|
- tests/test_enumerable.rb
|
47
|
-
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
- examples/examples.rb
|
54
|
-
test_files:
|
55
|
-
- tests/test.rb
|
55
|
+
- doc-main.txt
|
56
|
+
has_rdoc: true
|
57
|
+
homepage: http://lazylist.rubyforge.org
|
58
|
+
licenses: []
|
59
|
+
|
60
|
+
post_install_message:
|
56
61
|
rdoc_options:
|
57
|
-
- --title
|
58
|
-
- LazyList -- Infinite lists in Ruby
|
59
62
|
- --main
|
60
|
-
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
-
|
66
|
-
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
63
|
+
- doc-main.txt
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: "0"
|
71
|
+
version:
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
version:
|
71
78
|
requirements: []
|
72
79
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
- !ruby/object:Gem::Version
|
81
|
-
version: 0.2.2
|
82
|
-
version:
|
80
|
+
rubyforge_project: lazylist
|
81
|
+
rubygems_version: 1.3.2
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: Implementation of lazy lists for Ruby
|
85
|
+
test_files:
|
86
|
+
- tests/runner.rb
|