publisher 1.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.
- data/History.txt +3 -0
- data/Manifest.txt +7 -0
- data/README.txt +75 -0
- data/Rakefile +27 -0
- data/lib/publisher.rb +73 -0
- data/test/publisher_test.rb +358 -0
- data/test/test_helper.rb +20 -0
- metadata +70 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
publisher
|
2
|
+
* http://rubyforge.org/projects/atomicobjectrb/
|
3
|
+
* http://atomicobjectrb.rubyforge.org/constructor
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
publisher is a module for extending a class with event subscription and firing capabilities. This is helpful for implementing objects that participate in the Observer design pattern.
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* Nice syntax for declaring events that can be subscribed for
|
12
|
+
* Convenient event firing syntax
|
13
|
+
* Subscribe / unsubscribe functionality
|
14
|
+
* Several method name aliases give you the flexibility to make your code more readable (eg, *fire*, *notify*, *emit*)
|
15
|
+
|
16
|
+
== SYNOPSIS:
|
17
|
+
|
18
|
+
require 'rubygems'
|
19
|
+
require 'publisher'
|
20
|
+
|
21
|
+
class CustomerListHolder
|
22
|
+
extend Publisher
|
23
|
+
can_fire :customer_added, :list_cleared
|
24
|
+
|
25
|
+
def add_customer(cust)
|
26
|
+
(@list ||= []) << cust
|
27
|
+
fire :customer_added, cust
|
28
|
+
end
|
29
|
+
|
30
|
+
def clear_list
|
31
|
+
@list.clear
|
32
|
+
fire :list_cleared
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
holder = CustomerListHolder.new
|
37
|
+
holder.when :customer_added do |cust|
|
38
|
+
puts "Customer added! #{cust}"
|
39
|
+
end
|
40
|
+
holder.when :list_cleared do
|
41
|
+
puts "All gone."
|
42
|
+
end
|
43
|
+
|
44
|
+
holder.add_customer("Croz")
|
45
|
+
holder.add_customer("Matt")
|
46
|
+
holder.clear_list
|
47
|
+
|
48
|
+
== INSTALL:
|
49
|
+
|
50
|
+
* sudo gem install publisher
|
51
|
+
|
52
|
+
== LICENSE:
|
53
|
+
|
54
|
+
(The MIT License)
|
55
|
+
|
56
|
+
Copyright (c) 2007 Atomic Object
|
57
|
+
|
58
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
59
|
+
a copy of this software and associated documentation files (the
|
60
|
+
'Software'), to deal in the Software without restriction, including
|
61
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
62
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
63
|
+
permit persons to whom the Software is furnished to do so, subject to
|
64
|
+
the following conditions:
|
65
|
+
|
66
|
+
The above copyright notice and this permission notice shall be
|
67
|
+
included in all copies or substantial portions of the Software.
|
68
|
+
|
69
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
70
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
71
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
72
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
73
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
74
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
75
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'hoe'
|
3
|
+
require './lib/publisher.rb'
|
4
|
+
require 'rake'
|
5
|
+
require 'rake/testtask'
|
6
|
+
|
7
|
+
task :default => [ :test ]
|
8
|
+
|
9
|
+
desc "Run the unit tests in test"
|
10
|
+
Rake::TestTask.new("test") { |t|
|
11
|
+
t.libs << "test"
|
12
|
+
t.pattern = 'test/**/*_test.rb'
|
13
|
+
t.verbose = true
|
14
|
+
}
|
15
|
+
|
16
|
+
Hoe.new('publisher', Publisher::VERSION) do |p|
|
17
|
+
p.rubyforge_name = 'atomicobjectrb'
|
18
|
+
p.author = 'Atomic Object'
|
19
|
+
p.email = 'dev@atomicobject.com'
|
20
|
+
p.summary = 'Event subscription and firing mechanism'
|
21
|
+
p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
|
22
|
+
p.url = p.paragraphs_of('README.txt', 1).first.gsub(/\* /,'').split(/\n/)
|
23
|
+
# p.url = p.paragraphs_of('README.txt', 1).first.split(/\n/)[1..-1]
|
24
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
25
|
+
end
|
26
|
+
|
27
|
+
# vim: syntax=Ruby
|
data/lib/publisher.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# See README.txt for synopsis
|
2
|
+
module Publisher
|
3
|
+
VERSION = "1.1.0" #:nodoc:#
|
4
|
+
|
5
|
+
# Use this method (or one of the aliases) to declare which events you support
|
6
|
+
# Once invoked, your class will have the neccessary supporting methods for subscribing and firing.
|
7
|
+
def has_events(*args)
|
8
|
+
include InstanceMethods unless @published_events
|
9
|
+
@published_events ||= []
|
10
|
+
@published_events << args
|
11
|
+
@published_events.flatten!
|
12
|
+
end
|
13
|
+
alias :has_event :has_events
|
14
|
+
alias :can_fire :has_events
|
15
|
+
|
16
|
+
# Use this method to allow subscription and firing of arbitrary events.
|
17
|
+
# This is convenient if, eg, your class has dynamic event names.
|
18
|
+
# Don't use this unless you have to; it's better to declare your events if you
|
19
|
+
# can.
|
20
|
+
def has_any_event
|
21
|
+
include InstanceMethods unless @published_events
|
22
|
+
@published_events = :any_event_is_ok
|
23
|
+
end
|
24
|
+
alias :can_fire_anything :has_any_event
|
25
|
+
|
26
|
+
# Container for the instance methods that will be mixed-in to extenders of Publisher.
|
27
|
+
# These methods get mixed in when you use the 'has_events' call.
|
28
|
+
module InstanceMethods
|
29
|
+
# Sign up a code block to be executed when an event is fired.
|
30
|
+
# It's important to know the signature of the event, as your proc needs
|
31
|
+
# to accept incoming parameters accordingly.
|
32
|
+
def subscribe(event, &block)
|
33
|
+
ensure_valid event
|
34
|
+
@subscriptions ||= {}
|
35
|
+
listeners = @subscriptions[event]
|
36
|
+
listeners ||= []
|
37
|
+
listeners << block
|
38
|
+
@subscriptions[event] = listeners
|
39
|
+
end
|
40
|
+
alias :when :subscribe
|
41
|
+
alias :on :subscribe
|
42
|
+
|
43
|
+
# Unsubscribe for an event. 'listener' is a reference to the object who enacted the
|
44
|
+
# subscription... often, this is 'self'. If this object has subsribed more than once
|
45
|
+
# for the given event (unusual), all of the subscriptions will be removed.
|
46
|
+
def unsubscribe(event, listener)
|
47
|
+
ensure_valid event
|
48
|
+
if @subscriptions && @subscriptions[event]
|
49
|
+
@subscriptions[event].delete_if do |block|
|
50
|
+
eval('self',block.binding).equal?(listener)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
# Fire an event with 0 or more outbound parameters
|
57
|
+
def fire(event, *args) #:nod
|
58
|
+
ensure_valid event
|
59
|
+
listeners = @subscriptions[event] if @subscriptions
|
60
|
+
listeners.each do |l| l.call(*args) end if listeners
|
61
|
+
end
|
62
|
+
alias :emit :fire
|
63
|
+
alias :notify :fire
|
64
|
+
|
65
|
+
# Does nothing if the current class supports the named event.
|
66
|
+
# Raises RuntimeError otherwise.
|
67
|
+
def ensure_valid(event) #:nodoc:#
|
68
|
+
events = self.class.class_eval { @published_events }
|
69
|
+
return if events == :any_event_is_ok
|
70
|
+
raise "Event '#{event}' not available" unless events and events.include?(event)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,358 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/test_helper')
|
2
|
+
require 'publisher'
|
3
|
+
|
4
|
+
class PublisherTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
|
7
|
+
#
|
8
|
+
# TESTS
|
9
|
+
#
|
10
|
+
|
11
|
+
def test_unsubscribe_will_remove_subscription_for_correct_event
|
12
|
+
obj = SeveralWays.new
|
13
|
+
out = []
|
14
|
+
|
15
|
+
obj.on :eviction do
|
16
|
+
out << 'boom'
|
17
|
+
end
|
18
|
+
obj.on :cry do
|
19
|
+
out << 'pow'
|
20
|
+
end
|
21
|
+
obj.on :employee do
|
22
|
+
out << 'kaboom'
|
23
|
+
end
|
24
|
+
|
25
|
+
obj.unsubscribe :cry, self
|
26
|
+
|
27
|
+
obj.do_eviction
|
28
|
+
obj.do_cry
|
29
|
+
obj.do_employee
|
30
|
+
assert_equal ['boom','kaboom'], out
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_unsubsribe_will_raise_if_event_not_valid
|
34
|
+
obj = SeveralWays.new
|
35
|
+
assert_raise RuntimeError do
|
36
|
+
obj.unsubscribe :not_there, self
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_unsubscribe_will_not_care_if_no_previous_subscription_was_made
|
41
|
+
obj = SeveralWays.new
|
42
|
+
obj.unsubscribe :cry, self
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_unsubscribe_can_be_called_multiple_times
|
46
|
+
obj = SeveralWays.new
|
47
|
+
out = []
|
48
|
+
obj.on :cry do
|
49
|
+
out << 'a'
|
50
|
+
end
|
51
|
+
obj.unsubscribe :cry, self
|
52
|
+
obj.unsubscribe :cry, self
|
53
|
+
obj.do_cry
|
54
|
+
assert_equal [], out
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_unsubscribe_only_unsubscribes_the_unsubscriber
|
58
|
+
something = Something.new
|
59
|
+
watcher = SomethingWatcher.new something
|
60
|
+
|
61
|
+
out = []
|
62
|
+
something.on :boom do
|
63
|
+
out << 'boom'
|
64
|
+
end
|
65
|
+
|
66
|
+
something.do_boom
|
67
|
+
assert_equal ['boom'], out
|
68
|
+
assert_equal ['boom'], watcher.observations
|
69
|
+
|
70
|
+
something.unsubscribe :boom, watcher
|
71
|
+
something.do_boom
|
72
|
+
assert_equal ['boom','boom'], out
|
73
|
+
assert_equal ['boom'], watcher.observations
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_unsubscribe_removes_all_subscriptions_for_the_event_being_listened_for
|
77
|
+
something = Something.new
|
78
|
+
out = []
|
79
|
+
something.on :boom do
|
80
|
+
out << 'a'
|
81
|
+
end
|
82
|
+
something.on :boom do
|
83
|
+
out << 'b'
|
84
|
+
end
|
85
|
+
something.on :boom do
|
86
|
+
out << 'c'
|
87
|
+
end
|
88
|
+
something.do_boom
|
89
|
+
assert_equal ['a','b','c'], out
|
90
|
+
something.unsubscribe :boom, self
|
91
|
+
something.do_boom
|
92
|
+
assert_equal ['a','b','c'], out
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_subscribe_and_fire
|
96
|
+
obj = Something.new
|
97
|
+
|
98
|
+
out = []
|
99
|
+
obj.subscribe :boom do out << 'boom' end
|
100
|
+
obj.do_boom
|
101
|
+
assert_equal ['boom'], out
|
102
|
+
|
103
|
+
out = []
|
104
|
+
obj.subscribe :pow do out << 'pow' end
|
105
|
+
obj.do_pow
|
106
|
+
assert_equal ['pow'], out
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_alternate_event_declarators
|
110
|
+
obj = ManyEvents.new
|
111
|
+
[:a, :b, :c, :crunch, :rip, :shred, :rend].each do |event|
|
112
|
+
out = nil
|
113
|
+
obj.subscribe event do out = event end
|
114
|
+
obj.relay(event)
|
115
|
+
assert_equal event, out
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_alternate_subscribe_and_fire_methods
|
120
|
+
obj = SeveralWays.new
|
121
|
+
out = nil
|
122
|
+
obj.subscribe :employee do out = :employee end
|
123
|
+
obj.on :cry do out = :cry end
|
124
|
+
obj.when :eviction do out = :eviction end
|
125
|
+
|
126
|
+
out = nil
|
127
|
+
obj.do_employee
|
128
|
+
assert_equal :employee, out
|
129
|
+
|
130
|
+
out = nil
|
131
|
+
obj.do_cry
|
132
|
+
assert_equal :cry, out
|
133
|
+
|
134
|
+
out = nil
|
135
|
+
obj.do_eviction
|
136
|
+
assert_equal :eviction, out
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_fire_is_not_public
|
140
|
+
obj = Something.new
|
141
|
+
err = assert_raise NoMethodError do
|
142
|
+
obj.fire :boom
|
143
|
+
end
|
144
|
+
assert_match(/protected/i, err.message)
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_subscribe_for_non_event
|
148
|
+
obj = Something.new
|
149
|
+
assert_raise RuntimeError do
|
150
|
+
obj.subscribe :not_there
|
151
|
+
end
|
152
|
+
|
153
|
+
obj = Nobody.new
|
154
|
+
assert_raise NoMethodError do
|
155
|
+
obj.subscribe :huh
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_fire_non_event
|
160
|
+
obj = Broken.new
|
161
|
+
assert_raise RuntimeError do
|
162
|
+
obj.go
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_fire_with_parameters
|
167
|
+
obj = Somebody.new
|
168
|
+
out = nil
|
169
|
+
obj.on :eat_this do |food|
|
170
|
+
out = food
|
171
|
+
end
|
172
|
+
obj.go "burger"
|
173
|
+
assert_equal "burger", out
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_fire_when_nobodys_listening
|
177
|
+
# Make sure this doesn't explode
|
178
|
+
Something.new.do_boom
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_parameter_mismatch_between_event_and_handler
|
182
|
+
obj = Somebody.new
|
183
|
+
out = nil
|
184
|
+
obj.on :eat_this do
|
185
|
+
out = 'huh'
|
186
|
+
end
|
187
|
+
obj.go "ignore me"
|
188
|
+
assert_equal 'huh', out
|
189
|
+
end
|
190
|
+
|
191
|
+
# Cannot inherit events right now
|
192
|
+
# class SomebodyKid < Somebody
|
193
|
+
# end
|
194
|
+
#
|
195
|
+
# def test_inheriting_events
|
196
|
+
# obj = SomebodyKid.new
|
197
|
+
# out = nil
|
198
|
+
# obj.on :eat_this do |food|
|
199
|
+
# out = food
|
200
|
+
# end
|
201
|
+
# obj.go "taco"
|
202
|
+
# assert_equal "taco", out
|
203
|
+
# end
|
204
|
+
|
205
|
+
def test_extending_publisher_doesnt_affect_normal_inheritance
|
206
|
+
obj = Billy.new('wheel')
|
207
|
+
assert_equal 'wheel', obj.chair
|
208
|
+
out = nil
|
209
|
+
obj.subscribe :weapons do out = 'bang' end
|
210
|
+
|
211
|
+
obj.go
|
212
|
+
assert_equal 'bang', out
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_has_any_event
|
216
|
+
sh = SuperHoss.new
|
217
|
+
got = nil
|
218
|
+
sh.when :awesome do |data|
|
219
|
+
got = data
|
220
|
+
end
|
221
|
+
|
222
|
+
sh.go "right on"
|
223
|
+
assert_equal "right on", got
|
224
|
+
end
|
225
|
+
|
226
|
+
def test_can_fire_anything
|
227
|
+
sdh = SuperDuperHoss.new
|
228
|
+
got = nil
|
229
|
+
sdh.when :really_awesome do |data|
|
230
|
+
got = data
|
231
|
+
end
|
232
|
+
|
233
|
+
sdh.go "right on"
|
234
|
+
assert_equal "right on", got
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_multiple_subscriptions_for_same_event
|
238
|
+
obj = Somebody.new
|
239
|
+
out1 = nil
|
240
|
+
out2 = nil
|
241
|
+
obj.on :eat_this do |food|
|
242
|
+
out1 = food
|
243
|
+
end
|
244
|
+
obj.on :eat_this do |food|
|
245
|
+
out2 = food
|
246
|
+
end
|
247
|
+
obj.go "burger"
|
248
|
+
assert_equal "burger", out1, "First subscription no go"
|
249
|
+
assert_equal "burger", out2, "Second subscription no go"
|
250
|
+
end
|
251
|
+
|
252
|
+
#
|
253
|
+
# HELPERS
|
254
|
+
#
|
255
|
+
|
256
|
+
class SomethingWatcher
|
257
|
+
attr_reader :observations
|
258
|
+
def initialize(something)
|
259
|
+
@observations = []
|
260
|
+
something.on :boom do
|
261
|
+
@observations << 'boom'
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
class Something
|
267
|
+
extend Publisher
|
268
|
+
has_events :boom, :pow
|
269
|
+
|
270
|
+
def do_boom
|
271
|
+
fire :boom
|
272
|
+
end
|
273
|
+
|
274
|
+
def do_pow
|
275
|
+
fire :pow
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
class ManyEvents
|
280
|
+
extend Publisher
|
281
|
+
has_events :a, :b, :c
|
282
|
+
has_event :crunch
|
283
|
+
can_fire :rip
|
284
|
+
can_fire :shred, :rend
|
285
|
+
def relay(evt_sym)
|
286
|
+
fire evt_sym
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
class SeveralWays
|
291
|
+
extend Publisher
|
292
|
+
can_fire :cry, :eviction, :employee
|
293
|
+
|
294
|
+
def do_employee
|
295
|
+
fire :employee
|
296
|
+
end
|
297
|
+
def do_eviction
|
298
|
+
notify :eviction
|
299
|
+
end
|
300
|
+
def do_cry
|
301
|
+
emit :cry
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
class Broken
|
306
|
+
extend Publisher
|
307
|
+
can_fire :stuff
|
308
|
+
|
309
|
+
def go
|
310
|
+
fire :oops
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
class Nobody
|
315
|
+
extend Publisher
|
316
|
+
end
|
317
|
+
|
318
|
+
class Somebody
|
319
|
+
extend Publisher
|
320
|
+
can_fire :eat_this
|
321
|
+
def go(food)
|
322
|
+
fire :eat_this, food
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
class Grampa
|
327
|
+
attr_accessor :chair
|
328
|
+
def initialize(ch)
|
329
|
+
@chair = ch
|
330
|
+
end
|
331
|
+
end
|
332
|
+
class Billy < Grampa
|
333
|
+
extend Publisher
|
334
|
+
can_fire :weapons
|
335
|
+
def go
|
336
|
+
fire :weapons
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
class SuperHoss
|
341
|
+
extend Publisher
|
342
|
+
has_any_event
|
343
|
+
|
344
|
+
def go(arg)
|
345
|
+
fire :awesome, arg
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
class SuperDuperHoss
|
350
|
+
extend Publisher
|
351
|
+
can_fire_anything
|
352
|
+
|
353
|
+
def go(arg)
|
354
|
+
fire :really_awesome, arg
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
here = File.expand_path(File.dirname(__FILE__))
|
2
|
+
$: << "#{here}/../lib"
|
3
|
+
$: << "#{here}/../test"
|
4
|
+
|
5
|
+
require 'test/unit'
|
6
|
+
|
7
|
+
class Test::Unit::TestCase
|
8
|
+
# Prevent duplicate test methods
|
9
|
+
self.instance_eval { alias :old_method_added :method_added }
|
10
|
+
def self.method_added(method)
|
11
|
+
method = method.to_s
|
12
|
+
case method
|
13
|
+
when /^test_/
|
14
|
+
@_tracked_tests ||= {}
|
15
|
+
raise "Duplicate test #{method}" if @_tracked_tests[method]
|
16
|
+
@_tracked_tests[method] = true
|
17
|
+
end
|
18
|
+
old_method_added method
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: publisher
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
platform: ""
|
6
|
+
authors:
|
7
|
+
- Atomic Object
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2007-11-21 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.3.0
|
23
|
+
version:
|
24
|
+
description: "== FEATURES/PROBLEMS: * Nice syntax for declaring events that can be subscribed for * Convenient event firing syntax * Subscribe / unsubscribe functionality * Several method name aliases give you the flexibility to make your code more readable (eg, *fire*, *notify*, *emit*) == SYNOPSIS: require 'rubygems' require 'publisher' class CustomerListHolder extend Publisher can_fire :customer_added, :list_cleared"
|
25
|
+
email: dev@atomicobject.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- History.txt
|
32
|
+
- Manifest.txt
|
33
|
+
- README.txt
|
34
|
+
files:
|
35
|
+
- History.txt
|
36
|
+
- Manifest.txt
|
37
|
+
- README.txt
|
38
|
+
- Rakefile
|
39
|
+
- lib/publisher.rb
|
40
|
+
- test/publisher_test.rb
|
41
|
+
- test/test_helper.rb
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: "== DESCRIPTION:"
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options:
|
46
|
+
- --main
|
47
|
+
- README.txt
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project: atomicobjectrb
|
65
|
+
rubygems_version: 0.9.5
|
66
|
+
signing_key:
|
67
|
+
specification_version: 2
|
68
|
+
summary: Event subscription and firing mechanism
|
69
|
+
test_files:
|
70
|
+
- test/test_helper.rb
|