lazily 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTE1ODg4ZDgzNDFjMTc0YzlhMWE0ODU5MWRmNjcyYzQyMTNkMGNmYw==
5
+ data.tar.gz: !binary |-
6
+ MDlhZjZhMWI5ZDNiMDdmMzk3OWU4NGM4MGVmYzhlODUyMzEyYzg3Ng==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NWNkYWNkOTViODA2OWM0ZWM1NWJkNTlhY2Y2NWUwNmQ0NGQ1MjZiZjFkODgz
10
+ MGFiYjRlYmZjYTQzZDkyYjMyMzFhYjU1ZTE3Y2JmMTMwZWEwMzBhYWFhZDIw
11
+ Nzg3Y2I0MjUyYzQzOTJkOTg2MmI4NjdlZmQ0MTkwZTkzMzA2YTY=
12
+ data.tar.gz: !binary |-
13
+ OGQ5ZTBhZTgyNTUwOTc3NTEwOGE3MTgwMmM0OWFiZjBiZDY1ZGJjYWRlMDJl
14
+ YTM2NmY5ZmYzMGRhNDI3Yjk4NTgwYTU5MTdmYjllM2U4Y2M0ZDVlODM1ZTI1
15
+ MThmOTkyZDNhZDNjNDVkYWVkZjBmMDJmMGEwMGZjMGRiZTAxYzI=
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - jruby-18mode
7
+ - jruby-19mode
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "rake", "~> 10.0.0"
6
+ gem "rspec", "~> 2.13.0"
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require "rake"
2
+
3
+ require "bundler"
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ require "rspec/core/rake_task"
7
+
8
+ RSpec::Core::RakeTask.new do |t|
9
+ t.rspec_opts = ["--format", "nested"]
10
+ end
11
+
12
+ task "default" => "spec"
data/lazily.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ $:.push File.expand_path("../lib", __FILE__)
4
+ require "lazily/version"
5
+
6
+ Gem::Specification.new do |s|
7
+
8
+ s.name = "lazily"
9
+ s.version = Lazily::VERSION.dup
10
+ s.platform = Gem::Platform::RUBY
11
+ s.authors = ["Mike Williams"]
12
+ s.email = "mdub@dogbiscuit.org"
13
+ s.homepage = "http://github.com/mdub/lazily"
14
+
15
+ s.summary = %{Lazy Enumerables for everybody!}
16
+ s.description = <<-EOT
17
+ Lazily implements "lazy" versions of many Enumerable methods,
18
+ allowing streamed processing of large (or even infinite) collections.
19
+
20
+ It's equivalent to Ruby-2.x's Enumerable#lazy, but is implemented in
21
+ pure Ruby, and works even in Ruby-1.8.x.
22
+ EOT
23
+
24
+ s.files = `git ls-files`.split("\n")
25
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
+ s.require_paths = ["lib"]
27
+
28
+ end
data/lib/lazily.rb ADDED
@@ -0,0 +1,4 @@
1
+ require "lazily/combining"
2
+ require "lazily/filtering"
3
+ require "lazily/proxy"
4
+ require "lazily/threading"
@@ -0,0 +1,3 @@
1
+ require "lazily/concatenating"
2
+ require "lazily/merging"
3
+ require "lazily/zipping"
@@ -0,0 +1,37 @@
1
+ require "lazily/enumerable"
2
+
3
+ module Lazily
4
+
5
+ class << self
6
+
7
+ def concat(*enumerables)
8
+ Concatenator.new(enumerables)
9
+ end
10
+
11
+ end
12
+
13
+ module Enumerable
14
+
15
+ def concat(*others)
16
+ Lazily.concat(self, *others)
17
+ end
18
+
19
+ end
20
+
21
+ class Concatenator
22
+
23
+ include Lazily::Enumerable
24
+
25
+ def initialize(enumerables)
26
+ @enumerables = enumerables
27
+ end
28
+
29
+ def each(&block)
30
+ @enumerables.each do |enumerable|
31
+ enumerable.each(&block)
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,13 @@
1
+ module Lazily
2
+
3
+ module Enumerable
4
+
5
+ include ::Enumerable
6
+
7
+ def lazy?
8
+ true
9
+ end
10
+
11
+ end
12
+
13
+ end
@@ -0,0 +1,118 @@
1
+ require "lazily/enumerable"
2
+
3
+ module Lazily
4
+
5
+ module Enumerable
6
+
7
+ def collect
8
+ Filter.new do |output|
9
+ each do |element|
10
+ output.call yield(element)
11
+ end
12
+ end
13
+ end
14
+
15
+ alias map collect
16
+
17
+ def select
18
+ Filter.new do |output|
19
+ each do |element|
20
+ output.call(element) if yield(element)
21
+ end
22
+ end
23
+ end
24
+
25
+ alias find_all select
26
+
27
+ def reject
28
+ Filter.new do |output|
29
+ each do |element|
30
+ output.call(element) unless yield(element)
31
+ end
32
+ end
33
+ end
34
+
35
+ def uniq
36
+ Filter.new do |output|
37
+ seen = Set.new
38
+ each do |element|
39
+ output.call(element) if seen.add?(element)
40
+ end
41
+ end
42
+ end
43
+
44
+ def uniq_by
45
+ Filter.new do |output|
46
+ seen = Set.new
47
+ each do |element|
48
+ output.call(element) if seen.add?(yield element)
49
+ end
50
+ end
51
+ end
52
+
53
+ def take(n)
54
+ Filter.new do |output|
55
+ if n > 0
56
+ each_with_index do |element, index|
57
+ output.call(element)
58
+ throw Lazily::Filter::DONE if index + 1 == n
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ def take_while
65
+ Filter.new do |output|
66
+ each do |element|
67
+ throw Lazily::Filter::DONE unless yield(element)
68
+ output.call(element)
69
+ end
70
+ end
71
+ end
72
+
73
+ def drop(n)
74
+ Filter.new do |output|
75
+ each_with_index do |element, index|
76
+ next if index < n
77
+ output.call(element)
78
+ end
79
+ end
80
+ end
81
+
82
+ def drop_while
83
+ Filter.new do |output|
84
+ take = false
85
+ each do |element|
86
+ take ||= !yield(element)
87
+ output.call(element) if take
88
+ end
89
+ end
90
+ end
91
+
92
+ def [](n)
93
+ drop(n).first
94
+ end
95
+
96
+ end
97
+
98
+ class Filter
99
+
100
+ include Lazily::Enumerable
101
+
102
+ def initialize(&generator)
103
+ @generator = generator
104
+ end
105
+
106
+ DONE = "Lazily::DONE".to_sym
107
+
108
+ def each
109
+ return to_enum unless block_given?
110
+ yielder = proc { |x| yield x }
111
+ catch DONE do
112
+ @generator.call(yielder)
113
+ end
114
+ end
115
+
116
+ end
117
+
118
+ end
@@ -0,0 +1,72 @@
1
+ require "lazily/enumerable"
2
+
3
+ module Lazily
4
+
5
+ class << self
6
+
7
+ def merge(*enumerables)
8
+ Merger.new(enumerables)
9
+ end
10
+
11
+ def merge_by(*enumerables, &block)
12
+ Merger.new(enumerables, &block)
13
+ end
14
+
15
+ end
16
+
17
+ class Merger
18
+
19
+ include Lazily::Enumerable
20
+
21
+ def initialize(enumerables, &transformer)
22
+ @enumerables = enumerables
23
+ @transformer = transformer
24
+ end
25
+
26
+ def each(&block)
27
+ return to_enum unless block_given?
28
+ Generator.new(@enumerables.map(&:to_enum), @transformer).each(&block)
29
+ end
30
+
31
+ class Generator
32
+
33
+ def initialize(enumerators, transformer)
34
+ @enumerators = enumerators
35
+ @transformer = transformer
36
+ end
37
+
38
+ def each
39
+ loop do
40
+ discard_empty_enumerators
41
+ break if @enumerators.empty?
42
+ yield next_enumerator.next
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def discard_empty_enumerators
49
+ @enumerators.delete_if do |e|
50
+ begin
51
+ e.peek
52
+ false
53
+ rescue StopIteration
54
+ true
55
+ end
56
+ end
57
+ end
58
+
59
+ def next_enumerator
60
+ @enumerators.min_by { |enumerator| transform(enumerator.peek) }
61
+ end
62
+
63
+ def transform(item)
64
+ return item unless @transformer
65
+ @transformer.call(item)
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -0,0 +1,43 @@
1
+ require "lazily/enumerable"
2
+
3
+ module Lazily
4
+
5
+ module Enumerable
6
+
7
+ def prefetch(size)
8
+ Prefetcher.new(self, size)
9
+ end
10
+
11
+ end
12
+
13
+ class Prefetcher
14
+
15
+ include Lazily::Enumerable
16
+
17
+ def initialize(source, buffer_size)
18
+ @source = source.to_enum
19
+ @buffer_size = buffer_size
20
+ end
21
+
22
+ def each(&block)
23
+ return @source.each(&block) if @buffer_size <= 0
24
+ buffered_elements = []
25
+ i = 0
26
+ @source.each do |element|
27
+ slot = i % @buffer_size
28
+ if i >= @buffer_size
29
+ yield buffered_elements[slot]
30
+ end
31
+ buffered_elements[slot] = element
32
+ i += 1
33
+ end
34
+ buffered_elements.size.times do
35
+ slot = i % buffered_elements.size
36
+ yield buffered_elements[slot]
37
+ i += 1
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,32 @@
1
+ require "lazily/enumerable"
2
+
3
+ def Lazily(enumerable)
4
+ Lazily::Proxy.new(enumerable)
5
+ end
6
+
7
+ module ::Enumerable
8
+
9
+ def lazily
10
+ Lazily::Proxy.new(self)
11
+ end
12
+
13
+ end
14
+
15
+ module Lazily
16
+
17
+ class Proxy
18
+
19
+ include Lazily::Enumerable
20
+
21
+ def initialize(source)
22
+ @source = source
23
+ end
24
+
25
+ def each(&block)
26
+ return to_enum unless block
27
+ @source.each(&block)
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1,16 @@
1
+ require "lazily/prefetching"
2
+
3
+ module Lazily
4
+
5
+ module Enumerable
6
+
7
+ def in_threads(max_threads, &block)
8
+ collect do |item|
9
+ Thread.new { block.call(item) }
10
+ end.prefetch(max_threads - 1).collect do |thread|
11
+ thread.join; thread.value
12
+ end
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,3 @@
1
+ module Lazily
2
+ VERSION = "0.0.1".freeze
3
+ end
@@ -0,0 +1,46 @@
1
+ require "lazily/enumerable"
2
+
3
+ module Lazily
4
+
5
+ class << self
6
+
7
+ def zip(*enumerables)
8
+ Zipper.new(enumerables)
9
+ end
10
+
11
+ end
12
+
13
+ module Enumerable
14
+
15
+ def zip(*others)
16
+ Lazily.zip(self, *others)
17
+ end
18
+
19
+ end
20
+
21
+ class Zipper
22
+
23
+ include Lazily::Enumerable
24
+
25
+ def initialize(enumerables)
26
+ @enumerables = enumerables
27
+ end
28
+
29
+ def each
30
+ enumerators = @enumerables.map(&:to_enum)
31
+ while true
32
+ chunk = enumerators.map do |enumerator|
33
+ begin
34
+ enumerator.next
35
+ rescue StopIteration
36
+ nil
37
+ end
38
+ end
39
+ break if chunk.all?(&:nil?)
40
+ yield chunk
41
+ end
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,39 @@
1
+ require "spec_helper"
2
+
3
+ describe Lazily, "concatenating" do
4
+
5
+ describe ".concat" do
6
+
7
+ let(:array1) { [1,5,3] }
8
+ let(:array2) { [2,9,4] }
9
+
10
+ it "concatenates multiple Enumerables" do
11
+ result = Lazily.concat([1,5,3], [2,9,4])
12
+ result.to_a.should == [1,5,3,2,9,4]
13
+ end
14
+
15
+ it "is lazy" do
16
+ result = Lazily.concat([3,4], [1,2].with_time_bomb)
17
+ result.take(3).to_a.should == [3,4,1]
18
+ end
19
+
20
+ end
21
+
22
+ describe "#concat" do
23
+
24
+ let(:array1) { [1,5,3] }
25
+ let(:array2) { [2,9,4] }
26
+
27
+ it "concatenates multiple Enumerables" do
28
+ result = [1,5,3].lazily.concat([2,9,4])
29
+ result.to_a.should == [1,5,3,2,9,4]
30
+ end
31
+
32
+ it "is lazy" do
33
+ result = [3,4].lazily.concat([1,2].with_time_bomb)
34
+ result.take(3).to_a.should == [3,4,1]
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,134 @@
1
+ require "spec_helper"
2
+
3
+ describe Lazily, "filter" do
4
+
5
+ describe "#collect" do
6
+
7
+ it "transforms items" do
8
+ [1,2,3].lazily.collect { |x| x * 2 }.to_a.should == [2,4,6]
9
+ end
10
+
11
+ it "is lazy" do
12
+ [1,2,3].with_time_bomb.lazily.collect { |x| x * 2 }.first.should == 2
13
+ end
14
+
15
+ end
16
+
17
+ describe "#select" do
18
+
19
+ it "excludes items that don't pass the predicate" do
20
+ (1..6).lazily.select { |x| x%2 == 0 }.to_a.should == [2,4,6]
21
+ end
22
+
23
+ it "is lazy" do
24
+ (1..6).with_time_bomb.lazily.select { |x| x%2 == 0 }.first == 2
25
+ end
26
+
27
+ end
28
+
29
+ describe "#reject" do
30
+
31
+ it "excludes items that do pass the predicate" do
32
+ (1..6).lazily.reject { |x| x%2 == 0 }.to_a.should == [1,3,5]
33
+ end
34
+
35
+ it "is lazy" do
36
+ (1..6).with_time_bomb.lazily.reject { |x| x%2 == 0 }.first == 1
37
+ end
38
+
39
+ end
40
+
41
+ describe "#uniq" do
42
+
43
+ it "removes duplicates" do
44
+ [1,3,2,4,3,5,4,6].lazily.uniq.to_a.should == [1,3,2,4,5,6]
45
+ end
46
+
47
+ it "is lazy" do
48
+ [1,2,3].with_time_bomb.lazily.uniq.first.should == 1
49
+ end
50
+
51
+ end
52
+
53
+ describe "#uniq_by" do
54
+
55
+ it "uses the block to derive identity" do
56
+ @array = %w(A1 A2 B1 A3 C1 B2 C2)
57
+ @array.lazily.uniq_by { |s| s[0,1] }.to_a.should == %w(A1 B1 C1)
58
+ end
59
+
60
+ end
61
+
62
+ describe "#take" do
63
+
64
+ it "includes the specified number" do
65
+ @array = [1,2,3,4]
66
+ @array.lazily.take(3).to_a.should == [1,2,3]
67
+ end
68
+
69
+ it "is lazy" do
70
+ [1,2].with_time_bomb.lazily.take(2).to_a.should == [1,2]
71
+ end
72
+
73
+ it "copes with 0" do
74
+ [].with_time_bomb.lazily.take(0).to_a.should == []
75
+ end
76
+
77
+ end
78
+
79
+ describe "#take_while" do
80
+
81
+ it "takees elements as long as the predicate is true" do
82
+ @array = [2,4,6,3]
83
+ @array.lazily.take_while(&:even?).to_a.should == [2,4,6]
84
+ end
85
+
86
+ it "is lazy" do
87
+ [2,3].with_time_bomb.lazily.take_while(&:even?).to_a.should == [2]
88
+ end
89
+
90
+ end
91
+
92
+ describe "#drop" do
93
+
94
+ it "excludes the specified number" do
95
+ @array = [1,2,3,4]
96
+ @array.lazily.drop(2).to_a.should == [3,4]
97
+ end
98
+
99
+ it "is lazy" do
100
+ [1,2,3,4].with_time_bomb.lazily.drop(2).lazily.take(1).to_a.should == [3]
101
+ end
102
+
103
+ end
104
+
105
+ describe "#drop_while" do
106
+
107
+ it "drops elements as long as the predicate is true" do
108
+ @array = [2,4,6,3,4]
109
+ @array.lazily.drop_while(&:even?).to_a.should == [3,4]
110
+ end
111
+
112
+ it "is lazy" do
113
+ [2,3].with_time_bomb.lazily.drop_while(&:even?).lazily.take(1).to_a.should == [3]
114
+ end
115
+
116
+ end
117
+
118
+ describe "#[]" do
119
+
120
+ before do
121
+ @evens = [1,2,3,4,5].lazily.collect { |x| x * 2 }
122
+ end
123
+
124
+ it "finds the specified element" do
125
+ @evens.lazily[2].should == 6
126
+ end
127
+
128
+ it "is lazy" do
129
+ @evens.with_time_bomb.lazily[3].should == 8
130
+ end
131
+
132
+ end
133
+
134
+ end
@@ -0,0 +1,35 @@
1
+ require "spec_helper"
2
+
3
+ describe Lazily, :needs_enumerators => true do
4
+
5
+ describe ".merge" do
6
+
7
+ it "merges multiple Enumerators" do
8
+ @array1 = [1,3,6]
9
+ @array2 = [2,4,7]
10
+ @array3 = [5,8]
11
+ @merge = Lazily.merge(@array1, @array2, @array3)
12
+ @merge.to_a.should == [1,2,3,4,5,6,7,8]
13
+ end
14
+
15
+ it "is lazy" do
16
+ @enum1 = [1,3,6]
17
+ @enum2 = [2,4,7].with_time_bomb
18
+ @merge = Lazily.merge(@enum1, @enum2)
19
+ @merge.take(4).to_a.should == [1,2,3,4]
20
+ end
21
+
22
+ end
23
+
24
+ describe ".merge_by" do
25
+
26
+ it "uses the block to determine order" do
27
+ @array1 = %w(cccc dd a)
28
+ @array2 = %w(eeeee bbb)
29
+ @merge = Lazily.merge_by(@array1, @array2) { |s| -s.length }
30
+ @merge.to_a.should == %w(eeeee cccc bbb dd a)
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,69 @@
1
+ require "spec_helper"
2
+
3
+ describe Lazily do
4
+
5
+ Counter = Class.new do
6
+
7
+ include Enumerable
8
+
9
+ def initialize(source)
10
+ @source = source
11
+ @number_yielded = 0
12
+ end
13
+
14
+ def each
15
+ @source.each do |item|
16
+ @number_yielded += 1
17
+ yield item
18
+ end
19
+ end
20
+
21
+ attr_reader :number_yielded
22
+
23
+ end
24
+
25
+ describe "#prefetch" do
26
+
27
+ let(:source) { [1, 2, 3, 4, nil, false, 7] }
28
+
29
+ it "yields all items" do
30
+ source.lazily.prefetch(2).to_a.should eq(source)
31
+ source.lazily.prefetch(3).to_a.should eq(source)
32
+ end
33
+
34
+ it "is stateless" do
35
+ source.lazily.prefetch(2).first.should eq(source.first)
36
+ source.lazily.prefetch(2).first.should eq(source.first)
37
+ end
38
+
39
+ it "is lazy" do
40
+ source.with_time_bomb.lazily.prefetch(2).first.should eq(source.first)
41
+ end
42
+
43
+ it "pre-computes the specified number of elements" do
44
+ counter = Counter.new(source)
45
+ counter.lazily.prefetch(2).first
46
+ counter.number_yielded.should eq(3)
47
+ end
48
+
49
+ context "with a buffer size of zero" do
50
+
51
+ it "does not pre-fetch anything" do
52
+ counter = Counter.new(source)
53
+ counter.lazily.prefetch(0).first
54
+ counter.number_yielded.should eq(1)
55
+ end
56
+
57
+ end
58
+
59
+ context "with a buffer bigger than the source Enumerable" do
60
+
61
+ it "yields all items" do
62
+ source.lazily.prefetch(20).to_a.should eq(source)
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+
69
+ end
@@ -0,0 +1,50 @@
1
+ require "spec_helper"
2
+
3
+ describe Lazily, "threading" do
4
+
5
+ describe "#in_threads" do
6
+
7
+ it "acts like #collect" do
8
+ [1,2,3].lazily.in_threads(5) { |x| x * 2 }.to_a.should == [2,4,6]
9
+ end
10
+
11
+ it "runs things in separate threads" do
12
+ [1,2,3].lazily.in_threads(5) { Thread.current.object_id }.to_a.uniq.size.should eq(3)
13
+ end
14
+
15
+ it "is lazy" do
16
+ [1,2,3].with_time_bomb.lazily.in_threads(2) { |x| x * 2 }.first.should == 2
17
+ end
18
+
19
+ def round(n, accuracy = 0.02)
20
+ (n / accuracy).round.to_f * accuracy
21
+ end
22
+
23
+ it "runs the specified number of threads in parallel" do
24
+ delays = [0.03, 0.03, 0.03]
25
+ start = Time.now
26
+ delays.lazily.in_threads(2) do |delay|
27
+ sleep(delay)
28
+ end.to_a
29
+ round(Time.now - start).should eq(0.06)
30
+ end
31
+
32
+ it "acts as a sliding window" do
33
+ delays = [0.1, 0.08, 0.06, 0.04, 0.02]
34
+ start = Time.now
35
+ elapsed_times = delays.lazily.in_threads(3) do |delay|
36
+ sleep(delay)
37
+ round(Time.now - start)
38
+ end
39
+ elapsed_times.to_a.should eq([0.1, 0.08, 0.06, 0.14, 0.12])
40
+ end
41
+
42
+ it "surfaces exceptions" do
43
+ lambda do
44
+ [1,2,3].lazily.in_threads(5) { raise "hell" }.to_a
45
+ end.should raise_error(RuntimeError, "hell")
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,37 @@
1
+ require "spec_helper"
2
+
3
+ describe Lazily, "zipping", :needs_enumerators => true do
4
+
5
+ let(:array1) { [1,3,6] }
6
+ let(:array2) { [2,4,7] }
7
+ let(:array3) { [5,8] }
8
+
9
+ describe ".zip" do
10
+
11
+ it "zips together multiple Enumerables" do
12
+ zip = Lazily.zip(array1, array2, array3)
13
+ zip.to_a.should == [[1,2,5], [3,4,8], [6,7,nil]]
14
+ end
15
+
16
+ it "is lazy" do
17
+ zip = Lazily.zip(%w(a b c), [1,2].with_time_bomb)
18
+ zip.take(2).to_a.should == [["a", 1], ["b", 2]]
19
+ end
20
+
21
+ end
22
+
23
+ describe "#zip" do
24
+
25
+ it "zips an Enumerable with multiple others" do
26
+ zip = array1.lazily.zip(array2, array3)
27
+ zip.to_a.should == [[1,2,5], [3,4,8], [6,7,nil]]
28
+ end
29
+
30
+ it "is lazy" do
31
+ zip = %w(a b c).lazily.zip([1,2].with_time_bomb)
32
+ zip.take(2).to_a.should == [["a", 1], ["b", 2]]
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,17 @@
1
+ require "spec_helper"
2
+
3
+ describe "Lazily", "method" do
4
+
5
+ it "returns a lazy proxy" do
6
+ Lazily([1,2,3]).should be_lazy
7
+ end
8
+
9
+ end
10
+
11
+ describe "Enumerable", "#lazily" do
12
+
13
+ it "returns a lazy proxy" do
14
+ [1,2,3].lazily.should be_lazy
15
+ end
16
+
17
+ end
@@ -0,0 +1,41 @@
1
+ require "lazily"
2
+
3
+ class NotLazyEnough < StandardError; end
4
+
5
+ class WithTimeBomb
6
+
7
+ include Enumerable
8
+
9
+ def initialize(source)
10
+ @source = source
11
+ end
12
+
13
+ def each(&block)
14
+ @source.each(&block)
15
+ raise NotLazyEnough
16
+ end
17
+
18
+ end
19
+
20
+ module Enumerable
21
+
22
+ # extend an Enumerable to throw an exception after last element
23
+ def with_time_bomb
24
+ WithTimeBomb.new(self)
25
+ end
26
+
27
+ unless method_defined?(:first)
28
+ def first
29
+ each do |first_item|
30
+ return first_item
31
+ end
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ RSpec.configure do |config|
38
+ unless defined?(::Enumerator)
39
+ config.filter_run_excluding :needs_enumerators => true
40
+ end
41
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lazily
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mike Williams
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-19 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: ! " Lazily implements \"lazy\" versions of many Enumerable methods,\n
14
+ \ allowing streamed processing of large (or even infinite) collections.\n\n It's
15
+ equivalent to Ruby-2.x's Enumerable#lazy, but is implemented in\n pure Ruby,
16
+ and works even in Ruby-1.8.x.\n"
17
+ email: mdub@dogbiscuit.org
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - .rspec
24
+ - .travis.yml
25
+ - Gemfile
26
+ - Rakefile
27
+ - lazily.gemspec
28
+ - lib/lazily.rb
29
+ - lib/lazily/combining.rb
30
+ - lib/lazily/concatenating.rb
31
+ - lib/lazily/enumerable.rb
32
+ - lib/lazily/filtering.rb
33
+ - lib/lazily/merging.rb
34
+ - lib/lazily/prefetching.rb
35
+ - lib/lazily/proxy.rb
36
+ - lib/lazily/threading.rb
37
+ - lib/lazily/version.rb
38
+ - lib/lazily/zipping.rb
39
+ - spec/lazily/concatenating_spec.rb
40
+ - spec/lazily/filtering_spec.rb
41
+ - spec/lazily/merging_spec.rb
42
+ - spec/lazily/prefetching_spec.rb
43
+ - spec/lazily/threading_spec.rb
44
+ - spec/lazily/zipping_spec.rb
45
+ - spec/lazily_spec.rb
46
+ - spec/spec_helper.rb
47
+ homepage: http://github.com/mdub/lazily
48
+ licenses: []
49
+ metadata: {}
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubyforge_project:
66
+ rubygems_version: 2.0.0
67
+ signing_key:
68
+ specification_version: 4
69
+ summary: Lazy Enumerables for everybody!
70
+ test_files:
71
+ - spec/lazily/concatenating_spec.rb
72
+ - spec/lazily/filtering_spec.rb
73
+ - spec/lazily/merging_spec.rb
74
+ - spec/lazily/prefetching_spec.rb
75
+ - spec/lazily/threading_spec.rb
76
+ - spec/lazily/zipping_spec.rb
77
+ - spec/lazily_spec.rb
78
+ - spec/spec_helper.rb