lazily 0.1.2 → 0.2.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.
data/README.md CHANGED
@@ -41,14 +41,14 @@ See how it printed all the numbers from 1 to 10, indicating that the block given
41
41
  4
42
42
  => [1, 4, 9, 16]
43
43
 
44
- Same result, but notice how the block was only evaluated four times.
44
+ Same result, but notice how the block was only evaluated four times.
45
45
 
46
46
  Lazy pipelines
47
47
  --------------
48
48
 
49
49
  By combining two or more lazy operations, you can create an efficient "pipeline", e.g.
50
50
 
51
- User.to_enum(:find_each).lazily.select do |u|
51
+ User.to_enum(:find_each).lazily.select do |u|
52
52
  u.first_name[0] == u.last_name[0]
53
53
  end.collect(&:company).uniq.to_a
54
54
 
@@ -73,7 +73,7 @@ This is analogous to a Unix shell pipeline, though of course here we're talking
73
73
  Lazy multi-threaded processing
74
74
  ------------------------------
75
75
 
76
- The `#in_threads` method is a multi-threaded version of `#collect`, allowing multiple elements of a collection to be processed in parallel. It requires a numeric argument specifying the maximum number of Threads to use.
76
+ The `#in_threads` method is a multi-threaded version of `#collect`, allowing multiple elements of a collection to be processed in parallel. It requires a numeric argument specifying the maximum number of Threads to use.
77
77
 
78
78
  Benchmark.realtime do
79
79
  [1,2,3,4].lazily.in_threads(10) do |x|
@@ -82,7 +82,7 @@ The `#in_threads` method is a multi-threaded version of `#collect`, allowing mul
82
82
  end.to_a #=> [2,4,6,8]
83
83
  end.to_i #=> 1
84
84
 
85
- Outputs will be yielded in the expected order, making it a drop-in replacement for `#collect`.
85
+ Outputs will be yielded in the expected order, making it a drop-in replacement for `#collect`.
86
86
 
87
87
  Unlike some other "parallel map" implementations, the output of `#in_threads` is lazy (though it does need to pre-fetch elements from the source collection as required to start Threads).
88
88
 
@@ -116,10 +116,24 @@ A block can be provided to determine the sort-order.
116
116
  Lazily.merge(array1, array2) { |x| x.length }
117
117
  #=> %w(a dd eee cccc bbbbb)
118
118
 
119
+ `Lazily.associate` matches up "like" elements from separate collections. Again, it assumes it's inputs sorted.
120
+
121
+ fruit = %w(apple banana orange)
122
+ nautical_terms = %w(anchor boat flag)
123
+ Lazily.associate(:fruit => fruit, :nautical => nautical_terms) do |word|
124
+ word.chars.first
125
+ end
126
+ #=> [
127
+ { :fruit => ["apple"], :nautical => ["anchor"] },
128
+ { :fruit => ["banana"], :nautical => ["boat"] },
129
+ { :fruit => [], :nautical => ["flag"] },
130
+ { :fruit => ["orange"], :nautical => [] }
131
+ ]
132
+
119
133
  Same but different
120
134
  ------------------
121
135
 
122
- There are numerous similar implementations of lazy operations on Enumerables.
136
+ There are numerous similar implementations of lazy operations on Enumerables.
123
137
 
124
138
  ### Lazily vs. Enumerating
125
139
 
