stages 0.0.1 → 0.1.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/.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"
|