eventpublisher 0.1.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.
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 Davy Brion (ralinx@davybrion.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 ADDED
@@ -0,0 +1,70 @@
1
+ The EventPublisher module enables you to define multiple events in a class, and have objects subscribe to them with either a Method instance, or a block. Subscribers can obviously also unsubscribe Method instances, though blocks can't be unsubscribed.
2
+
3
+ Here's a simple example that illustrates the usage of the EventPublisher module:
4
+
5
+ class Publisher
6
+ include EventPublisher
7
+ event :first_event
8
+ event :second_event
9
+
10
+ def trigger_events
11
+ trigger :first_event, "first event"
12
+ trigger :second_event, "second event", "extra argument"
13
+ end
14
+ end
15
+
16
+ class FirstSubscriber
17
+ def initialize(publisher)
18
+ @publisher = publisher
19
+ @publisher.subscribe_all self
20
+ end
21
+
22
+ def stop_listening
23
+ @publisher.unsubscribe_all self
24
+ end
25
+
26
+ def first_event_handler(args)
27
+ puts "first_event_handler of FirstSubscriber received #{args}"
28
+ end
29
+
30
+ def second_event_handler(arg1, arg2)
31
+ puts "second_event_handler of FirstSubscriber received arg1 = #{arg1} arg2 = #{arg2}"
32
+ end
33
+ end
34
+
35
+ class SecondSubscriber
36
+ def initialize(publisher)
37
+ @publisher = publisher
38
+ @publisher.subscribe :first_event, method(:first_handler)
39
+ @publisher.subscribe(:second_event) { |arg1, arg2| puts "block from SecondSubscriber received: #{arg1} #{arg2}"}
40
+ end
41
+
42
+ def stop_listening
43
+ @publisher.unsubscribe :first_event, method(:first_handler)
44
+ end
45
+
46
+ def first_handler(args)
47
+ puts "first_handler of SecondSubscriber received #{args}"
48
+ end
49
+ end
50
+
51
+
52
+ publisher = Publisher.new
53
+ first_subscriber = FirstSubscriber.new(publisher)
54
+ second_subscriber = SecondSubscriber.new(publisher)
55
+ puts "you should see 4 outputted strings when the events are triggered"
56
+ publisher.trigger_events
57
+ first_subscriber.stop_listening
58
+ second_subscriber.stop_listening
59
+ puts "you should still see 1 outputted string because the block is still subscribed, while the Method instances have been unsubscribed"
60
+ publisher.trigger_events
61
+
62
+ The output of running this code is the following:
63
+
64
+ you should see 4 outputted strings when the events are triggered
65
+ first_event_handler of FirstSubscriber received first event
66
+ first_handler of SecondSubscriber received first event
67
+ second_event_handler of FirstSubscriber received arg1 = second event arg2 = extra argument
68
+ block from SecondSubscriber received: second event extra argument
69
+ you should still see 1 outputted string because the block is still subscribed, while the Method instances have been unsubscribed
70
+ block from SecondSubscriber received: second event extra argument
@@ -0,0 +1,33 @@
1
+ require 'rake'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems'
4
+ require 'spec/rake/spectask'
5
+
6
+ gem_spec = Gem::Specification.new do |s|
7
+ s.name = 'eventpublisher'
8
+ s.version = '0.1.0'
9
+ s.has_rdoc = false
10
+ s.summary = 'A module which enables objects to publish multiple events, which other objects can subscribe to'
11
+ s.description = s.summary + ' See http://github.com/davybrion/EventPublisher for more information.'
12
+ s.homepage = "http://github.com/davybrion/EventPublisher"
13
+ s.author = 'Davy Brion'
14
+ s.email = 'ralinx@davybrion.com'
15
+ s.files = FileList['lib/**/*.rb', 'bin/*', '[A-Z]*', 'test/**/*'].to_a
16
+ s.require_path = "lib"
17
+ s.required_ruby_version = '>= 1.9.1'
18
+ s.bindir = "bin"
19
+ end
20
+
21
+ Rake::GemPackageTask.new(gem_spec) do |p|
22
+ p.gem_spec = gem_spec
23
+ end
24
+
25
+ Spec::Rake::SpecTask.new(:run_specs) do |t|
26
+ t.spec_files = FileList['test/*_spec.rb']
27
+ t.verbose = true
28
+ t.warning = true
29
+ t.spec_opts << "--format nested"
30
+ end
31
+
32
+ task :default => :run_specs
33
+
@@ -0,0 +1,94 @@
1
+ module EventPublisher
2
+ class Event
3
+ attr_reader :name
4
+
5
+ def initialize(name)
6
+ @name = name
7
+ @handlers = []
8
+ end
9
+
10
+ def add(method=nil, &block)
11
+ @handlers << method if method
12
+ @handlers << block if block
13
+ end
14
+
15
+ def has?(method)
16
+ @handlers.include? method
17
+ end
18
+
19
+ def remove(method)
20
+ @handlers.delete method if method
21
+ end
22
+
23
+ def trigger(*args)
24
+ @handlers.each { |handler| handler.call *args }
25
+ end
26
+ end
27
+
28
+ def subscribe_all(subscriber)
29
+ each_suitable_handler(subscriber) do |event_symbol, method_symbol|
30
+ subscribe event_symbol, subscriber.method(method_symbol)
31
+ end
32
+ end
33
+
34
+ def unsubscribe_all(subscriber)
35
+ each_suitable_handler(subscriber) do |event_symbol, method_symbol|
36
+ unsubscribe event_symbol, subscriber.method(method_symbol)
37
+ end
38
+ end
39
+
40
+ def subscribe(symbol, method=nil, &block)
41
+ event = send(symbol)
42
+ event.add method if method
43
+ event.add block if block
44
+ end
45
+
46
+ def unsubscribe(symbol, method)
47
+ event = send(symbol)
48
+ event.remove method
49
+ end
50
+
51
+ def subscribed?(symbol, method)
52
+ event = send(symbol)
53
+ event.has? method
54
+ end
55
+
56
+ private
57
+
58
+ def each_suitable_handler(subscriber)
59
+ possible_handlers = subscriber.class.instance_methods.select { |name| name =~ /\w_handler/ }
60
+ possible_handlers.each do |method_name|
61
+ event_name = /(?<event_name>.*)_handler/.match(method_name)[:event_name]
62
+ if EVENTS.include? event_name.to_sym
63
+ yield event_name.to_sym, method_name.to_sym
64
+ end
65
+ end
66
+ end
67
+
68
+ def trigger(symbol, *args)
69
+ event = send(symbol)
70
+ event.trigger *args
71
+ end
72
+
73
+ self.class.class_eval do
74
+ EVENTS = []
75
+
76
+ def event(symbol)
77
+ getter = symbol
78
+ variable = :"@#{symbol}"
79
+ EVENTS << symbol
80
+
81
+ define_method getter do
82
+ if !instance_variable_defined? variable
83
+ event = Event.new(symbol.to_s)
84
+ instance_variable_set variable, event
85
+ end
86
+
87
+ instance_variable_get variable
88
+ end
89
+
90
+ private getter
91
+ end
92
+ end
93
+ end
94
+
@@ -0,0 +1,28 @@
1
+ require_relative './publisher'
2
+ require 'spec'
3
+
4
+ describe EventPublisher, ": auto subscribing" do
5
+ before(:each) do
6
+ @publisher = Publisher.new
7
+ @publisher.subscribe_all self
8
+ end
9
+
10
+ def first_event_handler(args);end
11
+ def second_event_handler(arg1, arg2);end
12
+ def some_other_handler(args);end
13
+
14
+ it "should subscribe all suitable methods" do
15
+ first_handler_subscribed = @publisher.subscribed? :first_event, method(:first_event_handler)
16
+ second_handler_subscribed = @publisher.subscribed? :second_event, method(:second_event_handler)
17
+ first_handler_subscribed.should be_true
18
+ second_handler_subscribed.should be_true
19
+ end
20
+
21
+ it "should not subscribe unsuitable methods" do
22
+ non_event_handler_subscribed_to_first_event = @publisher.subscribed? :first_event, method(:some_other_handler)
23
+ non_event_handler_subscribed_to_second_event = @publisher.subscribed? :second_event, method(:some_other_handler)
24
+ non_event_handler_subscribed_to_first_event.should be_false
25
+ non_event_handler_subscribed_to_second_event.should be_false
26
+ end
27
+
28
+ end
@@ -0,0 +1,22 @@
1
+ require_relative './publisher'
2
+ require 'spec'
3
+
4
+ describe EventPublisher, ": auto unsubscribing" do
5
+ before(:each) do
6
+ @publisher = Publisher.new
7
+ @publisher.subscribe_all self
8
+ @publisher.unsubscribe_all self
9
+ end
10
+
11
+ def first_event_handler(args);end
12
+ def second_event_handler(arg1, arg2);end
13
+ def some_other_handler(args);end
14
+
15
+ it "should unsubscribe all suitable methods" do
16
+ first_handler_subscribed = @publisher.subscribed? :first_event, method(:first_event_handler)
17
+ second_handler_subscribed = @publisher.subscribed? :second_event, method(:second_event_handler)
18
+ first_handler_subscribed.should be_false
19
+ second_handler_subscribed.should be_false
20
+ end
21
+
22
+ end
@@ -0,0 +1,16 @@
1
+ require_relative '../lib/eventpublisher'
2
+
3
+ # this class is used as an example event publisher class by the tests
4
+ class Publisher
5
+ include EventPublisher
6
+ event :first_event
7
+ event :second_event
8
+
9
+ def trigger_first_event(args)
10
+ trigger :first_event, args
11
+ end
12
+
13
+ def trigger_second_event(arg1, arg2)
14
+ trigger :second_event, arg1, arg2
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ require_relative './publisher'
2
+ require 'spec'
3
+
4
+ describe EventPublisher, ": subscribing" do
5
+ before(:each) do
6
+ @publisher = Publisher.new
7
+ end
8
+
9
+ def first_event_handler(args);end
10
+ def second_event_handler(arg1, arg2);end
11
+
12
+ it "should not know about a method that isn't subscribed" do
13
+ subscribed = @publisher.subscribed? :first_event, method(:first_event_handler)
14
+ subscribed.should be_false
15
+ end
16
+
17
+ it "should know about the subscribed method for the correct event" do
18
+ @publisher.subscribe :first_event, method(:first_event_handler)
19
+ subscribed = @publisher.subscribed? :first_event, method(:first_event_handler)
20
+ subscribed.should be_true
21
+ end
22
+
23
+ it "should not know about a subscribed method for a different event" do
24
+ @publisher.subscribe :first_event, method(:first_event_handler)
25
+ subscribed = @publisher.subscribed? :second_event, method(:first_event_handler)
26
+ subscribed.should be_false
27
+ end
28
+ end
@@ -0,0 +1,79 @@
1
+ require_relative './publisher'
2
+ require 'spec'
3
+
4
+ describe EventPublisher, ": triggering event" do
5
+ before(:each) do
6
+ @publisher = Publisher.new
7
+ end
8
+
9
+ it "should not fail without any subscribers" do
10
+ @publisher.trigger_first_event "testing"
11
+ end
12
+
13
+ it "should pass single event arg correctly to subscribed method with one argument" do
14
+ @args = nil
15
+ def first_event_handler(args);
16
+ @args = args
17
+ end
18
+
19
+ @publisher.subscribe :first_event, method(:first_event_handler)
20
+ @publisher.trigger_first_event "testing!"
21
+ @args.should == "testing!"
22
+ end
23
+
24
+ it "should pass multiple event args correctly to subscribed method with multiple arguments" do
25
+ @args2_1, @args2_2 = nil, nil
26
+ def second_event_handler(arg1, arg2)
27
+ @args2_1, @args2_2 = arg1, arg2
28
+ end
29
+
30
+ @publisher.subscribe :second_event, method(:second_event_handler)
31
+ @publisher.trigger_second_event "second", "event"
32
+ @args2_1.should eql("second")
33
+ @args2_2.should eql("event")
34
+ end
35
+
36
+ it "should pass single event arg correctly to subscribed block with one argument" do
37
+ event_args = nil
38
+ @publisher.subscribe(:first_event) { |args| event_args = args }
39
+ @publisher.trigger_first_event "test"
40
+ event_args.should eql("test")
41
+ end
42
+
43
+ it "should pass multiple event args correctly to subscribed block with two arguments" do
44
+ first_arg, second_arg = nil, nil
45
+ @publisher.subscribe(:second_event) { |arg1,arg2| first_arg, second_arg = arg1, arg2 }
46
+ @publisher.trigger_second_event "first", "second"
47
+ first_arg.should eql("first")
48
+ second_arg.should eql("second")
49
+ end
50
+
51
+ it "should call subscribed method once for each time it was subscribed" do
52
+ @counter1 = 0
53
+ def first_event_handler(args)
54
+ @counter1 += 1
55
+ end
56
+
57
+ 2.times { @publisher.subscribe :first_event, method(:first_event_handler) }
58
+ @publisher.trigger_first_event "test"
59
+ @counter1.should == 2
60
+ end
61
+
62
+ it "should call all subscribed methods" do
63
+ @counter1, @counter2 = 0, 0
64
+ def handler1(args)
65
+ @counter1 += 1
66
+ end
67
+
68
+ def handler2(args)
69
+ @counter2 += 1
70
+ end
71
+
72
+ @publisher.subscribe :first_event, method(:handler1)
73
+ @publisher.subscribe :first_event, method(:handler2)
74
+ @publisher.trigger_first_event "first_event"
75
+ @counter1.should eql(1)
76
+ @counter2.should eql(1)
77
+ end
78
+
79
+ end
@@ -0,0 +1,18 @@
1
+ require_relative './publisher'
2
+ require 'spec'
3
+
4
+ describe EventPublisher, ": unsubscribing" do
5
+ before(:each) do
6
+ @publisher = Publisher.new
7
+ end
8
+
9
+ def first_event_handler(args);end
10
+
11
+ it "should no longer know about an unsubscribed method for the correct event" do
12
+ @publisher.subscribe :first_event, method(:first_event_handler)
13
+ @publisher.unsubscribe :first_event, method(:first_event_handler)
14
+ subscribed = @publisher.subscribed? :first_event, method(:first_event_handler)
15
+ subscribed.should be_false
16
+ end
17
+
18
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eventpublisher
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Davy Brion
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-08-28 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: A module which enables objects to publish multiple events, which other objects can subscribe to See http://github.com/davybrion/EventPublisher for more information.
22
+ email: ralinx@davybrion.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - lib/eventpublisher.rb
31
+ - LICENSE.txt
32
+ - Rakefile
33
+ - README
34
+ - test/auto_subscription_spec.rb
35
+ - test/auto_unsubscription_spec.rb
36
+ - test/publisher.rb
37
+ - test/subscribing_spec.rb
38
+ - test/triggering_events_spec.rb
39
+ - test/unsubscribing_spec.rb
40
+ has_rdoc: true
41
+ homepage: http://github.com/davybrion/EventPublisher
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 1
56
+ - 9
57
+ - 1
58
+ version: 1.9.1
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ requirements: []
68
+
69
+ rubyforge_project:
70
+ rubygems_version: 1.3.7
71
+ signing_key:
72
+ specification_version: 3
73
+ summary: A module which enables objects to publish multiple events, which other objects can subscribe to
74
+ test_files: []
75
+