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 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