@@ -0,0 +1,44 @@
1
+ require "lazily/enumerable"
2
+
3
+ module Lazily
4
+
5
+ class << self
6
+
7
+ # Associate "like" elements of two or more Enumerables.
8
+ #
9
+ # @param labelled_enumerables [Hash<key,Enumerable>]
10
+ # @return [Enumerable] a lazy collection of Hashes
11
+ #
12
+ # @example
13
+ # Lazily.associate(a: [1,2,4], b: [1,3,4,4])
14
+ # #=> [
15
+ # { a: [1], b: [1] },
16
+ # { a: [2] },
17
+ # { b: [3] },
18
+ # { a: [4], b: [4, 4] }
19
+ # ]
20
+ #
21
+ def associate(source_map, &block)
22
+ labels = source_map.keys
23
+ tagged_element_sources = source_map.map do |label, enumerable|
24
+ enumerable.lazily.map do |value|
25
+ key = block ? block.call(value) : value
26
+ TaggedElement.new(key, value, label)
27
+ end
28
+ end
29
+ tagged_elements = Lazily.merge(*tagged_element_sources) { |te| te.key }
30
+ tagged_elements.chunk { |te| te.key }.map do |_, tagged_elements|
31
+ association = {}
32
+ labels.each { |label| association[label] = [] }
33
+ tagged_elements.each do |te|
34
+ association[te.label] << te.value
35
+ end
36
+ association
37
+ end
38
+ end
39
+
40
+ TaggedElement = Struct.new(:key, :value, :label)
41
+
42
+ end
43
+
44
+ end
@@ -1,3 +1,4 @@
1
+ require "lazily/associating"
1
2
  require "lazily/concatenating"
2
3
  require "lazily/merging"
3
4
  require "lazily/zipping"
@@ -1,3 +1,3 @@
1
1
  module Lazily
2
- VERSION = "0.1.2".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
@@ -0,0 +1,96 @@
1
+ require "spec_helper"
2
+
3
+ describe Lazily, "associating" do
4
+
5
+ describe ".associate" do
6
+
7
+ context "with two identical Enumerables" do
8
+
9
+ let(:collectionA) { [2,4,6] }
10
+ let(:collectionB) { collectionA }
11
+
12
+ let(:result) do
13
+ Lazily.associate(:A => collectionA, :B => collectionB)
14
+ end
15
+
16
+ it "yields matched pairs" do
17
+ expect(result.to_a).to eq [
18
+ { :A => [2], :B => [2] },
19
+ { :A => [4], :B => [4] },
20
+ { :A => [6], :B => [6] }
21
+ ]
22
+ end
23
+
24
+ end
25
+
26
+ context "with three identical Enumerables" do
27
+
28
+ let(:collectionA) { [1,2]}
29
+ let(:collectionB) { collectionA }
30
+ let(:collectionC) { collectionA }
31
+
32
+ let(:result) do
33
+ Lazily.associate(:A => collectionA, :B => collectionB, :C => collectionC)
34
+ end
35
+
36
+ it "yields matched triples" do
37
+ expect(result.to_a).to eq [
38
+ { :A => [1], :B => [1], :C => [1] },
39
+ { :A => [2], :B => [2], :C => [2] }
40
+ ]
41
+ end
42
+
43
+ end
44
+
45
+ context "when elements are missing" do
46
+
47
+ let(:collectionA) { [1,2] }
48
+ let(:collectionB) { [2,3] }
49
+ let(:collectionC) { [1,3] }
50
+
51
+ let(:result) do
52
+ Lazily.associate(:A => collectionA, :B => collectionB, :C => collectionC)
53
+ end
54
+
55
+ it "returns an empty Array for the corresponding label" do
56
+ expect(result.to_a).to eq [
57
+ { :A => [1], :B => [ ], :C => [1] },
58
+ { :A => [2], :B => [2], :C => [ ] },
59
+ { :A => [ ], :B => [3], :C => [3] }
60
+ ]
61
+ end
62
+
63
+ end
64
+
65
+ context "with a block" do
66
+
67
+ let(:colours) { %w(blue red) }
68
+ let(:fruits) { %w(apple banana cranberry) }
69
+ let(:shapes) { %w(circle rectangle triangle) }
70
+
71
+ let(:result) do
72
+ Lazily.associate(:c => colours, :f => fruits, :s => shapes) do |word|
73
+ word.chars.first
74
+ end
75
+ end
76
+
77
+ it "uses the block to associate the elements" do
78
+ expect(result.to_a).to eq [
79
+ { :c => [], :f => ['apple'], :s => [] },
80
+ { :c => ['blue'], :f => ['banana'], :s => [] },
81
+ { :c => [], :f => ['cranberry'], :s => ['circle'] },
82
+ { :c => ['red'], :f => [], :s => ['rectangle'] },
83
+ { :c => [], :f => [], :s => ['triangle'] }
84
+ ]
85
+ end
86
+
87
+ end
88
+
89
+ it "is lazy" do
90
+ result = Lazily.associate(:a => [1,2].ecetera, :b => [3,4].ecetera )
91
+ expect(result.first).to eq(:a => [1], :b => [])
92
+ end
93
+
94
+ end
95
+
96
+ end if ::Enumerable.method_defined?(:chunk)
@@ -16,27 +16,27 @@ describe Lazily, "threading" do
16
16
  [1,2,3].ecetera.lazily.in_threads(2) { |x| x * 2 }.should be_lazy
