lazylist 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,112 @@
1
+ class LazyList
2
+ module Enumerable
3
+ include ::Enumerable
4
+
5
+ # Returns two lazy lists, the first containing the elements of this lazy
6
+ # list for which the block evaluates to true, the second containing the
7
+ # rest.
8
+ def partition(&block)
9
+ return select(&block), reject(&block)
10
+ end
11
+
12
+ # Returns a sorted version of this lazy list. This method should only be
13
+ # called on finite lazy lists or it will never return. Also see
14
+ # Enumerable#sort.
15
+ def sort # :yields: a, b
16
+ LazyList.from_enum(super)
17
+ end
18
+
19
+ # Returns a sorted version of this lazy list. This method should only be
20
+ # called on finite lazy lists or it will never return. Also see
21
+ # Enumerable#sort_by.
22
+ def sort_by # :yields: obj
23
+ LazyList.from_enum(super)
24
+ end
25
+
26
+ # Calls _block_ with two arguments, the element and its index, for each
27
+ # element of this lazy list. If _block_ isn't given, the method returns a
28
+ # lazy list that consists of [ element, index ] pairs instead.
29
+ def each_with_index(&block)
30
+ if block
31
+ each_with_index.each { |x| block[x] }
32
+ else
33
+ i = -1
34
+ map { |x| [ x, i += 1 ] }
35
+ end
36
+ end
37
+
38
+ # Returns the lazy list, that contains all the given _block_'s return
39
+ # values, if it was called on every
40
+ # self[i], others[0][i], others[1][i],... others[others.size - 1][i]
41
+ # for i in 0..Infinity. If _block_ wasn't given
42
+ # this result will be the array
43
+ # [self[i], others[0][i], others[1][i],... ]
44
+ # and a lazy list of those arrays is returned.
45
+ def zip(*others, &block)
46
+ if empty? or others.any? { |o| o.empty? }
47
+ empty
48
+ else
49
+ block ||= Tuple
50
+ self.class.new(delay { block[head, *others.map { |o| o.head }] }) do
51
+ tail.zip(*others.map { |o| o.tail }, &block)
52
+ end
53
+ end
54
+ end
55
+
56
+ # obsoleted by #zip
57
+ def combine(other, &operator)
58
+ warn "method 'combine' is obsolete - use 'zip'"
59
+ zip(other, &operator)
60
+ end
61
+
62
+ # Returns a lazy list every element of this lazy list for which
63
+ # pattern === element is true. If the optional _block_ is supplied,
64
+ # each matching element is passed to it, and the block's result becomes
65
+ # an element of the returned lazy list.
66
+ def grep(pattern, &block)
67
+ result = select { |x| pattern === x }
68
+ block and result = result.map(&block)
69
+ result
70
+ end
71
+
72
+ # Returns a lazy list of all elements of this lazy list for which the block
73
+ # is false (see also +Lazylist#select+).
74
+ def reject
75
+ select { |obj| !yield(obj) }
76
+ end
77
+
78
+ # Returns a lazy list of all elements of this lazy list for which _block_
79
+ # is true.
80
+ def select(&block)
81
+ block = All unless block
82
+ s = self
83
+ until s.empty? or block[s.head]
84
+ s = s.tail
85
+ end
86
+ return empty if s.empty?
87
+ self.class.new(delay { s.head }) { s.tail.select(&block) }
88
+ end
89
+ alias find_all select
90
+
91
+ # obsoleted by #select
92
+ def filter(&p)
93
+ warn "method 'filter' is obsolete - use 'select'"
94
+ select(&p)
95
+ end
96
+
97
+ # Creates a new Lazylist that maps the block or Proc object f to every
98
+ # element in the old list.
99
+ def map(&f)
100
+ return empty if empty?
101
+ f = Identity unless f
102
+ self.class.new(delay { f[head] }) { tail.map(&f) }
103
+ end
104
+ alias collect map
105
+
106
+ # obsoleted by #map
107
+ def mapper(&f)
108
+ warn "method 'mapper' is obsolete - use 'map'"
109
+ map(&f)
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,137 @@
1
+ require 'dslkit'
2
+
3
+ class LazyList
4
+ def do_build(lb, others) # :nodoc:
5
+ if empty? or others.any? { |o| o.empty? }
6
+ Empty
7
+ else
8
+ variables = [ head ].concat others.map { |o| o.head }
9
+ if lb.filter
10
+ if lb.filter[*variables]
11
+ self.class.new(lb.transform[*variables]) do
12
+ tail.do_build(lb, others.map { |o| o.tail })
13
+ end
14
+ else
15
+ tail.do_build(lb, others.map { |o| o.tail })
16
+ end
17
+ else
18
+ self.class.new(lb.transform[*variables]) do
19
+ tail.do_build(lb, others.map { |o| o.tail })
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ def do_comprehend(lb, others) # :nodoc:
26
+ if lb.filter
27
+ cartesian_product(*others).select do |variables|
28
+ lb.filter[*variables]
29
+ end.map do |variables|
30
+ lb.transform[*variables]
31
+ end
32
+ else
33
+ cartesian_product(*others).map do |variables|
34
+ lb.transform[*variables]
35
+ end
36
+ end
37
+ end
38
+
39
+ # This class encapsulates a list builder (ListBuilder), that can be transformed
40
+ # into a LazyList, by calling LazyList::ListBuilder#where.
41
+ class ListBuilder
42
+ # This class is a special kind of Proc object, that uses instance_eval to
43
+ # execute a code block.
44
+ class ListBuilderProc < Proc
45
+ include DSLKit::MethodMissingDelegator
46
+ include DSLKit::BlockSelf
47
+
48
+ # Creates a ListBuilderProc working on the list builder _lb_ using the Proc
49
+ # returned by lb.#{name}. _name_ has to be either :filter or :transform.
50
+ def initialize(lb, name, &block)
51
+ @name = name
52
+ @lb = lb
53
+ @method_missing_delegator = block_self(&block)
54
+ super(&@lb.__send__(@name))
55
+ end
56
+
57
+ # Call this ListBuilderProc instance with the arguments _args_, which have to be
58
+ # the ordered values of the variables.
59
+ def call(*args)
60
+ prepare_variables
61
+ @lb.variables.each_with_index do |var, i|
62
+ instance_variable_set "@#{var}", args[i]
63
+ end
64
+ instance_eval(&@lb.__send__(@name))
65
+ end
66
+ alias [] call
67
+
68
+ private
69
+
70
+ def prepare_variables
71
+ @variables_prepared and return
72
+ variables = @lb.variables
73
+ class << self; self; end.instance_eval do
74
+ attr_reader(*variables)
75
+ end
76
+ @variables_prepared = true
77
+ end
78
+ end
79
+
80
+ # Creates LazyList::ListBuilder instance. _mode_ has to be either :do_build
81
+ # or :do_comprehend.
82
+ def initialize(mode, &block)
83
+ @mode = mode
84
+ @transform = ListBuilderProc.new(self, :transform, &block)
85
+ end
86
+
87
+ # The variable names defined in this list builder.
88
+ attr_reader :variables
89
+
90
+ # The transform ListBuilderProc instance of this list builder.
91
+ attr_reader :transform
92
+
93
+ # The filter ListBuilderProc of this list builder or nil.
94
+ attr_reader :filter
95
+
96
+ # This method creates a LazyList instance from this list builder,
97
+ # using the _sources_ hash to fetch the variables from. _sources_ consists
98
+ # of the variable name and the values, that can be LazyList instances or
99
+ # otherwise they will be transformed into a LazyList with LazyList.[].
100
+ #
101
+ # It also takes a block, to filter the results by a boolean expression.
102
+ def where(sources = {}, &block)
103
+ @variables = []
104
+ generators = []
105
+ sources.each do |var, src|
106
+ @variables << var
107
+ generators << (src.is_a?(LazyList) ? src : LazyList[src])
108
+ end
109
+ if block_given?
110
+ @filter = ListBuilderProc.new(self, :filter, &block)
111
+ else
112
+ @filter = nil
113
+ end
114
+ generators.first.__send__(@mode, self, generators[1..-1])
115
+ end
116
+
117
+ # Return a (not much) nicer string representation of the list
118
+ # builder.
119
+ def to_s
120
+ "#<LazyList::ListBuilder>"
121
+ end
122
+ alias inspect to_s
123
+
124
+ class << self
125
+ # Used to support the build method
126
+ def create_build(&block)
127
+ new(:do_build, &block)
128
+ end
129
+
130
+ # Used to evaluate a list comprehension, usually if calling the list
131
+ # method with only a block.
132
+ def create_comprehend(&block)
133
+ new(:do_comprehend, &block)
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,8 @@
1
+ class LazyList
2
+ # LazyList version
3
+ VERSION = '0.3.0'
4
+ VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
5
+ VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
+ VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
7
+ VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
8
+ end
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  puts "Creating documentation."
4
- system "rdoc -d lib/lazylist.rb"
4
+ system "rdoc -d #{Dir['lib/**/*.rb'] * ' '}"
5
5
  # vim: set et sw=2 ts=2:
