lazily 0.0.1

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