stages 0.3.4 → 0.4.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 +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
|