pubsub 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +1 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/VERSION +1 -1
- data/autotest/discover.rb +1 -0
- data/lib/pubsub.rb +1 -60
- data/lib/pubsub/logger.rb +12 -0
- data/lib/pubsub/pubsub.rb +79 -26
- data/spec/pubsup_spec.rb +64 -0
- data/spec/spec_helper.rb +42 -0
- metadata +54 -17
- data/test/helper.rb +0 -18
- data/test/test_pubsub.rb +0 -7
data/.autotest
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'autotest/growl'
|
data/.rspec
ADDED
data/Gemfile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.1
|
@@ -0,0 +1 @@
|
|
1
|
+
Autotest.add_discovery { "rspec2" }
|
data/lib/pubsub.rb
CHANGED
@@ -1,61 +1,2 @@
|
|
1
1
|
require "ruby_events"
|
2
|
-
require File.join(File.dirname(__FILE__), "pubsub/pubsub.rb")
|
3
|
-
|
4
|
-
module DigitalPro
|
5
|
-
module Events
|
6
|
-
module PubSub
|
7
|
-
def subscribe(channel, procs = nil, &block)
|
8
|
-
logger.info "Subscribe #{self.class.name} to #{channel}"
|
9
|
-
|
10
|
-
PubSub.events.listen channel, procs, &block
|
11
|
-
|
12
|
-
procs_collected = []
|
13
|
-
if procs.respond_to?(:each) && procs.respond_to?(:to_a)
|
14
|
-
procs_collected += procs.to_a
|
15
|
-
elsif procs
|
16
|
-
procs_collected << procs
|
17
|
-
end
|
18
|
-
procs_collected << block if block
|
19
|
-
|
20
|
-
channel_handlers[channel] ||= []
|
21
|
-
channel_handlers[channel] += procs_collected
|
22
|
-
end
|
23
|
-
|
24
|
-
def unsubscribe(channel=nil, proc = nil)
|
25
|
-
# unsubscribe from all object channels
|
26
|
-
unless channel
|
27
|
-
channel_handlers.each_key{ |channel_name| unsubscribe channel_name}
|
28
|
-
return
|
29
|
-
end
|
30
|
-
|
31
|
-
if proc
|
32
|
-
logger.info "Unsubscribe #{self.class.name} to #{channel}"
|
33
|
-
PubSub.events.remove channel, proc
|
34
|
-
channel_handlers[channel].delete_if {|stored_event| stored_event == proc} if channel_handlers.include? channel
|
35
|
-
else
|
36
|
-
channel_handlers[channel].each { |proc_handler| unsubscribe channel, proc_handler} if channel_handlers.include? channel
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def publish(channel, *args)
|
41
|
-
logger.info "Publish #{self.class.name} to #{channel} with #{args.to_s}"
|
42
|
-
|
43
|
-
channel.sub_before "/" do |sub_channel|
|
44
|
-
PubSub.events.fire sub_channel, *args
|
45
|
-
end
|
46
|
-
PubSub.events.fire "*", *args
|
47
|
-
end
|
48
|
-
|
49
|
-
protected
|
50
|
-
|
51
|
-
def channel_handlers
|
52
|
-
@channel_handlers ||= {}
|
53
|
-
end
|
54
|
-
|
55
|
-
def PubSub.events
|
56
|
-
@@events ||= RubyEvents::Events.new(self)
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
2
|
+
require File.join(File.dirname(__FILE__), "pubsub/pubsub.rb")
|
data/lib/pubsub/pubsub.rb
CHANGED
@@ -1,55 +1,108 @@
|
|
1
1
|
require "ruby_events"
|
2
|
+
require File.join(File.dirname(__FILE__), "logger.rb")
|
2
3
|
require File.join(File.dirname(__FILE__), "string.rb")
|
3
4
|
|
4
5
|
module PubSub
|
5
6
|
def subscribe(channel, procs = nil, &block)
|
6
|
-
|
7
|
+
mutex.synchronize do
|
8
|
+
logger.info "Subscribe #{self.class.name} to #{channel}"
|
7
9
|
|
8
|
-
|
10
|
+
PubSub.events.listen channel, procs, &block
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
procs_collected = []
|
13
|
+
if procs.respond_to?(:each) && procs.respond_to?(:to_a)
|
14
|
+
procs_collected += procs.to_a
|
15
|
+
elsif procs
|
16
|
+
procs_collected << procs
|
17
|
+
end
|
18
|
+
procs_collected << block if block
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
+
channel_handlers[channel] ||= []
|
21
|
+
channel_handlers[channel] += procs_collected
|
22
|
+
end
|
20
23
|
end
|
21
24
|
|
22
25
|
def unsubscribe(channel=nil, proc = nil)
|
23
|
-
|
24
|
-
|
25
|
-
channel_handlers.each_key{ |channel_name| unsubscribe channel_name}
|
26
|
-
return
|
26
|
+
mutex.synchronize do
|
27
|
+
unsubscribe_safe(channel, proc )
|
27
28
|
end
|
29
|
+
end
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
channel_handlers[channel].each { |proc_handler| unsubscribe channel, proc_handler} if channel_handlers.include? channel
|
31
|
+
def publish(channel, *args)
|
32
|
+
mutex.synchronize do
|
33
|
+
logger.info "Add to publish queue #{self.class.name} to #{channel} with #{args.to_s}"
|
34
|
+
PubSub.queue.push({:sender => self, :channel => channel, :params => args})
|
35
|
+
PubSub.thread.wakeup if PubSub.thread.status == "sleep"
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
38
|
-
def
|
39
|
-
|
39
|
+
def PubSub.run
|
40
|
+
@@stopped = false
|
41
|
+
PubSub.thread
|
42
|
+
while true
|
43
|
+
if @@stopped
|
44
|
+
PubSub.queue.clear
|
45
|
+
break
|
46
|
+
end
|
47
|
+
|
48
|
+
sleep if PubSub.queue.empty?
|
49
|
+
|
50
|
+
unless PubSub.queue.empty?
|
51
|
+
publish_info = PubSub.queue.shift
|
52
|
+
sender = publish_info[:sender]
|
53
|
+
channel = publish_info[:channel]
|
54
|
+
params = publish_info[:params]
|
55
|
+
logger.info "Publish ObjectID:#{sender.__id__} of class #{sender.class.name} to #{channel} with #{params.to_s}"
|
40
56
|
|
41
|
-
|
42
|
-
|
57
|
+
channel.sub_before "/" do |sub_channel|
|
58
|
+
PubSub.events.fire sub_channel, *params
|
59
|
+
end
|
60
|
+
PubSub.events.fire "*", *params
|
61
|
+
end
|
43
62
|
end
|
44
|
-
|
63
|
+
end
|
64
|
+
|
65
|
+
def PubSub.stop
|
66
|
+
@@stopped = true
|
45
67
|
end
|
46
68
|
|
47
69
|
protected
|
48
70
|
|
71
|
+
def mutex
|
72
|
+
@mutex ||= Mutex.new
|
73
|
+
end
|
74
|
+
|
49
75
|
def channel_handlers
|
50
76
|
@channel_handlers ||= {}
|
51
77
|
end
|
52
78
|
|
79
|
+
def unsubscribe_safe(channel=nil, proc = nil)
|
80
|
+
# unsubscribe from all object channels
|
81
|
+
unless channel
|
82
|
+
channel_handlers.each_key{ |channel_name| unsubscribe_safe channel_name}
|
83
|
+
return
|
84
|
+
end
|
85
|
+
|
86
|
+
unless proc
|
87
|
+
logger.info "Unsubscribe #{self.class.name} from #{channel}"
|
88
|
+
channel_handlers[channel].each { |proc_handler| PubSub.events.remove channel, proc_handler }if channel_handlers.include? channel
|
89
|
+
channel_handlers[channel].clear
|
90
|
+
return
|
91
|
+
end
|
92
|
+
|
93
|
+
logger.info "Unsubscribe #{self.class.name} from #{channel} listener #{proc}"
|
94
|
+
PubSub.events.remove channel, proc
|
95
|
+
channel_handlers[channel].delete_if {|stored_event| stored_event == proc} if channel_handlers.include? channel
|
96
|
+
end
|
97
|
+
|
98
|
+
def PubSub.thread
|
99
|
+
@@thread ||= Thread.current
|
100
|
+
end
|
101
|
+
|
102
|
+
def PubSub.queue
|
103
|
+
@@queue ||= []
|
104
|
+
end
|
105
|
+
|
53
106
|
def PubSub.events
|
54
107
|
@@events ||= RubyEvents::Events.new(self)
|
55
108
|
end
|
data/spec/pubsup_spec.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper.rb")
|
2
|
+
|
3
|
+
describe "Object with PubSub pattern" do
|
4
|
+
before(:each) do
|
5
|
+
PubSub.events.events_collection.clear
|
6
|
+
@publisher = Publisher.new
|
7
|
+
@subscriber = Subscriber.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should subscribe on channel" do
|
11
|
+
@subscriber.subscribe "channel", @subscriber.method(:listener)
|
12
|
+
PubSub.events.events_collection.size.should == 1
|
13
|
+
PubSub.events.events_collection.should have_key "channel"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should unsubscribe specific listeners from channel" do
|
17
|
+
@subscriber.subscribe "channel", @subscriber.method(:listener)
|
18
|
+
@subscriber.unsubscribe "channel", @subscriber.method(:listener)
|
19
|
+
PubSub.events.events_collection["channel"].should be_empty
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should unsubscribe all listeners from channel" do
|
23
|
+
@subscriber.subscribe "channel", @subscriber.method(:listener)
|
24
|
+
@subscriber.subscribe "channel", @subscriber.method(:listener1)
|
25
|
+
@subscriber.unsubscribe "channel"
|
26
|
+
PubSub.events.events_collection["channel"].should be_empty
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should unsubscribe from all channels" do
|
30
|
+
@subscriber.subscribe "channel", @subscriber.method(:listener)
|
31
|
+
@subscriber.subscribe "channel1", @subscriber.method(:listener1)
|
32
|
+
@subscriber.unsubscribe
|
33
|
+
PubSub.events.events_collection["channel"].should be_empty
|
34
|
+
PubSub.events.events_collection["channel1"].should be_empty
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should publish message to channel" do
|
38
|
+
@subscriber.should_receive(:listener).with("Hello world")
|
39
|
+
@subscriber.subscribe "channel", @subscriber.method(:listener)
|
40
|
+
@subscriber.subscribe "channel", @subscriber.method(:listener_with_stop)
|
41
|
+
@publisher.publish("channel", "Hello world")
|
42
|
+
PubSub.run
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should publish message to channel and subchannel" do
|
46
|
+
@subscriber.should_receive(:listener).with("Hello world")
|
47
|
+
@subscriber.subscribe "test/channel", @subscriber.method(:listener)
|
48
|
+
|
49
|
+
@subscriber.should_receive(:listener1).with("Hello world")
|
50
|
+
@subscriber.subscribe "test", @subscriber.method(:listener1)
|
51
|
+
|
52
|
+
@subscriber.subscribe "test/channel", @subscriber.method(:listener_with_stop)
|
53
|
+
@publisher.publish("test/channel", "Hello world")
|
54
|
+
PubSub.run
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should publish message to global channel" do
|
58
|
+
@subscriber.should_receive(:listener).with("Hello world")
|
59
|
+
@subscriber.subscribe "*", @subscriber.method(:listener)
|
60
|
+
@subscriber.subscribe "*", @subscriber.method(:listener_with_stop)
|
61
|
+
@publisher.publish("channel", "Hello world")
|
62
|
+
PubSub.run
|
63
|
+
end
|
64
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
|
11
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
12
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
13
|
+
require 'pubsub'
|
14
|
+
|
15
|
+
logger.level = Logger::WARN
|
16
|
+
|
17
|
+
module PubSub
|
18
|
+
PubSub.events.class.class_eval do
|
19
|
+
def events_collection
|
20
|
+
@events
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Publisher
|
26
|
+
include PubSub
|
27
|
+
end
|
28
|
+
|
29
|
+
class Subscriber
|
30
|
+
include PubSub
|
31
|
+
|
32
|
+
def listener(message = nil)
|
33
|
+
logger.info "listener_with_stop"
|
34
|
+
end
|
35
|
+
|
36
|
+
def listener1(message = nil)
|
37
|
+
end
|
38
|
+
|
39
|
+
def listener_with_stop(message = nil)
|
40
|
+
PubSub.stop
|
41
|
+
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pubsub
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-07-
|
12
|
+
date: 2011-07-17 00:00:00.000000000 +04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: ruby_events
|
17
|
-
requirement: &
|
17
|
+
requirement: &18948040 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *18948040
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: shoulda
|
28
|
-
requirement: &
|
28
|
+
requirement: &18946840 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *18946840
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: bundler
|
39
|
-
requirement: &
|
39
|
+
requirement: &18946080 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ~>
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: 1.0.0
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *18946080
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: jeweler
|
50
|
-
requirement: &
|
50
|
+
requirement: &18945200 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ~>
|
@@ -55,10 +55,10 @@ dependencies:
|
|
55
55
|
version: 1.6.4
|
56
56
|
type: :development
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *18945200
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: rcov
|
61
|
-
requirement: &
|
61
|
+
requirement: &18944220 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
63
63
|
requirements:
|
64
64
|
- - ! '>='
|
@@ -66,10 +66,43 @@ dependencies:
|
|
66
66
|
version: '0'
|
67
67
|
type: :development
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *18944220
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rspec
|
72
|
+
requirement: &18943460 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: *18943460
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: ZenTest
|
83
|
+
requirement: &18928680 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
type: :development
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: *18928680
|
92
|
+
- !ruby/object:Gem::Dependency
|
93
|
+
name: autotest-growl
|
94
|
+
requirement: &18927540 !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
type: :development
|
101
|
+
prerelease: false
|
102
|
+
version_requirements: *18927540
|
70
103
|
- !ruby/object:Gem::Dependency
|
71
104
|
name: ruby_events
|
72
|
-
requirement: &
|
105
|
+
requirement: &18921320 !ruby/object:Gem::Requirement
|
73
106
|
none: false
|
74
107
|
requirements:
|
75
108
|
- - ! '>='
|
@@ -77,7 +110,7 @@ dependencies:
|
|
77
110
|
version: '0'
|
78
111
|
type: :runtime
|
79
112
|
prerelease: false
|
80
|
-
version_requirements: *
|
113
|
+
version_requirements: *18921320
|
81
114
|
description: PubSub pattern
|
82
115
|
email: maxkazargm@gmail.com
|
83
116
|
executables: []
|
@@ -86,17 +119,21 @@ extra_rdoc_files:
|
|
86
119
|
- LICENSE.txt
|
87
120
|
- README.rdoc
|
88
121
|
files:
|
122
|
+
- .autotest
|
89
123
|
- .document
|
124
|
+
- .rspec
|
90
125
|
- Gemfile
|
91
126
|
- LICENSE.txt
|
92
127
|
- README.rdoc
|
93
128
|
- Rakefile
|
94
129
|
- VERSION
|
130
|
+
- autotest/discover.rb
|
95
131
|
- lib/pubsub.rb
|
132
|
+
- lib/pubsub/logger.rb
|
96
133
|
- lib/pubsub/pubsub.rb
|
97
134
|
- lib/pubsub/string.rb
|
98
|
-
-
|
99
|
-
-
|
135
|
+
- spec/pubsup_spec.rb
|
136
|
+
- spec/spec_helper.rb
|
100
137
|
has_rdoc: true
|
101
138
|
homepage: http://github.com/maxkazar/pubsub
|
102
139
|
licenses:
|
@@ -113,7 +150,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
113
150
|
version: '0'
|
114
151
|
segments:
|
115
152
|
- 0
|
116
|
-
hash:
|
153
|
+
hash: -2541202216032154175
|
117
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
155
|
none: false
|
119
156
|
requirements:
|
data/test/helper.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'bundler'
|
3
|
-
begin
|
4
|
-
Bundler.setup(:default, :development)
|
5
|
-
rescue Bundler::BundlerError => e
|
6
|
-
$stderr.puts e.message
|
7
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
-
exit e.status_code
|
9
|
-
end
|
10
|
-
require 'test/unit'
|
11
|
-
require 'shoulda'
|
12
|
-
|
13
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
-
require 'pubsub'
|
16
|
-
|
17
|
-
class Test::Unit::TestCase
|
18
|
-
end
|