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 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
- Returning nil from handle_value kills a pipeline. We may change this behavior in the future, but for now, it makes life easy.
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.3.4
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
- @fiber_delegate = Fiber.new do
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
- #seperate from reset! for restrict/resume purposes.
22
- def reset
23
- initialize_loop
24
- @source.reset if @source
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! if @source
44
+ @source.reset if @source
30
45
  end
31
46
 
32
47
  def die
33
48
  loop do
34
- output nil
49
+ output :stages_eos
35
50
  end
36
51
  end
37
52
 
38
53
  def process
39
- while value = input
40
- handle_value 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? ? nil : source.run
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
@@ -1,13 +1,9 @@
1
1
  module Stages
2
2
  class Cache < Stage
3
- def initialize()
4
- super()
5
- end
6
-
7
3
  def process
8
4
  cache = []
9
- while i = input
10
- cache << i
5
+ while !source_empty?
6
+ cache << input
11
7
  end
12
8
  cache.each{ |x| output x}
13
9
  end
data/lib/stages/count.rb CHANGED
@@ -1,15 +1,16 @@
1
1
  module Stages
2
2
  class Count < Stage
3
- def input
3
+ def process
4
4
  result = Hash.new{ |h, k| h[k] = 0 }
5
- while v = source.run
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
- result.empty? ? nil : result
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 v = input
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
- output thing
30
+ handle_value thing
31
31
  end
32
32
  end
33
33
  end
data/lib/stages/emit.rb CHANGED
@@ -4,8 +4,8 @@ module Stages
4
4
  @thing = thing
5
5
  super()
6
6
  end
7
-
8
- def process
7
+
8
+ def process
9
9
  output @thing
10
10
  end
11
11
  end
@@ -2,8 +2,8 @@ module Stages
2
2
  class Exhaust < Stage
3
3
  def process
4
4
  results = []
5
- while value = input
6
- results << value
5
+ while !source_empty?
6
+ results << input
7
7
  end
8
8
  output results
9
9
  end
@@ -2,7 +2,8 @@ module Stages
2
2
  class ExhaustCount < Stage
3
3
  def process
4
4
  results = 0
5
- while value = input
5
+ while !source_empty?
6
+ input
6
7
  results += 1
7
8
  end
8
9
  output results
data/lib/stages/map.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Stages
2
- class Map < Stage
2
+ class Map < Stage
3
3
  def handle_value(value)
4
4
  output @block.call(value)
5
5
  end
6
- end
6
+ end
7
7
  end
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 i = input
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| output x} if @prefetch
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 value = input
24
+ while !source_empty?
25
+ value = input
31
26
  subpipe = Emit.new(value) | @pipeline
32
27
  results = []
33
- while v = subpipe.run
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
@@ -28,14 +28,6 @@ module Stages
28
28
  ExhaustCount.new(*args, &block)
29
29
  end
30
30
 
31
- def restrict(*args, &block)
32
- Restrict.new(*args, &block)
33
- end
34
-
35
- def resume(*args, &block)
36
- Resume.new(*args, &block)
37
- end
38
-
39
31
  def group(*args, &block)
40
32
  Count.new
41
33
  end
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.3.4"
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-02"
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
@@ -46,7 +46,6 @@ class MiniTest::Unit
46
46
 
47
47
 
48
48
  @broken = nil
49
-
50
49
  @@out.print(case run_one inst
51
50
  when :pass
52
51
  @broken = false
@@ -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! resets everything' do
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 r = pipeline.run
94
- assert_equal(expected.pop, r)
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 r = pipeline.run
106
- results << r
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 r = pipeline.run
119
- results << r
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 excemption' do
127
+ test 'trying to pull from nil returns nil, not an exception' do
153
128
  pipeline = Unique.new
154
- assert_equal(nil, pipeline.run)
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 r = pipeline.run
30
- assert_equal(expected.pop, r)
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.3.4
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-02 00:00:00 Z
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: 2855126924498756477
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
-
@@ -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
@@ -1,16 +0,0 @@
1
- module Stages
2
- class Resume < Stage
3
- def input
4
- result = []
5
- while v = source.run
6
- result << v
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
@@ -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