wisper 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +131 -29
- data/lib/wisper.rb +7 -1
- data/lib/wisper/global_listeners.rb +28 -0
- data/lib/wisper/registration/object.rb +14 -3
- data/lib/wisper/registration/object/async_listener.rb +23 -0
- data/lib/wisper/rspec/stub_wisper_publisher.rb +15 -0
- data/lib/wisper/version.rb +1 -1
- data/spec/lib/async_spec.rb +34 -0
- data/spec/lib/global_subscribers_spec.rb +28 -0
- data/spec/lib/integration_spec.rb +3 -0
- data/spec/lib/rspec_extensions_spec.rb +27 -0
- data/spec/lib/wisper_spec.rb +2 -2
- data/wisper.gemspec +1 -0
- metadata +25 -25
data/README.md
CHANGED
@@ -3,10 +3,10 @@
|
|
3
3
|
Simple pub/sub for Ruby objects
|
4
4
|
|
5
5
|
[![Code Climate](https://codeclimate.com/github/krisleech/wisper.png)](https://codeclimate.com/github/krisleech/wisper)
|
6
|
-
[![Build Status](https://travis-ci.org/krisleech/wisper.png)](https://travis-ci.org/krisleech/wisper)
|
6
|
+
[![Build Status](https://travis-ci.org/krisleech/wisper.png?branch=master)](https://travis-ci.org/krisleech/wisper)
|
7
7
|
|
8
8
|
While this is not dependent on Rails in any way it was extracted from a Rails
|
9
|
-
project and
|
9
|
+
project and can used as an alternative to ActiveRecord callbacks and Observers.
|
10
10
|
|
11
11
|
The problem with callbacks and Observers is that they always happen. How many
|
12
12
|
times have you wanted to do `User.create` without firing off a welcome email?
|
@@ -19,7 +19,9 @@ models.
|
|
19
19
|
|
20
20
|
Add this line to your application's Gemfile:
|
21
21
|
|
22
|
-
|
22
|
+
```ruby
|
23
|
+
gem 'wisper', '~>1.0.0'
|
24
|
+
```
|
23
25
|
|
24
26
|
## Usage
|
25
27
|
|
@@ -33,6 +35,7 @@ class MyPublisher
|
|
33
35
|
include Wisper
|
34
36
|
|
35
37
|
def do_something
|
38
|
+
# ...
|
36
39
|
publish(:done_something, self)
|
37
40
|
end
|
38
41
|
end
|
@@ -49,17 +52,17 @@ publish(:done_something, self, 'hello', 'world')
|
|
49
52
|
|
50
53
|
#### Listeners
|
51
54
|
|
52
|
-
|
55
|
+
Any object can be a listener and by default they are only subscribed to events
|
56
|
+
they can respond to.
|
53
57
|
|
54
58
|
```ruby
|
55
|
-
listener = Object.new # any object
|
56
59
|
my_publisher = MyPublisher.new
|
57
|
-
my_publisher.subscribe(
|
60
|
+
my_publisher.subscribe(MyListener.new)
|
58
61
|
```
|
59
62
|
|
60
63
|
#### Blocks
|
61
64
|
|
62
|
-
|
65
|
+
Blocks are subscribed to single events.
|
63
66
|
|
64
67
|
```ruby
|
65
68
|
my_publisher = MyPublisher.new
|
@@ -68,6 +71,23 @@ my_publisher.on(:done_something) do |publisher|
|
|
68
71
|
end
|
69
72
|
```
|
70
73
|
|
74
|
+
### Asynchronous Publishing (Experimental)
|
75
|
+
|
76
|
+
There is support for publishing events asynchronously by passing the `async`
|
77
|
+
option.
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
my_publisher.add_subscriber(MySubscriber.new, :async => true)
|
81
|
+
```
|
82
|
+
|
83
|
+
This leans on Celluloid, which must be included in your Gemfile.
|
84
|
+
|
85
|
+
The listener is transparently turned in to a Celluloid Actor.
|
86
|
+
|
87
|
+
Please refer to [Celluloid](https://github.com/celluloid/celluloid/wiki)
|
88
|
+
for more information, particually the
|
89
|
+
[Gotchas](https://github.com/celluloid/celluloid/wiki/Gotchas).
|
90
|
+
|
71
91
|
### ActiveRecord
|
72
92
|
|
73
93
|
```ruby
|
@@ -103,34 +123,38 @@ class PostsController < ApplicationController
|
|
103
123
|
end
|
104
124
|
```
|
105
125
|
|
106
|
-
### Service/Use
|
107
|
-
|
108
|
-
The downside to publishing directly from ActiveRecord models is that an event
|
109
|
-
can get fired and then rolled back if a transaction fails.
|
126
|
+
### Service/Use Case/Command objects
|
110
127
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
The follow is contrived, but you can imagine it doing more than just updating a
|
115
|
-
record, maybe sending an email or updating other records.
|
128
|
+
A Service object is useful when an operation is complex, interacts with more
|
129
|
+
than one model, accesses an external API or would burden a model with too much
|
130
|
+
responsibility.
|
116
131
|
|
117
132
|
```ruby
|
118
|
-
class
|
133
|
+
class PlayerJoiningTeam
|
119
134
|
include Wisper
|
120
135
|
|
121
|
-
def execute(
|
122
|
-
|
136
|
+
def execute(player, team)
|
137
|
+
membership = Membership.new(player, team)
|
123
138
|
|
124
|
-
if
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
publish(:create_thing_successful, thing)
|
139
|
+
if membership.valid?
|
140
|
+
membership.save!
|
141
|
+
email_player(player, team)
|
142
|
+
assign_first_mission(player, team)
|
143
|
+
publish(:player_joining_team_successful, player, team)
|
130
144
|
else
|
131
|
-
publish(:
|
145
|
+
publish(:player_joining_team_failed, player, team)
|
132
146
|
end
|
133
147
|
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def email_player(player, team)
|
152
|
+
# ...
|
153
|
+
end
|
154
|
+
|
155
|
+
def assign_first_mission(player, team)
|
156
|
+
# ...
|
157
|
+
end
|
134
158
|
end
|
135
159
|
```
|
136
160
|
|
@@ -157,13 +181,40 @@ class StatisticsListener
|
|
157
181
|
# ...
|
158
182
|
end
|
159
183
|
end
|
184
|
+
|
185
|
+
class CacheListener
|
186
|
+
def create_thing_successful(thing)
|
187
|
+
# ...
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
class IndexingListener
|
192
|
+
def create_thing_successful(thing)
|
193
|
+
# ...
|
194
|
+
end
|
195
|
+
end
|
160
196
|
```
|
161
197
|
|
198
|
+
## Global listeners
|
199
|
+
|
200
|
+
If you become tired of adding the same listeners to _every_ publisher you can
|
201
|
+
add global listeners. They receive all published events which they can respond
|
202
|
+
to.
|
203
|
+
|
204
|
+
However it means that when looking at the code it will not be obvious that the
|
205
|
+
global listeners are being executed in additional to the regular listeners.
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
Wisper::GlobalListeners.add_listener(MyListener.new)
|
209
|
+
```
|
210
|
+
|
211
|
+
In a Rails app you might want to add your global listeners in an initalizer.
|
212
|
+
|
162
213
|
## Subscribing to selected events
|
163
214
|
|
164
|
-
By default a listener will get notified of all events it
|
165
|
-
limit which events a listener is notified of by passing an event or array
|
166
|
-
events to `:on`.
|
215
|
+
By default a listener will get notified of all events it can respond to. You
|
216
|
+
can limit which events a listener is notified of by passing an event or array
|
217
|
+
of events to `:on`.
|
167
218
|
|
168
219
|
```ruby
|
169
220
|
post_creater.subscribe(PusherListener.new, :on => :create_post_successful)
|
@@ -207,6 +258,57 @@ post.on(:success) { |post| redirect_to post }
|
|
207
258
|
.on(:failure) { |post| render :action => :edit, :locals => :post => post }
|
208
259
|
```
|
209
260
|
|
261
|
+
## RSpec
|
262
|
+
|
263
|
+
Wisper comes with a method for stubbing event publishers so that you can create isolation tests
|
264
|
+
that only care about reacting to events.
|
265
|
+
|
266
|
+
Given this piece of code:
|
267
|
+
|
268
|
+
```ruby
|
269
|
+
class CodeThatReactsToEvents
|
270
|
+
def do_something
|
271
|
+
publisher = MyPublisher.new
|
272
|
+
publisher.on(:some_event) do |variable|
|
273
|
+
return "Hello with #{variable}!"
|
274
|
+
end
|
275
|
+
publisher.execute
|
276
|
+
end
|
277
|
+
end
|
278
|
+
```
|
279
|
+
|
280
|
+
You can test it like this:
|
281
|
+
|
282
|
+
```ruby
|
283
|
+
require 'wisper/rspec/stub_wisper_publisher'
|
284
|
+
|
285
|
+
describe CodeThatReactsToEvents do
|
286
|
+
context "on some_event" do
|
287
|
+
before do
|
288
|
+
stub_wisper_publisher("MyPublisher", :execute, :some_event, "foo")
|
289
|
+
end
|
290
|
+
|
291
|
+
it "renders" do
|
292
|
+
response = CodeThatReactsToEvents.new.do_something
|
293
|
+
response.should == "Hello with foo!"
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
```
|
298
|
+
|
299
|
+
This becomes important when testing, for example, Rails controllers in
|
300
|
+
isolation from the business logic. This technique is used at the controller
|
301
|
+
layer to isolate testing the controller from testing the encapsulated business
|
302
|
+
logic.
|
303
|
+
|
304
|
+
You can use any number of args to pass to the event:
|
305
|
+
|
306
|
+
```ruby
|
307
|
+
stub_wisper_publisher("MyPublisher", :execute, :some_event, "foo1", "foo2", ...)
|
308
|
+
```
|
309
|
+
|
310
|
+
See `spec/lib/rspec_extensions_spec.rb` for a runnable example.
|
311
|
+
|
210
312
|
## Compatibility
|
211
313
|
|
212
314
|
Tested with 1.9.x on MRI, JRuby and Rubinius.
|
data/lib/wisper.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require "wisper/version"
|
2
2
|
require "wisper/registration/registration"
|
3
3
|
require "wisper/registration/object"
|
4
|
+
require "wisper/registration/object/async_listener"
|
4
5
|
require "wisper/registration/block"
|
6
|
+
require 'wisper/global_listeners'
|
5
7
|
|
6
8
|
module Wisper
|
7
9
|
def listeners
|
@@ -29,8 +31,12 @@ module Wisper
|
|
29
31
|
|
30
32
|
private
|
31
33
|
|
34
|
+
def all_listeners
|
35
|
+
listeners.merge(GlobalListeners.listeners)
|
36
|
+
end
|
37
|
+
|
32
38
|
def broadcast(event, *args)
|
33
|
-
|
39
|
+
all_listeners.each do | listener |
|
34
40
|
listener.broadcast(clean_event(event), *args)
|
35
41
|
end
|
36
42
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module Wisper
|
4
|
+
class GlobalListeners
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@listeners = Set.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_listener(listener, options = {})
|
12
|
+
listeners << ObjectRegistration.new(listener, options)
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def listeners
|
17
|
+
@listeners
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.add_listener(listener, options = {})
|
21
|
+
instance.add_listener(listener, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.listeners
|
25
|
+
instance.listeners
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,16 +1,27 @@
|
|
1
|
+
begin
|
2
|
+
require 'celluloid/autostart'
|
3
|
+
rescue LoadError
|
4
|
+
# no-op
|
5
|
+
end
|
6
|
+
|
1
7
|
module Wisper
|
2
8
|
class ObjectRegistration < Registration
|
3
|
-
attr_reader :with
|
9
|
+
attr_reader :with, :async
|
4
10
|
|
5
11
|
def initialize(listener, options)
|
6
12
|
super(listener, options)
|
7
|
-
@with
|
13
|
+
@with = options[:with]
|
14
|
+
@async = options.fetch(:async, false)
|
8
15
|
end
|
9
16
|
|
10
17
|
def broadcast(event, *args)
|
11
18
|
method_to_call = map_event_to_method(event)
|
12
19
|
if should_broadcast?(event) && listener.respond_to?(method_to_call)
|
13
|
-
|
20
|
+
unless async
|
21
|
+
listener.public_send(method_to_call, *args)
|
22
|
+
else
|
23
|
+
AsyncListener.new(listener, method_to_call).async.public_send(method_to_call, *args)
|
24
|
+
end
|
14
25
|
end
|
15
26
|
end
|
16
27
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class AsyncListener
|
2
|
+
include Celluloid if defined?(Celluloid)
|
3
|
+
|
4
|
+
attr_reader :listener, :event_method
|
5
|
+
|
6
|
+
def initialize(listener, event_method)
|
7
|
+
@listener = listener
|
8
|
+
@event_method = event_method.to_sym
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(method, *args, &block)
|
12
|
+
if listener.respond_to?(method)
|
13
|
+
if method == event_method
|
14
|
+
listener.public_send(method, *args, &block)
|
15
|
+
terminate
|
16
|
+
else
|
17
|
+
listener.public_send(method, *args, &block)
|
18
|
+
end
|
19
|
+
else
|
20
|
+
super(method, *args, &block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
### Wisper Stubbing
|
2
|
+
# This is a proposal for integration as part of wisper core
|
3
|
+
# for testing: https://github.com/krisleech/wisper/issues/1
|
4
|
+
class TestWisperPublisher
|
5
|
+
include Wisper
|
6
|
+
def initialize(*args); end
|
7
|
+
end
|
8
|
+
|
9
|
+
def stub_wisper_publisher(clazz, called_method, event_to_publish, *published_event_args)
|
10
|
+
stub_const(clazz, Class.new(TestWisperPublisher) do
|
11
|
+
define_method(called_method) do
|
12
|
+
publish(event_to_publish, *published_event_args)
|
13
|
+
end
|
14
|
+
end)
|
15
|
+
end
|
data/lib/wisper/version.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class MyService
|
4
|
+
include Wisper
|
5
|
+
|
6
|
+
def execute
|
7
|
+
broadcast('success', self)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# help me...
|
12
|
+
$global = 'no'
|
13
|
+
|
14
|
+
class MyListener
|
15
|
+
def success(command)
|
16
|
+
$global = 'yes'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe Wisper do
|
21
|
+
|
22
|
+
it 'subscribes object to all published events' do
|
23
|
+
listener = MyListener.new
|
24
|
+
|
25
|
+
command = MyService.new
|
26
|
+
|
27
|
+
command.add_listener(listener, :async => true)
|
28
|
+
|
29
|
+
command.execute
|
30
|
+
sleep(1) # seriously...
|
31
|
+
$global.should == 'yes'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Wisper::GlobalListeners do
|
4
|
+
let(:global_listener) { double('listener') }
|
5
|
+
let(:local_listener) { double('listener') }
|
6
|
+
let(:publisher) { Object.new.extend(Wisper) }
|
7
|
+
|
8
|
+
describe '.add_listener' do
|
9
|
+
it 'adds given listener to every publisher' do
|
10
|
+
Wisper::GlobalListeners.add_listener(global_listener)
|
11
|
+
global_listener.should_receive(:it_happened)
|
12
|
+
publisher.send(:broadcast, :it_happened)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'works along side local listeners' do
|
16
|
+
# global listener
|
17
|
+
Wisper::GlobalListeners.add_listener(global_listener)
|
18
|
+
|
19
|
+
# local listener
|
20
|
+
publisher.add_listener(local_listener)
|
21
|
+
|
22
|
+
global_listener.should_receive(:it_happened)
|
23
|
+
local_listener.should_receive(:it_happened)
|
24
|
+
|
25
|
+
publisher.send(:broadcast, :it_happened)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -56,7 +56,9 @@ describe Wisper do
|
|
56
56
|
|
57
57
|
it 'subscribes block can be chained' do
|
58
58
|
insider = double('Insider')
|
59
|
+
|
59
60
|
insider.should_receive(:render).with('success')
|
61
|
+
insider.should_receive(:render).with('failure')
|
60
62
|
|
61
63
|
command = MyCommand.new
|
62
64
|
|
@@ -64,5 +66,6 @@ describe Wisper do
|
|
64
66
|
.on(:failure) { |message| insider.render('failure') }
|
65
67
|
|
66
68
|
command.execute(true)
|
69
|
+
command.execute(false)
|
67
70
|
end
|
68
71
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'wisper/rspec/stub_wisper_publisher'
|
3
|
+
|
4
|
+
describe Wisper do
|
5
|
+
describe "given a piece of code invoking a publisher" do
|
6
|
+
class CodeThatReactsToEvents
|
7
|
+
def do_something
|
8
|
+
publisher = MyPublisher.new
|
9
|
+
publisher.on(:some_event) do |variable1, variable2|
|
10
|
+
return "Hello with #{variable1} #{variable2}!"
|
11
|
+
end
|
12
|
+
publisher.execute
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "when stubbing the publisher to emit an event" do
|
17
|
+
before do
|
18
|
+
stub_wisper_publisher("MyPublisher", :execute, :some_event, "foo1", "foo2")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "emits the event" do
|
22
|
+
response = CodeThatReactsToEvents.new.do_something
|
23
|
+
response.should == "Hello with foo1 foo2!"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/spec/lib/wisper_spec.rb
CHANGED
@@ -62,8 +62,9 @@ describe Wisper do
|
|
62
62
|
end
|
63
63
|
|
64
64
|
describe '.add_block_listener' do
|
65
|
+
let(:insider) { double('insider') }
|
66
|
+
|
65
67
|
it 'subscribes given block to all events' do
|
66
|
-
insider = double('insider')
|
67
68
|
insider.should_receive(:it_happened).twice
|
68
69
|
|
69
70
|
publisher.add_block_listener do
|
@@ -76,7 +77,6 @@ describe Wisper do
|
|
76
77
|
|
77
78
|
describe ':on argument' do
|
78
79
|
it '.add_block_listener subscribes block to an event' do
|
79
|
-
insider = double('insider')
|
80
80
|
insider.should_not_receive(:it_happened).once
|
81
81
|
|
82
82
|
publisher.add_block_listener(:on => 'something_happened') do
|
data/wisper.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wisper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-02 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirement: &2152451840 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,15 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ! '>='
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '0'
|
24
|
+
version_requirements: *2152451840
|
30
25
|
- !ruby/object:Gem::Dependency
|
31
26
|
name: rspec
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
27
|
+
requirement: &2152451300 !ruby/object:Gem::Requirement
|
33
28
|
none: false
|
34
29
|
requirements:
|
35
30
|
- - ! '>='
|
@@ -37,15 +32,10 @@ dependencies:
|
|
37
32
|
version: '0'
|
38
33
|
type: :development
|
39
34
|
prerelease: false
|
40
|
-
version_requirements:
|
41
|
-
none: false
|
42
|
-
requirements:
|
43
|
-
- - ! '>='
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: '0'
|
35
|
+
version_requirements: *2152451300
|
46
36
|
- !ruby/object:Gem::Dependency
|
47
37
|
name: simplecov
|
48
|
-
requirement: !ruby/object:Gem::Requirement
|
38
|
+
requirement: &2152450760 !ruby/object:Gem::Requirement
|
49
39
|
none: false
|
50
40
|
requirements:
|
51
41
|
- - ! '>='
|
@@ -53,12 +43,18 @@ dependencies:
|
|
53
43
|
version: '0'
|
54
44
|
type: :development
|
55
45
|
prerelease: false
|
56
|
-
version_requirements:
|
46
|
+
version_requirements: *2152450760
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: celluloid
|
49
|
+
requirement: &2152450220 !ruby/object:Gem::Requirement
|
57
50
|
none: false
|
58
51
|
requirements:
|
59
52
|
- - ! '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2152450220
|
62
58
|
description: pub/sub for Ruby objects
|
63
59
|
email:
|
64
60
|
- kris.leech@gmail.com
|
@@ -74,11 +70,17 @@ files:
|
|
74
70
|
- README.md
|
75
71
|
- Rakefile
|
76
72
|
- lib/wisper.rb
|
73
|
+
- lib/wisper/global_listeners.rb
|
77
74
|
- lib/wisper/registration/block.rb
|
78
75
|
- lib/wisper/registration/object.rb
|
76
|
+
- lib/wisper/registration/object/async_listener.rb
|
79
77
|
- lib/wisper/registration/registration.rb
|
78
|
+
- lib/wisper/rspec/stub_wisper_publisher.rb
|
80
79
|
- lib/wisper/version.rb
|
80
|
+
- spec/lib/async_spec.rb
|
81
|
+
- spec/lib/global_subscribers_spec.rb
|
81
82
|
- spec/lib/integration_spec.rb
|
83
|
+
- spec/lib/rspec_extensions_spec.rb
|
82
84
|
- spec/lib/simple_example_spec.rb
|
83
85
|
- spec/lib/wisper_spec.rb
|
84
86
|
- spec/spec_helper.rb
|
@@ -95,26 +97,24 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
95
97
|
- - ! '>='
|
96
98
|
- !ruby/object:Gem::Version
|
97
99
|
version: '0'
|
98
|
-
segments:
|
99
|
-
- 0
|
100
|
-
hash: -3667309302433800657
|
101
100
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
101
|
none: false
|
103
102
|
requirements:
|
104
103
|
- - ! '>='
|
105
104
|
- !ruby/object:Gem::Version
|
106
105
|
version: '0'
|
107
|
-
segments:
|
108
|
-
- 0
|
109
|
-
hash: -3667309302433800657
|
110
106
|
requirements: []
|
111
107
|
rubyforge_project:
|
112
|
-
rubygems_version: 1.8.
|
108
|
+
rubygems_version: 1.8.10
|
113
109
|
signing_key:
|
114
110
|
specification_version: 3
|
115
111
|
summary: pub/sub for Ruby objects
|
116
112
|
test_files:
|
113
|
+
- spec/lib/async_spec.rb
|
114
|
+
- spec/lib/global_subscribers_spec.rb
|
117
115
|
- spec/lib/integration_spec.rb
|
116
|
+
- spec/lib/rspec_extensions_spec.rb
|
118
117
|
- spec/lib/simple_example_spec.rb
|
119
118
|
- spec/lib/wisper_spec.rb
|
120
119
|
- spec/spec_helper.rb
|
120
|
+
has_rdoc:
|