17
17
  end
18
18
 
19
- def round(n, accuracy = 0.02)
20
- (n / accuracy).round.to_f * accuracy
19
+ def round(n, accuracy = 20)
20
+ (n * accuracy).round.to_f / accuracy
21
21
  end
22
22
 
23
23
  it "runs the specified number of threads in parallel" do
24
- delays = [0.03, 0.03, 0.03]
24
+ delays = [0.05, 0.05, 0.05]
25
25
  start = Time.now
26
26
  delays.lazily.in_threads(2) do |delay|
27
27
  sleep(delay)
28
28
  end.to_a
29
- round(Time.now - start).should eq(0.06)
29
+ round(Time.now - start).should eq(0.1)
30
30
  end
31
31
 
32
32
  it "acts as a sliding window" do
33
- delays = [0.1, 0.08, 0.06, 0.04, 0.02]
33
+ delays = [0.1, 0.15, 0.05, 0.05, 0.05]
34
34
  start = Time.now
35
35
  elapsed_times = delays.lazily.in_threads(3) do |delay|
36
36
  sleep(delay)
37
37
  round(Time.now - start)
38
38
  end
39
- elapsed_times.to_a.should eq([0.1, 0.08, 0.06, 0.14, 0.12])
39
+ elapsed_times.to_a.should eq([0.1, 0.15, 0.05, 0.15, 0.2])
40
40
  end
41
41
 
42
42
  it "surfaces exceptions" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lazily
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-24 00:00:00.000000000 Z
12
+ date: 2013-07-14 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! " Lazily implements \"lazy\" versions of many Enumerable methods,\n
15
15
  \ allowing streamed processing of large (or even infinite) collections.\n\n It's
@@ -30,6 +30,7 @@ files:
30
30
  - benchmarks/pipeline_bench.rb
31
31
  - lazily.gemspec
32
32
  - lib/lazily.rb
33
+ - lib/lazily/associating.rb
33
34
  - lib/lazily/combining.rb
34
35
  - lib/lazily/concatenating.rb
35
36
  - lib/lazily/enumerable.rb
@@ -40,6 +41,7 @@ files:
40
41
  - lib/lazily/threading.rb
41
42
  - lib/lazily/version.rb
42
43
  - lib/lazily/zipping.rb
44
+ - spec/lazily/associating_spec.rb
43
45
  - spec/lazily/bugs_spec.rb
44
46
  - spec/lazily/concatenating_spec.rb
45
47
  - spec/lazily/filtering_spec.rb
@@ -63,7 +65,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
63
65
  version: '0'
64
66
  segments:
65
67
  - 0
66
- hash: 1657751678053576424
68
+ hash: 3722161259490547720
67
69
  required_rubygems_version: !ruby/object:Gem::Requirement
68
70
  none: false
69
71
  requirements:
@@ -72,7 +74,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
72
74
  version: '0'
73
75
  segments:
74
76
  - 0
75
- hash: 1657751678053576424
77
+ hash: 3722161259490547720
76
78
  requirements: []
77
79
  rubyforge_project:
78
80
  rubygems_version: 1.8.23
@@ -80,6 +82,7 @@ signing_key:
80
82
  specification_version: 3
81
83
  summary: Lazy Enumerables for everybody!
82
84
  test_files:
85
+ - spec/lazily/associating_spec.rb
83
86
  - spec/lazily/bugs_spec.rb
84
87
  - spec/lazily/concatenating_spec.rb
85
88
  - spec/lazily/filtering_spec.rb