@@ -3,12 +3,7 @@
3
3
  require 'test/unit/ui/console/testrunner'
4
4
  require 'test/unit/testsuite'
5
5
  $:.unshift File.expand_path(File.dirname($0))
6
- $:.unshift 'lib'
7
- $:.unshift '../lib'
8
- begin
9
- require 'coverage'
10
- rescue LoadError
11
- end
6
+ $:.unshift 'tests'
12
7
  require 'test'
13
8
  require 'test_enumerable'
14
9
 
@@ -67,6 +67,7 @@ class TC_LazyList < Test::Unit::TestCase
67
67
  assert_equal @finite_inner1.to_a, @finite1.to_a
68
68
  assert_equal @finite_inner10.to_a, @finite10.to_a
69
69
  assert_equal @finite_span_generated, @finite_span.to_a
70
+ assert_equal @finite_span_generated, LazyList["A"..."K"].to_a
70
71
  end
71
72
 
72
73
  def test_size
@@ -84,6 +85,8 @@ class TC_LazyList < Test::Unit::TestCase
84
85
  assert_equal 1, @odd[0]
85
86
  assert_equal 3, @odd[1]
86
87
  assert_equal 5, @odd[2]
88
+ assert_equal [3, 5, 7], @odd.take_range(1..3)
89
+ assert_equal [3, 5, 7, 9], @odd.take_span(1, 4)
87
90
  assert_equal (1..19).select(&@oddp), @odd[0, 10].to_a
