stages 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +1 -1
- data/{README → README.md} +1 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/examples/sing.rb +48 -0
- data/examples/sing_subpipes.rb +34 -0
- data/lib/stage_base.rb +37 -4
- data/lib/stages.rb +1 -1
- data/lib/stages/count.rb +11 -0
- data/lib/stages/each_element.rb +1 -1
- data/lib/stages/each_input.rb +10 -0
- data/lib/stages/restrict.rb +28 -0
- data/lib/stages/resume.rb +16 -0
- data/lib/stages/resume_count.rb +16 -0
- data/lib/stages/sub_stage.rb +20 -0
- data/stages.gemspec +13 -5
- data/test/test_pipeline.rb +4 -13
- data/test/test_stages.rb +53 -5
- metadata +14 -9
data/.autotest
CHANGED
@@ -3,7 +3,7 @@ Autotest.add_hook(:initialize) do |at|
|
|
3
3
|
at.add_exception(exception)
|
4
4
|
end
|
5
5
|
|
6
|
-
at.add_mapping(%r%^
|
6
|
+
at.add_mapping(%r%^lib(/stages)?/(.*).rb$%, true) do |filename, _|
|
7
7
|
['test/test_pipeline.rb', 'test/test_stages.rb']
|
8
8
|
end
|
9
9
|
|
data/{README → README.md}
RENAMED
@@ -19,7 +19,7 @@ We have included some general purpose stages, map and select, which can accompli
|
|
19
19
|
|
20
20
|
```ruby
|
21
21
|
pipeline = Evens.new | Map.new{ |x| x * 3} | Select.new{ |x| x % 7 == 0}
|
22
|
-
|
22
|
+
3.times{ pipeline.run } #[0, 42, 84]}
|
23
23
|
```
|
24
24
|
|
25
25
|
Writing New Stages
|
data/Rakefile
CHANGED
@@ -25,7 +25,7 @@ Jeweler::Tasks.new do |gem|
|
|
25
25
|
gem.summary = "pipeline builder"
|
26
26
|
gem.description = "pipeline builder"
|
27
27
|
gem.email = "support@igodigital.com"
|
28
|
-
gem.authors = ["
|
28
|
+
gem.authors = ["The Justice Eight"]
|
29
29
|
# dependencies defined in Gemfile
|
30
30
|
end
|
31
31
|
Jeweler::RubygemsDotOrgTasks.new
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/examples/sing.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../lib/stages"
|
2
|
+
|
3
|
+
include Stages
|
4
|
+
|
5
|
+
#count the occurance of each letter in these song lyrics
|
6
|
+
def sing
|
7
|
+
{ :do => 'doe a deer a female deer',
|
8
|
+
:re => 'ray a drop of golden sun',
|
9
|
+
:mi => 'me a name I call myself',
|
10
|
+
:fa => 'far a long long way to run',
|
11
|
+
:so => 'a needle pulling thread',
|
12
|
+
:la => 'a note to follow so',
|
13
|
+
:ti => 'a drink with jam and bread'}
|
14
|
+
end
|
15
|
+
|
16
|
+
def setup_pipeline
|
17
|
+
generator = EachElement.new sing.keys
|
18
|
+
loop = Restrict.new
|
19
|
+
get_lyric = HashLookup.new sing
|
20
|
+
each_character = EachInput.new{ |x| x.chars }
|
21
|
+
whitespace = Select.new{ |x| x != ' '}
|
22
|
+
pool = ResumeCount.new
|
23
|
+
subtotals = Map.new { |x| x.values.first }
|
24
|
+
iterator = EachInput.new
|
25
|
+
aggregator = SuperAggregator.new
|
26
|
+
|
27
|
+
generator | loop | get_lyric | each_character | whitespace | pool | subtotals | iterator | aggregator
|
28
|
+
end
|
29
|
+
|
30
|
+
class SuperAggregator < Stage
|
31
|
+
def initialize
|
32
|
+
@accumulator = Hash.new{ |h,k| h[k] = 0}
|
33
|
+
super()
|
34
|
+
end
|
35
|
+
|
36
|
+
def handle_value(value)
|
37
|
+
@accumulator[value[0]] += value[1]
|
38
|
+
while v = input
|
39
|
+
@accumulator[v[0]] += v[1]
|
40
|
+
end
|
41
|
+
output @accumulator
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
puts setup_pipeline.run.inspect
|
46
|
+
|
47
|
+
|
48
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../lib/stages"
|
2
|
+
|
3
|
+
include Stages
|
4
|
+
|
5
|
+
#count the occurance of each letter in these song lyrics
|
6
|
+
def sing
|
7
|
+
{ :do => 'doe a deer a female deer',
|
8
|
+
:re => 'ray a drop of golden sun',
|
9
|
+
:mi => 'me a name I call myself',
|
10
|
+
:fa => 'far a long long way to run',
|
11
|
+
:so => 'a needle pulling thread',
|
12
|
+
:la => 'a note to follow so',
|
13
|
+
:ti => 'a drink with jam and bread'}
|
14
|
+
end
|
15
|
+
|
16
|
+
def setup_pipeline
|
17
|
+
get_lyric = HashLookup.new sing
|
18
|
+
each_character = EachInput.new{ |x| x.chars }
|
19
|
+
whitespace = Select.new{ |x| x != ' '}
|
20
|
+
sub_pipeline = get_lyric | each_character | whitespace
|
21
|
+
process_elements = SubStage.new(sub_pipeline)
|
22
|
+
|
23
|
+
generator = EachElement.new sing.keys
|
24
|
+
subtotals = Map.new { |x| x.values.first }
|
25
|
+
iterator = EachInput.new
|
26
|
+
count = Count.new
|
27
|
+
|
28
|
+
generator | process_elements | subtotals | iterator | count
|
29
|
+
end
|
30
|
+
|
31
|
+
puts setup_pipeline.run.inspect
|
32
|
+
|
33
|
+
|
34
|
+
|
data/lib/stage_base.rb
CHANGED
@@ -4,14 +4,23 @@ module Stages
|
|
4
4
|
|
5
5
|
def initialize(&block)
|
6
6
|
@block = block
|
7
|
-
|
7
|
+
initialize_loop
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize_loop
|
11
|
+
@fiber_delegate = Fiber.new do
|
8
12
|
process
|
9
13
|
die
|
10
14
|
end
|
11
15
|
end
|
12
16
|
|
13
17
|
def run
|
14
|
-
|
18
|
+
@fiber_delegate.resume
|
19
|
+
end
|
20
|
+
|
21
|
+
def continue
|
22
|
+
initialize_loop
|
23
|
+
@source.continue if @source
|
15
24
|
end
|
16
25
|
|
17
26
|
def die
|
@@ -38,10 +47,34 @@ module Stages
|
|
38
47
|
Fiber.yield value
|
39
48
|
end
|
40
49
|
|
41
|
-
def |(other
|
42
|
-
other.source = self
|
50
|
+
def |(other)
|
51
|
+
other.root_source.source = self
|
43
52
|
other
|
44
53
|
end
|
54
|
+
|
55
|
+
def root_source
|
56
|
+
source.nil? ? self : source.root_source
|
57
|
+
end
|
58
|
+
|
59
|
+
def drop_leftmost!
|
60
|
+
if @source.end?
|
61
|
+
@source = nil
|
62
|
+
else
|
63
|
+
@source.drop_leftmost!
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def end?
|
68
|
+
@source.nil?
|
69
|
+
end
|
70
|
+
|
71
|
+
def length
|
72
|
+
if source
|
73
|
+
source.length + 1
|
74
|
+
else
|
75
|
+
1
|
76
|
+
end
|
77
|
+
end
|
45
78
|
end
|
46
79
|
end
|
47
80
|
|
data/lib/stages.rb
CHANGED
data/lib/stages/count.rb
ADDED
data/lib/stages/each_element.rb
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Stages
|
2
|
+
class Restrict < Stage
|
3
|
+
alias :super_continue :continue
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@open = true
|
7
|
+
super()
|
8
|
+
end
|
9
|
+
|
10
|
+
def continue
|
11
|
+
@open = true
|
12
|
+
r = @last_value
|
13
|
+
@last_value = nil
|
14
|
+
r
|
15
|
+
end
|
16
|
+
|
17
|
+
def process
|
18
|
+
while value = input
|
19
|
+
while !@open
|
20
|
+
handle_value nil
|
21
|
+
end
|
22
|
+
@open = false
|
23
|
+
@last_value = value
|
24
|
+
handle_value value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Stages
|
2
|
+
class ResumeCount < Stage
|
3
|
+
def input
|
4
|
+
result = Hash.new{ |h, k| h[k] = 0 }
|
5
|
+
while v = source.run
|
6
|
+
result[v] += 1
|
7
|
+
end
|
8
|
+
continued = @source.continue
|
9
|
+
if continued.nil?
|
10
|
+
nil
|
11
|
+
else
|
12
|
+
{ continued => result}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Stages
|
2
|
+
class SubStage < Stage
|
3
|
+
def initialize(pipeline)
|
4
|
+
@pipeline = pipeline
|
5
|
+
super()
|
6
|
+
end
|
7
|
+
|
8
|
+
def handle_value(value)
|
9
|
+
results = []
|
10
|
+
subpipe = (EachElement.new([value]) | @pipeline)
|
11
|
+
while v = subpipe.run
|
12
|
+
results << v
|
13
|
+
end
|
14
|
+
@pipeline.drop_leftmost!
|
15
|
+
@pipeline.continue
|
16
|
+
results = results.first if results.length == 1
|
17
|
+
output ({ value => results })
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/stages.gemspec
CHANGED
@@ -5,31 +5,39 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "stages"
|
8
|
-
s.version = "0.0
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = ["
|
12
|
-
s.date = "2012-01-
|
11
|
+
s.authors = ["The Justice Eight"]
|
12
|
+
s.date = "2012-01-14"
|
13
13
|
s.description = "pipeline builder"
|
14
14
|
s.email = "support@igodigital.com"
|
15
15
|
s.extra_rdoc_files = [
|
16
|
-
"README"
|
16
|
+
"README.md"
|
17
17
|
]
|
18
18
|
s.files = [
|
19
19
|
".autotest",
|
20
20
|
"Gemfile",
|
21
21
|
"Gemfile.lock",
|
22
|
-
"README",
|
22
|
+
"README.md",
|
23
23
|
"Rakefile",
|
24
24
|
"VERSION",
|
25
|
+
"examples/sing.rb",
|
26
|
+
"examples/sing_subpipes.rb",
|
25
27
|
"lib/stage_base.rb",
|
26
28
|
"lib/stages.rb",
|
29
|
+
"lib/stages/count.rb",
|
27
30
|
"lib/stages/each_element.rb",
|
31
|
+
"lib/stages/each_input.rb",
|
28
32
|
"lib/stages/evens.rb",
|
29
33
|
"lib/stages/hash_lookup.rb",
|
30
34
|
"lib/stages/map.rb",
|
31
35
|
"lib/stages/multiples_of.rb",
|
36
|
+
"lib/stages/restrict.rb",
|
37
|
+
"lib/stages/resume.rb",
|
38
|
+
"lib/stages/resume_count.rb",
|
32
39
|
"lib/stages/select.rb",
|
40
|
+
"lib/stages/sub_stage.rb",
|
33
41
|
"stages.gemspec",
|
34
42
|
"test/helper.rb",
|
35
43
|
"test/test_pipeline.rb",
|
data/test/test_pipeline.rb
CHANGED
@@ -10,19 +10,19 @@ class TestPipeline < MiniTest::Unit::TestCase
|
|
10
10
|
mx3.source = evens
|
11
11
|
mx7.source = mx3
|
12
12
|
|
13
|
-
result = (0..2).map{
|
13
|
+
result = (0..2).map{ mx7.run }
|
14
14
|
assert_equal([0, 42, 84], result)
|
15
15
|
end
|
16
16
|
|
17
17
|
test 'pipeline pipe syntax works' do
|
18
18
|
pipeline = Evens.new | MultiplesOf.new(3) | MultiplesOf.new(7)
|
19
|
-
result = (0..2).map{
|
19
|
+
result = (0..2).map{ pipeline.run }
|
20
20
|
assert_equal([0, 42, 84], result)
|
21
21
|
end
|
22
22
|
|
23
23
|
test 'block stages work' do
|
24
24
|
pipeline = Evens.new | Map.new{ |x| x * 3} | Select.new{ |x| x % 7 == 0}
|
25
|
-
result = (0..2).map{
|
25
|
+
result = (0..2).map{ pipeline.run }
|
26
26
|
assert_equal([0, 42, 84], result)
|
27
27
|
end
|
28
28
|
|
@@ -43,14 +43,5 @@ class TestPipeline < MiniTest::Unit::TestCase
|
|
43
43
|
end
|
44
44
|
assert_equal([1, 2], result)
|
45
45
|
end
|
46
|
-
|
47
|
-
def sing
|
48
|
-
{ :do => 'doe a deer a female deer',
|
49
|
-
:re => 'ray a drop of golden sun',
|
50
|
-
:mi => 'me a name I call myself',
|
51
|
-
:fa => 'far a long long way to run',
|
52
|
-
:so => 'A needle pulling thread',
|
53
|
-
:la => 'a note to follow so',
|
54
|
-
:ti => 'a drink with jam and bread'}
|
55
|
-
end
|
46
|
+
|
56
47
|
end
|
data/test/test_stages.rb
CHANGED
@@ -11,34 +11,82 @@ class TestStages < MiniTest::Unit::TestCase
|
|
11
11
|
|
12
12
|
test 'select' do
|
13
13
|
pipeline = Evens.new | Select.new{ |val| val > 6}
|
14
|
-
result = (0..2).map{
|
14
|
+
result = (0..2).map{ pipeline.run }
|
15
15
|
assert_equal([8, 10, 12], result)
|
16
16
|
end
|
17
17
|
|
18
18
|
test 'map' do
|
19
19
|
pipeline = Evens.new | Map.new{ |val| val * 3}
|
20
|
-
result = (0..2).map{
|
20
|
+
result = (0..2).map{ pipeline.run }
|
21
21
|
assert_equal([0, 6, 12], result)
|
22
22
|
end
|
23
23
|
|
24
24
|
test 'multiples_of' do
|
25
25
|
pipeline = Evens.new | MultiplesOf.new(3)
|
26
|
-
result = (0..3).map{
|
26
|
+
result = (0..3).map{ pipeline.run }
|
27
27
|
assert_equal([0, 6, 12, 18], result)
|
28
28
|
end
|
29
29
|
|
30
30
|
test 'each_element' do
|
31
31
|
pipeline = EachElement.new([1, 2, 3])
|
32
|
-
result = (0..2).map{
|
32
|
+
result = (0..2).map{ pipeline.run }
|
33
33
|
assert_equal([1, 2, 3], result)
|
34
34
|
end
|
35
35
|
|
36
36
|
test 'hash_lookup' do
|
37
37
|
pipeline = EachElement.new([:do, :re, :mi]) | HashLookup.new(sing)
|
38
|
-
result = (0..2).map{
|
38
|
+
result = (0..2).map { pipeline.run }
|
39
39
|
assert_equal(['doe a deer a female deer', 'ray a drop of golden sun', 'me a name I call myself'], result)
|
40
40
|
end
|
41
41
|
|
42
|
+
test 'restrict' do
|
43
|
+
pipeline = Evens.new | Restrict.new | Map.new{ |x| x * 2}
|
44
|
+
result = []
|
45
|
+
while v = pipeline.run
|
46
|
+
result << v
|
47
|
+
end
|
48
|
+
assert_equal([0], result)
|
49
|
+
pipeline.continue
|
50
|
+
while v = pipeline.run
|
51
|
+
result << v
|
52
|
+
end
|
53
|
+
assert_equal([0, 4], result)
|
54
|
+
end
|
55
|
+
|
56
|
+
test 'each_input' do
|
57
|
+
pipeline = EachElement.new([[1, 2], [3, 4]]) | EachInput.new
|
58
|
+
result = []
|
59
|
+
while v = pipeline.run
|
60
|
+
result << v
|
61
|
+
end
|
62
|
+
assert_equal([1, 2, 3, 4], result)
|
63
|
+
end
|
64
|
+
|
65
|
+
test 'resume' do
|
66
|
+
pipeline = EachElement.new(%w(foo bar)) | Restrict.new | EachInput.new{ |x| x.chars} | Resume.new
|
67
|
+
result = []
|
68
|
+
while v = pipeline.run
|
69
|
+
result << v
|
70
|
+
end
|
71
|
+
assert_equal([{ 'foo' => %w(f o o)}, {'bar' => %w(b a r)}], result)
|
72
|
+
end
|
73
|
+
|
74
|
+
test 'resume with count' do
|
75
|
+
resume = ResumeCount.new
|
76
|
+
pipeline = EachElement.new(%w(foo bar)) | Restrict.new | EachInput.new{ |x| x.chars} | Map.new{ |x| x.to_sym } | resume
|
77
|
+
result = pipeline.run
|
78
|
+
assert_equal({ 'foo' => { :f => 1, :o => 2}}, result)
|
79
|
+
end
|
80
|
+
|
81
|
+
test 'substage instead of resume' do
|
82
|
+
sub = EachInput.new{ |x| x.chars } | Map.new{ |x| x.to_sym} | Count.new
|
83
|
+
pipeline = EachElement.new(%w(foo bar)) | SubStage.new(sub)
|
84
|
+
result = pipeline.run
|
85
|
+
assert_equal({ 'foo' => { :f => 1, :o => 2}}, result)
|
86
|
+
result = pipeline.run
|
87
|
+
assert_equal({ 'bar' => { :b => 1, :a => 1, :r => 1}}, result)
|
88
|
+
end
|
89
|
+
|
42
90
|
def sing
|
43
91
|
{ :do => 'doe a deer a female deer',
|
44
92
|
:re => 'ray a drop of golden sun',
|
metadata
CHANGED
@@ -2,18 +2,15 @@
|
|
2
2
|
name: stages
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0
|
5
|
+
version: 0.1.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
|
-
-
|
9
|
-
- Justin Hill
|
10
|
-
- Matt Brown
|
11
|
-
- Kyle Prifogle
|
8
|
+
- The Justice Eight
|
12
9
|
autorequire:
|
13
10
|
bindir: bin
|
14
11
|
cert_chain: []
|
15
12
|
|
16
|
-
date: 2012-01-
|
13
|
+
date: 2012-01-14 00:00:00 Z
|
17
14
|
dependencies:
|
18
15
|
- !ruby/object:Gem::Dependency
|
19
16
|
name: rake
|
@@ -33,22 +30,30 @@ executables: []
|
|
33
30
|
extensions: []
|
34
31
|
|
35
32
|
extra_rdoc_files:
|
36
|
-
- README
|
33
|
+
- README.md
|
37
34
|
files:
|
38
35
|
- .autotest
|
39
36
|
- Gemfile
|
40
37
|
- Gemfile.lock
|
41
|
-
- README
|
38
|
+
- README.md
|
42
39
|
- Rakefile
|
43
40
|
- VERSION
|
41
|
+
- examples/sing.rb
|
42
|
+
- examples/sing_subpipes.rb
|
44
43
|
- lib/stage_base.rb
|
45
44
|
- lib/stages.rb
|
45
|
+
- lib/stages/count.rb
|
46
46
|
- lib/stages/each_element.rb
|
47
|
+
- lib/stages/each_input.rb
|
47
48
|
- lib/stages/evens.rb
|
48
49
|
- lib/stages/hash_lookup.rb
|
49
50
|
- lib/stages/map.rb
|
50
51
|
- lib/stages/multiples_of.rb
|
52
|
+
- lib/stages/restrict.rb
|
53
|
+
- lib/stages/resume.rb
|
54
|
+
- lib/stages/resume_count.rb
|
51
55
|
- lib/stages/select.rb
|
56
|
+
- lib/stages/sub_stage.rb
|
52
57
|
- stages.gemspec
|
53
58
|
- test/helper.rb
|
54
59
|
- test/test_pipeline.rb
|
@@ -66,7 +71,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
66
71
|
requirements:
|
67
72
|
- - ">="
|
68
73
|
- !ruby/object:Gem::Version
|
69
|
-
hash:
|
74
|
+
hash: 1745323606775845054
|
70
75
|
segments:
|
71
76
|
- 0
|
72
77
|
version: "0"
|