pipeliner 1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
File without changes
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2009 spox <spox@modspox.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,112 @@
1
+ == Pipeliner
2
+
3
+ The pipeliner library provides framework for message passing between objects. It allows objects to hook into the pipeline to receive certain types of objects, and process them in any way they see fit. Processing happens using a thread pool, letting message processing happen in an asynchronous fashion.
4
+
5
+ === install (easy):
6
+
7
+ gem install pipeliner
8
+
9
+ === install (less easy):
10
+
11
+ git clone http://github.com/spox/pipeliner.git
12
+ cd pipeliner && gem build *.gemspec && gem install ./
13
+
14
+ === install (less easy that's a little easier)
15
+
16
+ {rip}[http://hellorip.com/about.html] makes it easy to install directly from a github repository.
17
+
18
+ == Gritty Details
19
+
20
+ The pipeliner library allows for some fun things, and here is where I'll try and explain some of them. First, lets take a look at a simple example of this library in action:
21
+
22
+ require 'pipeliner'
23
+
24
+ output = Array.new
25
+ pipeline = Pipeliner::Pipeline.new
26
+ pipeline.hook(String){|s| output << "#{s}: modified"}
27
+ pipeline << "string"
28
+ pipeline << 100
29
+ p output
30
+
31
+ => ["string: modified"]
32
+
33
+ In the example above, we use a simple block to process any String type objects. Anything else passed placed in the pipeline is ignored by the block. We can also use objects instead of blocks:
34
+
35
+ require 'pipeliner'
36
+
37
+ class Tester < Pipeliner::Filter
38
+ attr_reader :store
39
+ def initialize
40
+ @store = []
41
+ end
42
+ def process(m)
43
+ @store << m
44
+ end
45
+ end
46
+
47
+ pipeline = Pipeliner::Pipeline.new
48
+ obj = Tester.new
49
+ pipeline.hook(Object, obj, :process)
50
+ pipeline << "String"
51
+ pipeline << 100
52
+ pipeline << {:test => :data}
53
+ p obj.store
54
+
55
+ => ["String", 100, {:test=>:data}]
56
+
57
+ But, what if you want anything added to the pipeline to be modified before it is distributed out to hooked processors? Well, then you would use a filter:
58
+
59
+ require 'pipeliner'
60
+
61
+ output = []
62
+ pipeline = Pipeliner::Pipeline.new
63
+ pipeline.filters.add(String){|s| "#{s} -> filtered"}
64
+ pipeline.hook(Object){|s| output << s}
65
+ pipeline << "string"
66
+ p output
67
+
68
+ => ["string -> filtered"]
69
+
70
+ Filters allow objects to be modified before reaching any hooked processors, and can even remove an unwanted object from the pipeline. Here is an example that removes all Symbols:
71
+
72
+ require 'pipeliner'
73
+
74
+ output = []
75
+ pipeline = Pipeliner::Pipeline.new
76
+ pipeline.filters.add(Symbol){|s| nil}
77
+ pipeline.hook(Object){|s| output << s}
78
+ pipeline << "string"
79
+ pipeline << 100
80
+ pipeline << :test
81
+ p output
82
+
83
+ => ["string", 100]
84
+
85
+ Filters can also be created using the Filter object:
86
+
87
+ require 'pipeliner'
88
+
89
+ class MyFilter < Pipeliner::Filter
90
+ def do_filter(m)
91
+ "#{m} - filtered"
92
+ end
93
+ end
94
+ output = []
95
+ pipeline = Pipeliner::Pipeline.new
96
+ filter = MyFilter.new(String)
97
+ pipeline.filters.add(String, filter)
98
+ pipeline.hook(Object){|s|output << s}
99
+ pipeline << "string"
100
+ pipeline << 100
101
+ p output
102
+
103
+ => ["string - filtered", 100]
104
+
105
+ == Last remarks
106
+
107
+ If you find any bugs, please report them through {github}[http://github.com/spox/pipeliner/issues]. If you are in need of any help, you can generally find me on DALnet and Freenode.
108
+
109
+ == License
110
+
111
+ Pipeliner is licensed under the MIT License
112
+ Copyright (c) 2009 spox <spox@modspox.com>
@@ -0,0 +1,31 @@
1
+ module Pipeliner
2
+ class Filter
3
+ # type of Objects filter is to be applied to
4
+ attr_reader :type
5
+ # t:: type of Objects filter is to be applied to
6
+ # Create a new Filter
7
+ def initialize(t)
8
+ raise ArgumentError.new('Expecting Class or String') unless [Class, String].include?(t.class)
9
+ @type = t
10
+ end
11
+
12
+ # o:: Object from Pipeline
13
+ # Applies filter to Object
14
+ def filter(o)
15
+ raise ArgumentError.new('Wrong type supplied to filter') unless Splib.type_of?(o, @type)
16
+ do_filter(o)
17
+ end
18
+
19
+ protected
20
+
21
+ # o:: Object to be filtered
22
+ # This is where the actual filtering takes place. This
23
+ # is the method to overload!
24
+ # NOTE: Objects can be filtered in any way. For a filter to
25
+ # basically "throw away" an Object, simply return nil and the
26
+ # Object will not be flushed down the Pipeline
27
+ def do_filter(o)
28
+ raise NoMethodError.new('This method has not been implemented')
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,109 @@
1
+ require 'pipeliner/Filter'
2
+ require 'thread'
3
+
4
+ module Pipeliner
5
+ class FilterManager
6
+ # Create a new FilterManager
7
+ def initialize
8
+ @filters = {}
9
+ @lock = Mutex.new
10
+ end
11
+
12
+ # type:: Object type to apply filter to
13
+ # filter:: Pipeline::Filter to add
14
+ # Add a Filter to be applied to the given types
15
+ def add(type, filter=nil, &block)
16
+ if((filter.nil? && !block_given?) || (filter && !filter.is_a?(Filter)))
17
+ raise ArgumentError.new('Filter or proc must be provided for filter')
18
+ end
19
+ const = Splib.find_const(type)
20
+ type = const unless const.nil?
21
+ @lock.synchronize do
22
+ @filters[type] ||= {}
23
+ end
24
+ if(block_given?)
25
+ unless(block.arity == 1 || block.arity < 0)
26
+ raise ArgumentError.new('Block must accept a parameter')
27
+ end
28
+ @lock.synchronize do
29
+ @filters[type][:procs] ||= []
30
+ unless(@filters[type][:procs].include?(block))
31
+ @filters[type][:procs] << block
32
+ end
33
+ end
34
+ end
35
+ if(filter)
36
+ @lock.synchronize do
37
+ unless(@filters[type].include?(filter))
38
+ @filters[type][:filters] ||= []
39
+ unless(@filters[type][:filters].include?(filter))
40
+ @filters[type][:filters] << filter
41
+ end
42
+ end
43
+ end
44
+ end
45
+ filter ? block_given? ? [filter, block] : filter : block
46
+ end
47
+
48
+ # filter:: Pipeline::Filter to remove
49
+ # type:: Object type filter is applied to.
50
+ # Remove Filter from given type. If no type is given all references
51
+ # to the given filter will be removed
52
+ def remove(filter, type=nil)
53
+ if(type)
54
+ const = Splib.find_const(type)
55
+ type = const unless const.nil?
56
+ end
57
+ @lock.synchronize do
58
+ (type ? [@filters[type]] : @filters.values).each do |set|
59
+ [:filters, :procs].each do |t|
60
+ if(set[t])
61
+ set[t].delete_if{|v| v == filter}
62
+ set.delete(t) if set[t].empty?
63
+ end
64
+ end
65
+ end
66
+ @filters.delete_if{|k,v|v.empty?}
67
+ end
68
+ nil
69
+ end
70
+
71
+ # type:: Object types
72
+ # Return filters of given type or all filters
73
+ # if not type is supplied
74
+ def filters(type=nil)
75
+ unless(type)
76
+ @filters.dup
77
+ else
78
+ const = Splib.find_const(type)
79
+ type = const unless const.nil?
80
+ @filters[type] ? @filters[type].dup : nil
81
+ end
82
+ end
83
+
84
+ # o:: Object to apply filters to
85
+ # Applies any Filters applicable to object type
86
+ def apply_filters(o)
87
+ @filters.keys.find_all{|type| Splib.type_of?(o, type)}.each do |type|
88
+ @filters[type].each_pair do |k,v|
89
+ begin
90
+ case k
91
+ when :filters
92
+ v.each{|f|o = f.filter(o)}
93
+ when :procs
94
+ v.each{|pr|o = pr.call(o)}
95
+ end
96
+ rescue ArgumentError
97
+ # ignore this
98
+ end
99
+ end
100
+ end
101
+ o
102
+ end
103
+
104
+ # Remove all filters
105
+ def clear
106
+ @filters.clear
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,154 @@
1
+ ['thread', 'splib', 'actionpool', 'pipeliner/FilterManager'].each{|f| require f}
2
+
3
+ Splib.load :Constants
4
+
5
+ module Pipeliner
6
+ class Pipeline
7
+ # args:: Hash containing initializations
8
+ # :pool =>:: ActionPool::Pool for the Pipeline to use
9
+ # :filters =>:: FilterManager for the Pipeline to use
10
+ # Create a new Pipeline
11
+ def initialize(args={})
12
+ @pool = args[:pool] ? args[:pool] : ActionPool::Pool.new
13
+ @hooks = {}
14
+ @lock = Mutex.new
15
+ @filters = args[:filters] ? args[:filters] : FilterManager.new
16
+ end
17
+
18
+ # Close the pipeline
19
+ # Note: This is important to at the end of a script when not
20
+ # providing an ActionPool thread pool to the pipeline.
21
+ # This will ensure the thread pool is properly shutdown
22
+ # and avoid the script hanging.
23
+ def close
24
+ @pool.shutdown
25
+ clear
26
+ @pool = nil
27
+ end
28
+
29
+ # Open the pipeline
30
+ def open
31
+ @pool = ActionPool::Pool.new unless @pool
32
+ end
33
+
34
+ # Returns current FilterManager
35
+ def filters
36
+ @filters
37
+ end
38
+
39
+ # fm:: FilterManager
40
+ # Set the FilterManager the Pipeline should use
41
+ def filters=(fm)
42
+ raise ArgumentError.new('Expecting a FilterManager') unless fm.is_a?(FilterManager)
43
+ @filters = fm
44
+ end
45
+
46
+ # type:: Type of Objects to pass to object
47
+ # object:: Object to hook to pipeline
48
+ # method:: Method to call on object
49
+ # block:: Block to apply to object (called without object and method set)
50
+ # Hooks an Object into the pipeline for objects of a given type
51
+ def hook(type, object=nil, method=nil, &block)
52
+ raise ArgumentError.new('No object information or block provided for hook') if !block_given? && object.nil? && method.nil?
53
+ raise ArgumentError.new('Block must accept a parameter') unless block.nil? || block.arity == 1 || block.arity < 0
54
+ @lock.synchronize do
55
+ const = Splib.find_const(type)
56
+ type = const unless const.nil?
57
+ @hooks[type] ||= {}
58
+ if(block_given?)
59
+ @hooks[type][:procs] ||= []
60
+ @hooks[type][:procs] << block
61
+ end
62
+ if(object && method)
63
+ name = object.class
64
+ method = method.to_sym
65
+ raise ArgumentError.new('Given object does not respond to given method') unless object.respond_to?(method)
66
+ @hooks[type][name] ||= []
67
+ @hooks[type][name] << {:object => object, :method => method}
68
+ end
69
+ end
70
+ block_given? ? block : nil
71
+ end
72
+
73
+ # object:: Object or Proc to unhook from the pipeline
74
+ # type:: Type of Objects being received
75
+ # method:: method registered to call
76
+ # Remove a hook from the pipeline. If the method and type are not
77
+ # specified, the given object will be removed from all hooks
78
+ def unhook(object, type=nil, method=nil)
79
+ raise ArgumentError.new('Object method provided for a Proc') if object.is_a?(Proc) && method
80
+ @lock.synchronize do
81
+ case object
82
+ when Proc
83
+ if(type)
84
+ @hooks[type][:procs].delete(object)
85
+ @hooks[type].delete(:procs) if @hooks[type][:procs].empty?
86
+ else
87
+ @hooks.each_value do |h|
88
+ h[:procs].delete(object)
89
+ h.delete(:procs) if h[:procs].empty?
90
+ end
91
+ end
92
+ else
93
+ if(method.nil? && type.nil?)
94
+ @hooks.each_value{|v|v.delete_if{|k,z| k == object.class}}
95
+ else
96
+ raise ArgumentError.new('Type must be provided') if type.nil?
97
+ const = Splib.find_const(type)
98
+ type = const unless const.nil?
99
+ method = method.to_sym if method
100
+ name = object.class
101
+ raise NameError.new('Uninitialized hook type given') unless @hooks[type]
102
+ raise StandardError.new('No hooks found for given object') unless @hooks[type][name]
103
+ if(method)
104
+ @hooks[type][name].delete_if{|x|x[:method] == method}
105
+ @hooks[type].delete(name) if @hooks[type][name].empty?
106
+ else
107
+ @hooks[type].delete(name)
108
+ end
109
+ end
110
+ end
111
+ @hooks.delete_if{|k,v|v.empty?}
112
+ end
113
+ end
114
+
115
+ # Return current hooks hash
116
+ def hooks
117
+ @lock.synchronize{ @hooks.dup }
118
+ end
119
+
120
+ # Remove all hooks from the pipeline
121
+ def clear
122
+ @lock.synchronize{ @hooks.clear }
123
+ end
124
+
125
+ # object:: Object to send down the pipeline
126
+ # Send an object down the pipeline
127
+ def <<(object)
128
+ raise StandardError.new('Pipeline is currently closed') if @pool.nil?
129
+ object = @filters.apply_filters(object)
130
+ if(object)
131
+ object.freeze
132
+ @pool.process{ flush(object) }
133
+ end
134
+ end
135
+
136
+ private
137
+
138
+ # o:: Object to flush
139
+ # Applies object to all matching hooks
140
+ def flush(o)
141
+ @hooks.keys.each do |type|
142
+ next unless Splib.type_of?(o, type)
143
+ @hooks[type].each_pair do |key, objects|
144
+ if(key == :procs)
145
+ objects.each{|pr| @pool.process{ pr.call(o) }}
146
+ else
147
+ objects.each{|h| @pool.process{ h[:object].send(h[:method], o)}}
148
+ end
149
+ end
150
+ end
151
+ nil
152
+ end
153
+ end
154
+ end
data/lib/pipeliner.rb ADDED
@@ -0,0 +1 @@
1
+ require 'pipeliner/Pipeline'
data/pipeliner.gemspec ADDED
@@ -0,0 +1,17 @@
1
+ spec = Gem::Specification.new do |s|
2
+ s.name = 'pipeliner'
3
+ s.author = 'spox'
4
+ s.email = 'spox@modspox.com'
5
+ s.version = '1.0'
6
+ s.summary = 'Object Pipeline'
7
+ s.platform = Gem::Platform::RUBY
8
+ s.files = Dir['**/*']
9
+ s.rdoc_options = %w(--title pipeliner --main README.rdoc --line-numbers)
10
+ s.extra_rdoc_files = %w(README.rdoc CHANGELOG)
11
+ s.require_paths = %w(lib)
12
+ s.required_ruby_version = '>= 1.8.6'
13
+ s.add_dependency 'ActionPool', '~> 0.2.0'
14
+ s.add_dependency 'splib', '~> 1.1'
15
+ s.homepage = %q(http://github.com/spox/pipeliner)
16
+ s.description = "Simple library to allow pipeline styled communications between objects"
17
+ end
@@ -0,0 +1,29 @@
1
+ require 'pipeliner'
2
+ require 'test/unit'
3
+
4
+ class FilterTest < Test::Unit::TestCase
5
+ def setup
6
+ end
7
+ def teardown
8
+ end
9
+
10
+ class MyFilter < Pipeliner::Filter
11
+ def do_filter(o)
12
+ return [o.to_sym]
13
+ end
14
+ end
15
+
16
+ def test_basic
17
+ assert_raise(ArgumentError){ Pipeliner::Filter.new }
18
+ a = Pipeliner::Filter.new(String)
19
+ assert_kind_of(Pipeliner::Filter, a)
20
+ assert_raise(ArgumentError){ a.filter([1,2]) }
21
+ assert_raise(NoMethodError){ a.filter('test') }
22
+ end
23
+
24
+ def test_custom
25
+ a = MyFilter.new(String)
26
+ assert_kind_of(Array, a.filter('test'))
27
+ assert_equal([:test], a.filter('test'))
28
+ end
29
+ end
@@ -0,0 +1,75 @@
1
+ require 'pipeliner'
2
+ require 'test/unit'
3
+
4
+ class FilterManagerTest < Test::Unit::TestCase
5
+ class MyFilter < Pipeliner::Filter
6
+ def do_filter(o)
7
+ "#{o}: filtered"
8
+ end
9
+ end
10
+ def setup
11
+ @fm = Pipeliner::FilterManager.new
12
+ @filter = MyFilter.new(String)
13
+ end
14
+ def teardown
15
+ @fm.clear
16
+ end
17
+
18
+ def test_add
19
+ @fm.add(String, @filter)
20
+ assert_equal(1, @fm.filters[String][:filters].size)
21
+ @fm.add(String, @filter)
22
+ assert_equal(1, @fm.filters[String][:filters].size)
23
+ @fm.add(String){|s|s}
24
+ assert_equal(1, @fm.filters[String][:procs].size)
25
+ assert_raise(ArgumentError) do
26
+ @fm.add(String, "string")
27
+ end
28
+ assert_raise(ArgumentError) do
29
+ @fm.add(Object)
30
+ end
31
+ @fm.clear
32
+ assert(@fm.filters.empty?)
33
+ @fm.add(String, @filter){|s|s}
34
+ assert_equal(1, @fm.filters[String][:filters].size)
35
+ assert_equal(1, @fm.filters[String][:procs].size)
36
+ end
37
+
38
+ def test_remove
39
+ @fm.add(String, @filter)
40
+ assert_equal(1, @fm.filters[String][:filters].size)
41
+ @fm.remove(@filter, String)
42
+ assert(!@fm.filters.has_key?(String))
43
+ @fm.add(String, @filter)
44
+ assert_equal(1, @fm.filters[String][:filters].size)
45
+ @fm.remove(@filter)
46
+ assert(!@fm.filters.has_key?(String))
47
+ pr = @fm.add(String){|s|s}
48
+ assert_equal(1, @fm.filters[String][:procs].size)
49
+ @fm.remove(pr, String)
50
+ assert(!@fm.filters.has_key?(String))
51
+ pr = @fm.add(String){|s|s}
52
+ assert_equal(1, @fm.filters[String][:procs].size)
53
+ @fm.remove(pr)
54
+ assert(!@fm.filters.has_key?(String))
55
+ end
56
+
57
+ def test_apply
58
+ @fm.add(String, @filter)
59
+ assert_equal("test: filtered", @fm.apply_filters("test"))
60
+ assert_equal(1, @fm.apply_filters(1))
61
+ data = "fubar"
62
+ assert_not_same(data, @fm.apply_filters(data))
63
+ data = [:fubar]
64
+ assert_same(data, @fm.apply_filters(data))
65
+ @fm.add(Fixnum){|o| "string"}
66
+ assert_kind_of(String, @fm.apply_filters(2))
67
+ end
68
+
69
+ def test_clear
70
+ @fm.add(String, @filter)
71
+ assert_equal(1, @fm.filters[String][:filters].size)
72
+ @fm.clear
73
+ assert(@fm.filters.empty?)
74
+ end
75
+ end
@@ -0,0 +1,111 @@
1
+ require 'pipeliner'
2
+ require 'test/unit'
3
+
4
+ class PipelineTest < Test::Unit::TestCase
5
+ class Tester
6
+ def initialize
7
+ @m = []
8
+ end
9
+ def method(s)
10
+ @m << s
11
+ end
12
+ def messages
13
+ @m
14
+ end
15
+ end
16
+ def setup
17
+ @pipeline = Pipeliner::Pipeline.new
18
+ end
19
+ def teardown
20
+ @pipeline.filters.clear
21
+ @pipeline.clear
22
+ @pipeline.close
23
+ end
24
+ def test_filters
25
+ assert_kind_of(Pipeliner::FilterManager, @pipeline.filters)
26
+ end
27
+ def test_set_filters
28
+ fm = Pipeliner::FilterManager.new
29
+ assert_not_same(fm, @pipeline.filters)
30
+ @pipeline.filters = fm
31
+ assert_same(fm, @pipeline.filters)
32
+ end
33
+ def test_hook_addition
34
+ assert_raise(ArgumentError){ @pipeline.hook(String) }
35
+ assert_raise(ArgumentError){ @pipeline.hook(String){ true } }
36
+ assert_raise(ArgumentError){ @pipeline.hook(String){|a,b| true} }
37
+ assert_kind_of(Proc, @pipeline.hook(String){|a| true })
38
+ assert_kind_of(Proc, @pipeline.hook(String){|a, *b| true })
39
+ assert_kind_of(Proc, @pipeline.hook(String){|*a| true })
40
+ assert_equal(1, @pipeline.hooks.size)
41
+ assert_equal(3, @pipeline.hooks[String][:procs].size)
42
+ @pipeline.clear
43
+ assert(@pipeline.hooks.empty?)
44
+ object = Tester.new
45
+ assert_nil(@pipeline.hook(String, object, :method))
46
+ assert_equal(1, @pipeline.hooks[String][object.class].size)
47
+ end
48
+ def test_hook_deletion
49
+ pr = @pipeline.hook(String){|a| true}
50
+ assert_kind_of(Proc, pr)
51
+ assert_equal(1, @pipeline.hooks[String][:procs].size)
52
+ @pipeline.unhook(pr, String)
53
+ assert(@pipeline.hooks.empty?)
54
+ object = Tester.new
55
+ @pipeline.hook(String, object, :method)
56
+ assert_equal(1, @pipeline.hooks[String].size)
57
+ @pipeline.unhook(object, String, :method)
58
+ assert(@pipeline.hooks.empty?)
59
+ @pipeline.hook(String, object, :method)
60
+ assert_equal(1, @pipeline.hooks[String].size)
61
+ @pipeline.unhook(object, String)
62
+ assert(@pipeline.hooks.empty?)
63
+ @pipeline.hook(String, object, :method)
64
+ assert_equal(1, @pipeline.hooks[String].size)
65
+ @pipeline.unhook(object)
66
+ assert(@pipeline.hooks.empty?)
67
+ @pipeline.hook(String, object, :method)
68
+ @pipeline.hook(Object){|a|true}
69
+ assert_equal(2, @pipeline.hooks.size)
70
+ @pipeline.clear
71
+ assert(@pipeline.hooks.empty?)
72
+ end
73
+ def test_flush
74
+ out = []
75
+ assert(out.empty?)
76
+ @pipeline.hook(String){|x|out << x}
77
+ assert_equal(1, @pipeline.hooks.size)
78
+ @pipeline << "Fubar"
79
+ sleep(0.01)
80
+ assert_equal(1, out.size)
81
+ assert_equal("Fubar", out.pop)
82
+ @pipeline << 100
83
+ sleep(0.01)
84
+ assert(out.empty?)
85
+ object = Tester.new
86
+ @pipeline.hook(String, object, :method)
87
+ @pipeline.hook(Fixnum, object, :method)
88
+ assert_equal(2, @pipeline.hooks[String].size)
89
+ assert_equal(2, @pipeline.hooks.size)
90
+ @pipeline << 'test'
91
+ sleep(0.01)
92
+ assert_equal(object.messages.pop, out.pop)
93
+ @pipeline << 1
94
+ sleep(0.01)
95
+ assert(out.empty?)
96
+ assert_equal(1, object.messages.pop)
97
+ end
98
+ def test_filters
99
+ out = []
100
+ @pipeline.filters.add(String){|s|10}
101
+ @pipeline.hook(Object){|s|out << s}
102
+ @pipeline << 'fubar'
103
+ assert(out.include?(10))
104
+ assert(!out.include?('fubar'))
105
+ @pipeline.filters.clear
106
+ out.clear
107
+ @pipeline.filters.add(String){|s|nil}
108
+ @pipeline << 'test'
109
+ assert(out.empty?)
110
+ end
111
+ end
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH.unshift(File.expand_path("#{__FILE__}/../../lib"))
2
+
3
+ require 'test/unit'
4
+ require 'pipeliner'
5
+
6
+ Dir.new("#{File.dirname(__FILE__)}/cases").each{|f|
7
+ require "#{File.dirname(__FILE__)}/cases/#{f}" if f[-2..f.size] == 'rb'
8
+ }
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pipeliner
3
+ version: !ruby/object:Gem::Version
4
+ version: "1.0"
5
+ platform: ruby
6
+ authors:
7
+ - spox
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-30 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ActionPool
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 0.2.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: splib
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: "1.1"
34
+ version:
35
+ description: Simple library to allow pipeline styled communications between objects
36
+ email: spox@modspox.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README.rdoc
43
+ - CHANGELOG
44
+ files:
45
+ - tests/cases/Filter.rb
46
+ - tests/cases/FilterManager.rb
47
+ - tests/cases/Pipeline.rb
48
+ - tests/run_tests.rb
49
+ - lib/pipeliner/Filter.rb
50
+ - lib/pipeliner/FilterManager.rb
51
+ - lib/pipeliner/Pipeline.rb
52
+ - lib/pipeliner.rb
53
+ - CHANGELOG
54
+ - LICENSE
55
+ - README.rdoc
56
+ - pipeliner.gemspec
57
+ has_rdoc: true
58
+ homepage: http://github.com/spox/pipeliner
59
+ licenses: []
60
+
61
+ post_install_message:
62
+ rdoc_options:
63
+ - --title
64
+ - pipeliner
65
+ - --main
66
+ - README.rdoc
67
+ - --line-numbers
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 1.8.6
75
+ version:
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ version:
82
+ requirements: []
83
+
84
+ rubyforge_project:
85
+ rubygems_version: 1.3.5
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: Object Pipeline
89
+ test_files: []
90
+