88
91
  assert_equal (1..10).to_a, @natural[0, 10].to_a
89
92
  assert_equal [ 1 ] * 10, @ones[0, 10].to_a
@@ -244,11 +247,16 @@ class TC_LazyList < Test::Unit::TestCase
244
247
  assert_equal 5, f[0]
245
248
  assert_equal 26, f[1]
246
249
  assert_equal [5, 26, 13, 66, 33, 166, 83, 416], f[0, 8].to_a
250
+ a196 = LazyList.iterate(35) { |x| x + x.to_s.reverse.to_i }
251
+ assert_equal [35, 88, 176, 847, 1595, 7546, 14003, 44044, 88088, 176176],
252
+ a196.take(10)
247
253
  end
248
254
 
249
255
  def test_inspect
250
256
  l = LazyList[1..11]
251
257
  assert_equal "[]", Empty.inspect
258
+ assert_equal "[... ]", l.inspect
259
+ l[0]
252
260
  assert_equal "[1,... ]", l.inspect
253
261
  l[1]
254
262
  assert_equal "[1, 2,... ]", l.inspect
@@ -284,10 +292,12 @@ class TC_LazyList < Test::Unit::TestCase
284
292
  assert_equal [1, 3, 5, 7, 9, 11, 13, 15, 17, 19], o.take(10)
