lazylist 0.2.2 → 0.3.0

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.
@@ -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: