publisher 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|