285
293
  assert_equal @odd.take(10), o.take(10)
286
294
  ones = list(1) { ones }
295
+ assert_equal '[... ]', ones.inspect
287
296
  assert_equal 1, ones.head
288
297
  assert_equal '[1,... ]', ones.inspect
289
298
  assert_equal [ 1 ] * 10 , ones.take(10)
290
299
  assert_equal '[1,... ]', ones.inspect
300
+ assert_equal [:foo], LazyList[:foo].to_a
291
301
  end
292
302
 
293
303
  def test_sublist
@@ -324,5 +334,56 @@ class TC_LazyList < Test::Unit::TestCase
324
334
  assert_equal [1, 2, 3] + [5, 6, 7] + [9, 10, 11, 12],
325
335
  l1.append(l2, l3).take(10)
326
336
  end
337
+
338
+ def test_list_builder
339
+ lb = build { y * x }
340
+ assert_kind_of LazyList::ListBuilder, lb
341
+ assert_equal "#<LazyList::ListBuilder>", lb.to_s
342
+ l = lb.where :x => 1..10, :y => 'a'..'j' do
343
+ x % 2 == 0 && y < 'j'
344
+ end
345
+ assert_kind_of LazyList, l
346
+ assert_equal ["bb", "dddd", "ffffff", "hhhhhhhh"], l.to_a
347
+ l = build { y * x }.where :x => 1..10, :y => 'a'..'j'
348
+ assert_equal ["a", "bb", "ccc", "dddd", "eeeee", "ffffff", "ggggggg",
349
+ "hhhhhhhh", "iiiiiiiii", "jjjjjjjjjj"], l.to_a
350
+ end
351
+
352
+ def twice(x)
353
+ 2 * x
354
+ end
355
+
356
+ def test_list_comprehend
357
+ f = LazyList[1..3]
358
+ g = LazyList[1..2]
359
+ assert_equal [ ], LazyList.mix(LazyList::Empty).to_a
360
+ assert_equal [ ], LazyList.mix(LazyList::Empty, LazyList::Empty).to_a
361
+ assert_equal [ 1 ], LazyList.mix(list(1), LazyList::Empty).to_a
362
+ assert_equal [ 1 ], LazyList.mix(LazyList::Empty, list(1)).to_a
363
+ assert_equal [ 1, 1, 2, 2, 3 ], LazyList.mix(f, g).to_a
364
+ assert_equal list, list * list
365
+ assert_equal list, list * list(1)
366
+ assert_equal list, list(1) * list
367
+ assert_equal list, list.cartesian_product
368
+ assert_equal [ [1, 1], [1, 2], [2, 1], [2, 2], [3, 1], [3, 2] ],
369
+ f.cartesian_product(g).to_a
370
+ assert_equal [[1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 2, 2], [2, 1, 1], [2, 1,
371
+ 2], [2, 2, 1], [2, 2, 2]], g.cartesian_product(g, g).to_a
372
+ assert_equal [1, 2, 2, 4, 2, 4, 4, 8],
373
+ g.cartesian_product(g, g, &lambda { |x,y,z| x * y * z }).to_a
374
+ assert_equal g.map { |x| x * x }, g.cartesian_product { |x| x * x }
375
+ l = list { [ x, y ] }.where :x => g, :y => g
376
+ 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
+ assert_equal [ [ 1, 1 ], [ 1, 2 ], [ 2, 1 ], [ 2, 2 ], [ 3, 1 ], [ 3, 2 ] ], l.to_a.sort
379
+ l = list { [ x, y ] }.where(:x => f, :y => f) { x > y }
380
+ assert_equal [ [ 2, 1 ], [ 3, 1 ], [ 3, 2 ] ], l.to_a.sort
381
+ l = list { [ x, y ] }.where(:x => f, :y => f) { x <= y }
382
+ assert_equal [ [1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3] ], l.to_a.sort
383
+ test = list { x * y }.where :x => 1..4, :y => list(3, 5, 7, 9)
384
+ assert_equal [ 3, 5, 6, 7, 10, 14, 9, 9, 21, 27, 15, 18, 36, 12, 28, 20 ].sort, test.to_a.sort
385
+ test = list { x + twice(y) }.where :x => 1..4, :y => list(3, 5, 7, 9)
386
+ assert_equal [ 7, 11, 8, 15, 12, 16, 9, 19, 17, 21, 13, 20, 22, 10, 18, 14 ].sort, test.to_a.sort
387
+ end
327
388
  end
