Skip to content

Commit 1159de3

Browse files
committed
operator :together for Proc objects
1 parent b9fdbf1 commit 1159de3

File tree

4 files changed

+120
-7
lines changed

4 files changed

+120
-7
lines changed

README

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ records [word, frequency] he should run
3535
One can make calculations lazy just by converting container to lazy one:
3636
records.to_lazy. ...
3737

38-
Lazy container allows to dramatically reduce memory usage when
38+
LazyEnumerable allows to dramatically reduce memory usage when
3939
using piped transfromations: map, select, uniq, pipe, and reduce.
4040

41-
The only problem is method +sort+, which requires all records to be
41+
The only problem is the method +sort+, which requires all records to be
4242
loaded to memory. But one can use any scalable external sort:
4343

4444
cat records.txt | \

lib/core_ext.rb

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
$:.unshift File.dirname(__FILE__)
22

33
require 'meta_ext'
4+
require 'proc_ext'
45
require 'hash_ext'
56

lib/meta_ext.rb

-5
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,6 @@ def extract_options(args)
1414
end
1515
end
1616

17-
class Proc
18-
# This alias make it possible use blocks as virtual input streams or arrays.
19-
alias :<< :call
20-
end
21-
2217
class Symbol
2318
unless public_method_defined? :to_proc
2419
def to_proc

lib/proc_ext.rb

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
class Proc
2+
alias << call
3+
4+
class MultipleValue < Array
5+
def initialize(*args)
6+
args.each_with_index{|e,i| self[i] = e}
7+
end
8+
def each_with_recursion(&block)
9+
each_without_recursion do |e|
10+
if e.is_a?(MultipleValue)
11+
e.each(&block)
12+
else
13+
block[e]
14+
end
15+
end
16+
end
17+
alias each_without_recursion each
18+
alias each each_with_recursion
19+
end
20+
21+
attr_accessor :together_blocks
22+
# protected :together_blocks, :together_blocks=
23+
24+
def together(other)
25+
block = Proc.new do |reduced_value, e|
26+
reduced_value = MV( *([reduced_value]*block.together_blocks.size) ) unless reduced_value.is_a?(MultipleValue)
27+
i = -1
28+
reduced_value.map!{|rv|
29+
block.together_blocks[i+=1][rv, e]
30+
}
31+
end
32+
block.together_blocks = (self.together_blocks || [self]) + (other.together_blocks || [other])
33+
block
34+
end
35+
alias + together
36+
end
37+
38+
def MV(*args)
39+
Proc::MultipleValue.new(*args)
40+
end
41+
42+
class Symbol
43+
unless public_method_defined? :to_proc
44+
def to_proc
45+
Proc.new { |*args| args.shift.__send__(self, *args) }
46+
end
47+
end
48+
end
49+
50+
if $0 == __FILE__
51+
require 'test/unit'
52+
class TestProcExt < Test::Unit::TestCase
53+
def test_reducers_sum
54+
55+
b = :+.to_proc + :*.to_proc
56+
57+
assert_equal(
58+
[15, 120],
59+
[1,2,3,4,5].inject(&b)
60+
)
61+
62+
assert_equal(
63+
[17, 240],
64+
[1,2,3,4,5].inject(2, &b)
65+
)
66+
67+
assert_equal(
68+
[17, 1200],
69+
[1,2,3,4,5].inject( MV(2,10), &b )
70+
)
71+
72+
c = :+.to_proc + :+.to_proc + :+.to_proc
73+
assert_equal(
74+
[15, 16, 17],
75+
[1,2,3,4,5].inject( MV(0,1,2), &c ).to_a
76+
)
77+
end
78+
79+
def test_abc
80+
a = :+.to_proc
81+
b = a + :*.to_proc
82+
d = lambda{|x,y| [x,y].min}
83+
c = b + d
84+
e = d + b
85+
assert_equal(
86+
6,
87+
[1,2,3].inject(&a)
88+
)
89+
90+
assert_equal(
91+
1,
92+
[4,3,1,4,5].inject(&d)
93+
)
94+
95+
assert_equal(
96+
[10, 30],
97+
[2,3,5].inject(&b)
98+
)
99+
100+
assert(
101+
3,
102+
c.send(:together_blocks).size
103+
)
104+
105+
assert_equal(
106+
[10, 30, 2],
107+
[3,2,5].inject(&c)
108+
)
109+
110+
assert_equal(
111+
[2, 10, 30],
112+
[3,2,5].inject(&e)
113+
)
114+
end
115+
end
116+
end
117+

0 commit comments

Comments
 (0)