stages 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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%^dataprocessing/pipeline(/stages)?/(.*).rb$%, true) do |filename, _|
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
 
@@ -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
- (0..2).map{ |x| pipeline.run } #[0, 42, 84]}
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 = ["Nathan Acuff", "Justin Hill", "Matt Brown", "Kyle Prifogle"]
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
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
- @fiber_delegate = Fiber.new do
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
- @fiber_delegate.resume
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=nil)
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
@@ -1,3 +1,3 @@
1
- require 'stage_base'
1
+ require "#{File.dirname(__FILE__)}/stage_base"
2
2
  Dir["#{File.dirname(__FILE__)}/stages/*.rb"].each { |file| require file.gsub(".rb", "")}
3
3
 
@@ -0,0 +1,11 @@
1
+ module Stages
2
+ class Count < 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
+ result.empty? ? nil : result
9
+ end
10
+ end
11
+ end
@@ -4,7 +4,7 @@ module Stages
4
4
  @things = things
5
5
  super()
6
6
  end
7
-
7
+
8
8
  def process
9
9
  @things.each do |thing|
10
10
  output thing
@@ -0,0 +1,10 @@
1
+ module Stages
2
+ class EachInput < Stage
3
+ def handle_value(value)
4
+ value = @block.call(value) if @block
5
+ value.each do |i|
6
+ output i
7
+ end
8
+ end
9
+ end
10
+ end
@@ -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 Resume < Stage
3
+ def input
4
+ result = []
5
+ while v = source.run
6
+ result << v
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,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.1"
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 = ["Nathan Acuff", "Justin Hill", "Matt Brown", "Kyle Prifogle"]
12
- s.date = "2012-01-13"
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",
@@ -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{ |x| mx7.run }
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{ |x| pipeline.run }
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{ |x| pipeline.run }
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{ |x| pipeline.run }
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{ |x| pipeline.run }
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{ |x| pipeline.run }
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{ |x| pipeline.run }
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{ |x| pipeline.run }
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.1
5
+ version: 0.1.0
6
6
  platform: ruby
7
7
  authors:
8
- - Nathan Acuff
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 00:00:00 Z
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: 4101338441187827743
74
+ hash: 1745323606775845054
70
75
  segments:
71
76
  - 0
72
77
  version: "0"