328
389
  # vim: set et sw=2 ts=2:
metadata CHANGED
@@ -3,62 +3,79 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: lazylist
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.2.2
7
- date: 2005-12-23 00:00:00 +01:00
6
+ version: 0.3.0
7
+ date: 2007-05-05 00:00:00 +02:00
8
8
  summary: Implementation of lazy lists for Ruby
9
9
  require_paths:
10
- - lib
10
+ - lib
11
11
  email: flori@ping.de
12
12
  homepage: http://lazylist.rubyforge.org
13
13
  rubyforge_project: lazylist
14
- description: ''
15
- autorequire: lazylist
14
+ description: ""
15
+ autorequire:
16
16
  default_executable:
17
17
  bindir: bin
18
18
  has_rdoc: true
19
19
  required_ruby_version: !ruby/object:Gem::Version::Requirement
20
20
  requirements:
21
- -
22
- - ">"
23
- - !ruby/object:Gem::Version
24
- version: 0.0.0
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
25
24
  version:
26
25
  platform: ruby
27
26
  signing_key:
28
27
  cert_chain:
29
28
  authors:
30
- - Florian Frank
29
+ - Florian Frank
31
30
  files:
32
- - examples
33
- - install.rb
34
- - GPL
35
- - TODO
36
- - Rakefile
37
- - VERSION
38
- - tests
39
- - CHANGES
40
- - lib
41
- - make_doc.rb
42
- - README.en
43
- - examples/hamming.rb
44
- - examples/sieve.rb
45
- - examples/pi.rb
46
- - examples/examples.rb
47
- - tests/test.rb
48
- - tests/test_enumerable.rb
49
- - tests/runner.rb
50
- - lib/lazylist.rb
31
+ - VERSION
32
+ - tests
33
+ - GPL
34
+ - README.en
35
+ - install.rb
36
+ - Rakefile
37
+ - examples
38
+ - lib
39
+ - make_doc.rb
40
+ - CHANGES
41
+ - tests/runner.rb
42
+ - tests/test.rb
43
+ - tests/test_enumerable.rb
44
+ - examples/pi.rb
45
+ - examples/hamming.rb
46
+ - examples/examples.rb
47
+ - examples/sieve.rb
48
+ - lib/lazylist.rb
49
+ - lib/lazylist
50
+ - lib/lazylist/list_builder.rb
51
+ - lib/lazylist/enumerable.rb
52
+ - lib/lazylist/version.rb
51
53
  test_files:
52
- - tests/test.rb
54
+ - tests/test.rb
53
55
  rdoc_options:
54
- - "--title"
55
- - "LazyList -- Infinite lists in Ruby"
56
- - "--main"
57
- - LazyList
58
- - "--line-numbers"
56
+ - --title
57
+ - LazyList -- Infinite lists in Ruby
58
+ - --main
59
+ - LazyList
60
+ - --line-numbers
59
61
  extra_rdoc_files:
60
- - lib/lazylist.rb
62
+ - lib/lazylist.rb
63
+ - lib/lazylist/list_builder.rb
64
+ - lib/lazylist/enumerable.rb
65
+ - lib/lazylist/version.rb
61
66
  executables: []
67
+
62
68
  extensions: []
69
+
63
70
  requirements: []
64
- dependencies: []
71
+
72
+ dependencies:
73
+ - !ruby/object:Gem::Dependency
74
+ name: dslkit
75
+ version_requirement:
76
+ version_requirements: !ruby/object:Gem::Version::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: 0.2.2
81
+ version: