stages 0.3.4 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +15 -1
- data/VERSION +1 -1
- data/lib/stage_base.rb +33 -11
- data/lib/stages/cache.rb +2 -6
- data/lib/stages/count.rb +4 -3
- data/lib/stages/each.rb +7 -7
- data/lib/stages/emit.rb +2 -2
- data/lib/stages/exhaust.rb +2 -2
- data/lib/stages/exhaust_count.rb +2 -1
- data/lib/stages/map.rb +2 -2
- data/lib/stages/unique.rb +3 -2
- data/lib/stages/wrap.rb +7 -11
- data/lib/sugar.rb +0 -8
- data/stages.gemspec +2 -6
- data/test/helper.rb +0 -1
- data/test/test_pipeline.rb +2 -2
- data/test/test_stages.rb +14 -39
- data/test/test_syntax.rb +2 -11
- metadata +3 -7
- data/examples/sing.rb +0 -48
- data/lib/stages/restrict.rb +0 -27
- data/lib/stages/resume.rb +0 -16
- data/lib/stages/resume_count.rb +0 -16
data/README.md
CHANGED
@@ -45,6 +45,20 @@ If you are writing a generator, you probably want to subclass Stage and implemen
|
|
45
45
|
Stern Warnings
|
46
46
|
--------------
|
47
47
|
|
48
|
-
|
48
|
+
There are BREAKING CHANGES in 0.4.0. Nil and false no longer kill pipelines, there is a special value that does that. If you are overriding process and have a construct like this:
|
49
|
+
```ruby
|
50
|
+
while v = input
|
51
|
+
do_things v
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
You will need to replace it with something like this:
|
56
|
+
```ruby
|
57
|
+
while !source_empty?
|
58
|
+
do_things input
|
59
|
+
end
|
60
|
+
```
|
61
|
+
But, your pipelines now treat nil and false as perfectly valid values. It's breaking, but it's probably an improvement.
|
62
|
+
|
49
63
|
|
50
64
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/lib/stage_base.rb
CHANGED
@@ -8,36 +8,51 @@ module Stages
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def initialize_loop
|
11
|
-
|
11
|
+
@done = false
|
12
|
+
@cached_value = :stages_empty_cache
|
13
|
+
@fiber_delegate = Fiber.new do
|
12
14
|
process
|
15
|
+
@done = true
|
13
16
|
die
|
14
17
|
end
|
15
18
|
end
|
16
19
|
|
17
20
|
def run
|
21
|
+
if @cached_value != :stages_empty_cache
|
22
|
+
v = @cached_value
|
23
|
+
@cached_value = :stages_empty_cache
|
24
|
+
return v
|
25
|
+
end
|
18
26
|
@fiber_delegate.resume
|
19
27
|
end
|
20
28
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
29
|
+
def done?
|
30
|
+
return true if @done
|
31
|
+
return false if @cached_value != :stages_empty_cache
|
32
|
+
next_value = @fiber_delegate.resume
|
33
|
+
if next_value == :stages_eos
|
34
|
+
@done = true
|
35
|
+
@cached_value = :stages_empty_cache
|
36
|
+
return true
|
37
|
+
end
|
38
|
+
@cached_value = next_value
|
39
|
+
return false
|
25
40
|
end
|
26
41
|
|
27
|
-
def reset
|
42
|
+
def reset
|
28
43
|
initialize_loop
|
29
|
-
@source.reset
|
44
|
+
@source.reset if @source
|
30
45
|
end
|
31
46
|
|
32
47
|
def die
|
33
48
|
loop do
|
34
|
-
output
|
49
|
+
output :stages_eos
|
35
50
|
end
|
36
51
|
end
|
37
52
|
|
38
53
|
def process
|
39
|
-
while
|
40
|
-
handle_value
|
54
|
+
while !source_empty?
|
55
|
+
handle_value input
|
41
56
|
end
|
42
57
|
end
|
43
58
|
|
@@ -45,8 +60,12 @@ module Stages
|
|
45
60
|
output value
|
46
61
|
end
|
47
62
|
|
63
|
+
def source_empty?
|
64
|
+
(source.nil? || source.done?)
|
65
|
+
end
|
66
|
+
|
48
67
|
def input
|
49
|
-
source.nil? ?
|
68
|
+
source.nil? ? :stages_eos : source.run
|
50
69
|
end
|
51
70
|
|
52
71
|
def output(value)
|
@@ -59,6 +78,9 @@ module Stages
|
|
59
78
|
other
|
60
79
|
end
|
61
80
|
|
81
|
+
#root_source lets you add to existing pipelines
|
82
|
+
#the result is always the rightmost stage
|
83
|
+
#so adding things to it is problematic
|
62
84
|
def root_source
|
63
85
|
source.nil? ? self : source.root_source
|
64
86
|
end
|
data/lib/stages/cache.rb
CHANGED
data/lib/stages/count.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
module Stages
|
2
2
|
class Count < Stage
|
3
|
-
def
|
3
|
+
def process
|
4
4
|
result = Hash.new{ |h, k| h[k] = 0 }
|
5
|
-
while
|
5
|
+
while !source_empty?
|
6
|
+
v = source.run
|
6
7
|
if v.is_a? Hash
|
7
8
|
v.each_pair{ |key, value| result[key] += (value || 0) }
|
8
9
|
else
|
9
10
|
result[v] += 1
|
10
11
|
end
|
11
12
|
end
|
12
|
-
|
13
|
+
handle_value result
|
13
14
|
end
|
14
15
|
end
|
15
16
|
end
|
data/lib/stages/each.rb
CHANGED
@@ -5,29 +5,29 @@ module Stages
|
|
5
5
|
@block = block
|
6
6
|
super()
|
7
7
|
end
|
8
|
-
|
9
|
-
def process
|
8
|
+
|
9
|
+
def process
|
10
10
|
if @things
|
11
11
|
process_things
|
12
12
|
else
|
13
13
|
process_inputs
|
14
14
|
end
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def process_inputs
|
18
|
-
while
|
18
|
+
while !source_empty?
|
19
|
+
v = input
|
19
20
|
v = @block.call(v) if @block
|
20
21
|
v.each do |v|
|
21
22
|
output v
|
22
23
|
end
|
23
24
|
end
|
24
25
|
end
|
25
|
-
|
26
|
+
|
26
27
|
def process_things
|
27
28
|
@things = @block.call(@things) if @block
|
28
|
-
output nil if @things.nil?
|
29
29
|
@things.each do |thing|
|
30
|
-
|
30
|
+
handle_value thing
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
data/lib/stages/emit.rb
CHANGED
data/lib/stages/exhaust.rb
CHANGED
data/lib/stages/exhaust_count.rb
CHANGED
data/lib/stages/map.rb
CHANGED
data/lib/stages/unique.rb
CHANGED
@@ -9,11 +9,12 @@ module Stages
|
|
9
9
|
|
10
10
|
def process
|
11
11
|
set = Set.new
|
12
|
-
while
|
12
|
+
while !source_empty?
|
13
|
+
i = input
|
13
14
|
added = set.add? i
|
14
15
|
handle_value i if added && !@prefetch
|
15
16
|
end
|
16
|
-
set.each{ |x|
|
17
|
+
set.each{ |x| handle_value x} if @prefetch
|
17
18
|
set = nil
|
18
19
|
end
|
19
20
|
end
|
data/lib/stages/wrap.rb
CHANGED
@@ -16,30 +16,26 @@ module Stages
|
|
16
16
|
|
17
17
|
def reset
|
18
18
|
initialize_loop
|
19
|
-
@pipeline.reset
|
19
|
+
@pipeline.reset
|
20
20
|
@source.reset if @source
|
21
21
|
end
|
22
22
|
|
23
|
-
def reset!
|
24
|
-
initialize_loop
|
25
|
-
@pipeline.reset!
|
26
|
-
@source.reset! if @source
|
27
|
-
end
|
28
|
-
|
29
23
|
def process
|
30
|
-
while
|
24
|
+
while !source_empty?
|
25
|
+
value = input
|
31
26
|
subpipe = Emit.new(value) | @pipeline
|
32
27
|
results = []
|
33
|
-
while
|
28
|
+
while !subpipe.done?
|
29
|
+
v = subpipe.run
|
34
30
|
@output_style == :each ? output(v) : results << v
|
35
31
|
end
|
36
32
|
results = results.first if @aggregated
|
37
33
|
output results if @output_style == :array
|
38
34
|
output({ value => results}) if @output_style == :hash
|
39
35
|
@pipeline.drop_leftmost!
|
40
|
-
@pipeline.reset
|
36
|
+
@pipeline.reset
|
41
37
|
end
|
42
|
-
@pipeline.reset
|
38
|
+
@pipeline.reset
|
43
39
|
end
|
44
40
|
end
|
45
41
|
end
|
data/lib/sugar.rb
CHANGED
data/stages.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "stages"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["The Justice Eight"]
|
12
|
-
s.date = "2012-04-
|
12
|
+
s.date = "2012-04-12"
|
13
13
|
s.description = "pipeline builder"
|
14
14
|
s.email = "support@igodigital.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -22,7 +22,6 @@ Gem::Specification.new do |s|
|
|
22
22
|
"README.md",
|
23
23
|
"Rakefile",
|
24
24
|
"VERSION",
|
25
|
-
"examples/sing.rb",
|
26
25
|
"examples/sing_custom_stages.rb",
|
27
26
|
"examples/sing_subpipes.rb",
|
28
27
|
"lib/stage_base.rb",
|
@@ -34,9 +33,6 @@ Gem::Specification.new do |s|
|
|
34
33
|
"lib/stages/exhaust.rb",
|
35
34
|
"lib/stages/exhaust_count.rb",
|
36
35
|
"lib/stages/map.rb",
|
37
|
-
"lib/stages/restrict.rb",
|
38
|
-
"lib/stages/resume.rb",
|
39
|
-
"lib/stages/resume_count.rb",
|
40
36
|
"lib/stages/select.rb",
|
41
37
|
"lib/stages/unique.rb",
|
42
38
|
"lib/stages/wrap.rb",
|
data/test/helper.rb
CHANGED
data/test/test_pipeline.rb
CHANGED
@@ -53,10 +53,10 @@ class TestPipeline < MiniTest::Unit::TestCase
|
|
53
53
|
assert_equal({ 'bar' => { :b => 1, :a => 1, :r => 1}}, result)
|
54
54
|
end
|
55
55
|
|
56
|
-
test 'reset
|
56
|
+
test 'reset resets everything' do
|
57
57
|
pipeline = Each.new([1, 2, 3])
|
58
58
|
assert_equal(1, pipeline.run)
|
59
|
-
pipeline.reset
|
59
|
+
pipeline.reset
|
60
60
|
assert_equal(1, pipeline.run)
|
61
61
|
assert_equal(2, pipeline.run)
|
62
62
|
end
|
data/test/test_stages.rb
CHANGED
@@ -32,36 +32,6 @@ class TestStages < MiniTest::Unit::TestCase
|
|
32
32
|
assert_equal(['doe a deer a female deer', 'ray a drop of golden sun', 'me a name I call myself'], result)
|
33
33
|
end
|
34
34
|
|
35
|
-
test 'restrict' do
|
36
|
-
pipeline = Evens.new | Restrict.new | Map.new{ |x| x * 2}
|
37
|
-
result = []
|
38
|
-
while v = pipeline.run
|
39
|
-
result << v
|
40
|
-
end
|
41
|
-
assert_equal([0], result)
|
42
|
-
pipeline.reset
|
43
|
-
while v = pipeline.run
|
44
|
-
result << v
|
45
|
-
end
|
46
|
-
assert_equal([0, 4], result)
|
47
|
-
end
|
48
|
-
|
49
|
-
test 'resume' do
|
50
|
-
pipeline = Each.new(%w(foo bar)) | Restrict.new | Each.new{ |x| x.chars} | Resume.new
|
51
|
-
result = []
|
52
|
-
while v = pipeline.run
|
53
|
-
result << v
|
54
|
-
end
|
55
|
-
assert_equal([{ 'foo' => %w(f o o)}, {'bar' => %w(b a r)}], result)
|
56
|
-
end
|
57
|
-
|
58
|
-
test 'resume with count' do
|
59
|
-
resume = ResumeCount.new
|
60
|
-
pipeline = Each.new(%w(foo bar)) | Restrict.new | Each.new{ |x| x.chars} | Map.new{ |x| x.to_sym } | resume
|
61
|
-
result = pipeline.run
|
62
|
-
assert_equal({ 'foo' => { :f => 1, :o => 2}}, result)
|
63
|
-
end
|
64
|
-
|
65
35
|
test 'hash mode wrap' do
|
66
36
|
pipeline = Each.new(%w(foo bar)) | Wrap.new(Each.new{ |x| x.chars})
|
67
37
|
result = pipeline.run
|
@@ -90,20 +60,25 @@ class TestStages < MiniTest::Unit::TestCase
|
|
90
60
|
test 'each mode wrap' do
|
91
61
|
pipeline = Each.new(%w(foo bar)) | Wrap.new(Each.new{ |x| x.chars}, :each)
|
92
62
|
expected = %w(r a b o o f)
|
93
|
-
while
|
94
|
-
assert_equal(expected.pop,
|
63
|
+
while !pipeline.done?
|
64
|
+
assert_equal(expected.pop, pipeline.run)
|
95
65
|
end
|
96
66
|
end
|
97
67
|
|
68
|
+
test 'nil makes it through' do
|
69
|
+
pipeline = Each.new([1, 2, nil, 4]) | Map.new{ |x| x.nil? ? x : x*2} | Exhaust.new
|
70
|
+
result = pipeline.run
|
71
|
+
assert_equal([2, 4, nil, 8], result)
|
72
|
+
end
|
98
73
|
|
99
74
|
test 'unique-jit' do
|
100
75
|
order = []
|
101
76
|
pipeline = Each.new('abcadefbega'){ |x| x.chars} |
|
102
|
-
Map.new{ |x| order << 'a'; x} | Unique.new|
|
77
|
+
Map.new{ |x| order << 'a'; x} | Unique.new |
|
103
78
|
Map.new{ |x| order << 'b'; x}
|
104
79
|
results = []
|
105
|
-
while
|
106
|
-
results <<
|
80
|
+
while !pipeline.done?
|
81
|
+
results << pipeline.run
|
107
82
|
end
|
108
83
|
assert_equal(%w(a b c d e f g), results)
|
109
84
|
assert_equal(%w(a b a b a b a a b a b a b a a a b a), order)
|
@@ -115,8 +90,8 @@ class TestStages < MiniTest::Unit::TestCase
|
|
115
90
|
Map.new{ |x| order << 'a'; x} | Unique.new(prefetch: true) |
|
116
91
|
Map.new{ |x| order << 'b'; x}
|
117
92
|
results = []
|
118
|
-
while
|
119
|
-
results <<
|
93
|
+
while !pipeline.done?
|
94
|
+
results << pipeline.run
|
120
95
|
end
|
121
96
|
assert_equal(%w(a b c d e f g), results)
|
122
97
|
assert_equal(['a']*11 + ['b']*7, order)
|
@@ -149,9 +124,9 @@ class TestStages < MiniTest::Unit::TestCase
|
|
149
124
|
assert_equal({ a: 2}, pipeline.run)
|
150
125
|
end
|
151
126
|
|
152
|
-
test 'trying to pull from nil returns nil, not an
|
127
|
+
test 'trying to pull from nil returns nil, not an exception' do
|
153
128
|
pipeline = Unique.new
|
154
|
-
|
129
|
+
assert pipeline.done?
|
155
130
|
end
|
156
131
|
|
157
132
|
def sing
|
data/test/test_syntax.rb
CHANGED
@@ -14,20 +14,11 @@ class TestSyntax < MiniTest::Unit::TestCase
|
|
14
14
|
assert_equal({ 1 => 6}, pipeline.run)
|
15
15
|
end
|
16
16
|
|
17
|
-
test 'restrict and resume' do
|
18
|
-
pipeline = each(%w(foo bar)) | restrict | each{ |x| x.chars} | resume
|
19
|
-
result = []
|
20
|
-
while v = pipeline.run
|
21
|
-
result << v
|
22
|
-
end
|
23
|
-
assert_equal([{ 'foo' => %w(f o o)}, {'bar' => %w(b a r)}], result)
|
24
|
-
end
|
25
|
-
|
26
17
|
test 'wrap' do
|
27
18
|
pipeline = each(%w(foo bar)) | wrap(each{ |x| x.chars}, :each)
|
28
19
|
expected = %w(r a b o o f)
|
29
|
-
while
|
30
|
-
assert_equal(expected.pop,
|
20
|
+
while !pipeline.done?
|
21
|
+
assert_equal(expected.pop, pipeline.run)
|
31
22
|
end
|
32
23
|
end
|
33
24
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: stages
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.4.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- The Justice Eight
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-04-
|
13
|
+
date: 2012-04-12 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rake
|
@@ -38,7 +38,6 @@ files:
|
|
38
38
|
- README.md
|
39
39
|
- Rakefile
|
40
40
|
- VERSION
|
41
|
-
- examples/sing.rb
|
42
41
|
- examples/sing_custom_stages.rb
|
43
42
|
- examples/sing_subpipes.rb
|
44
43
|
- lib/stage_base.rb
|
@@ -50,9 +49,6 @@ files:
|
|
50
49
|
- lib/stages/exhaust.rb
|
51
50
|
- lib/stages/exhaust_count.rb
|
52
51
|
- lib/stages/map.rb
|
53
|
-
- lib/stages/restrict.rb
|
54
|
-
- lib/stages/resume.rb
|
55
|
-
- lib/stages/resume_count.rb
|
56
52
|
- lib/stages/select.rb
|
57
53
|
- lib/stages/unique.rb
|
58
54
|
- lib/stages/wrap.rb
|
@@ -75,7 +71,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
75
71
|
requirements:
|
76
72
|
- - ">="
|
77
73
|
- !ruby/object:Gem::Version
|
78
|
-
hash:
|
74
|
+
hash: -3184955072304030691
|
79
75
|
segments:
|
80
76
|
- 0
|
81
77
|
version: "0"
|
data/examples/sing.rb
DELETED
@@ -1,48 +0,0 @@
|
|
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 = Each.new sing.keys
|
18
|
-
loop = Restrict.new
|
19
|
-
get_lyric = Map.new{ |x| sing[x]}
|
20
|
-
each_character = Each.new{ |x| x.chars }
|
21
|
-
whitespace = Select.new{ |x| x != ' '}
|
22
|
-
pool = ResumeCount.new
|
23
|
-
subtotals = Map.new { |x| x.values.first }
|
24
|
-
iterator = Each.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
|
-
|
data/lib/stages/restrict.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
module Stages
|
2
|
-
class Restrict < Stage
|
3
|
-
|
4
|
-
def initialize
|
5
|
-
@open = true
|
6
|
-
super()
|
7
|
-
end
|
8
|
-
|
9
|
-
def reset
|
10
|
-
@open = true
|
11
|
-
r = @last_value
|
12
|
-
@last_value = nil
|
13
|
-
r
|
14
|
-
end
|
15
|
-
|
16
|
-
def process
|
17
|
-
while value = input
|
18
|
-
while !@open
|
19
|
-
handle_value nil
|
20
|
-
end
|
21
|
-
@open = false
|
22
|
-
@last_value = value
|
23
|
-
handle_value value
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/lib/stages/resume.rb
DELETED
data/lib/stages/resume_count.rb
DELETED
@@ -1,16 +0,0 @@
|
|
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.reset
|
9
|
-
if continued.nil?
|
10
|
-
nil
|
11
|
-
else
|
12
|
-
{ continued => result}
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|