notifyhub 0.0.1

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,112 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+ <title>
7
+ Top Level Namespace
8
+
9
+ &mdash; Documentation by YARD 0.8.6.1
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ hasFrames = window.top.frames.main ? true : false;
19
+ relpath = '';
20
+ framesUrl = "frames.html#!" + escape(window.location.href);
21
+ </script>
22
+
23
+
24
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
25
+
26
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
27
+
28
+
29
+ </head>
30
+ <body>
31
+ <div id="header">
32
+ <div id="menu">
33
+
34
+ <a href="_index.html">Index</a> &raquo;
35
+
36
+
37
+ <span class="title">Top Level Namespace</span>
38
+
39
+
40
+ <div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
41
+ </div>
42
+
43
+ <div id="search">
44
+
45
+ <a class="full_list_link" id="class_list_link"
46
+ href="class_list.html">
47
+ Class List
48
+ </a>
49
+
50
+ <a class="full_list_link" id="method_list_link"
51
+ href="method_list.html">
52
+ Method List
53
+ </a>
54
+
55
+ <a class="full_list_link" id="file_list_link"
56
+ href="file_list.html">
57
+ File List
58
+ </a>
59
+
60
+ </div>
61
+ <div class="clear"></div>
62
+ </div>
63
+
64
+ <iframe id="search_frame"></iframe>
65
+
66
+ <div id="content"><h1>Top Level Namespace
67
+
68
+
69
+
70
+ </h1>
71
+
72
+ <dl class="box">
73
+
74
+
75
+
76
+
77
+
78
+
79
+
80
+
81
+ </dl>
82
+ <div class="clear"></div>
83
+
84
+ <h2>Defined Under Namespace</h2>
85
+ <p class="children">
86
+
87
+
88
+
89
+
90
+ <strong class="classes">Classes:</strong> <span class='object_link'><a href="Notify.html" title="Notify (class)">Notify</a></span>, <span class='object_link'><a href="NotifyHub.html" title="NotifyHub (class)">NotifyHub</a></span>, <span class='object_link'><a href="NotifySet.html" title="NotifySet (class)">NotifySet</a></span>
91
+
92
+
93
+ </p>
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+ </div>
104
+
105
+ <div id="footer">
106
+ Generated on Sun Jan 19 21:55:11 2014 by
107
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
108
+ 0.8.6.1 (ruby-1.9.3).
109
+ </div>
110
+
111
+ </body>
112
+ </html>
data/lib/notifyhub.rb ADDED
@@ -0,0 +1,339 @@
1
+ # NotifyHub is a callback facility. NotifyHub is used by the informer
2
+ # to notify clients about arbitrary events in the informer. NotifyHub
3
+ # contains notification sets (NotifySet).
4
+ #
5
+ # NotifySet is identified by set ID and it can include one or many
6
+ # notifications (Notify). Client defines the action performed at
7
+ # notification (callback). Informer activates the notification when
8
+ # notification events occur.
9
+ #
10
+ # Notifications can be enabled/disabled on different levels
11
+ # (NotifyHub, NotifySet, and Notify).
12
+ #
13
+ # Example:
14
+ #
15
+ # require 'notifyhub'
16
+ #
17
+ # # Create class that includes interesting events.
18
+ # class Storage
19
+ #
20
+ # # Handle to NotifyHub.
21
+ # attr_accessor :hub
22
+ #
23
+ # def initialize
24
+ # # Create NotifyHub.
25
+ # @hub = NotifyHub.declare( :store, :load, :na )
26
+ # end
27
+ #
28
+ # # Store data and notify clients.
29
+ # def store( data )
30
+ # @data = data
31
+ # @hub[ :store ].notify( @data )
32
+ # end
33
+ #
34
+ # # Load data and notify clients.
35
+ # def load
36
+ # @hub[ :load ].notify( @data )
37
+ # @data
38
+ # end
39
+ # end
40
+ #
41
+ #
42
+ # storage = Storage.new
43
+ #
44
+ # # Setup notify action for store.
45
+ # storage.hub[ :store ].action do |data|
46
+ # puts "store: #{data}"
47
+ # end
48
+ #
49
+ # # Setup notify action for load.
50
+ # storage.hub[ :load ].action do |data|
51
+ # puts "load: #{data}"
52
+ # end
53
+ #
54
+ #
55
+ # # Use storage and get notifications.
56
+ # storage.store( "my data" )
57
+ # data = storage.load
58
+
59
+ class NotifyHub
60
+
61
+
62
+ # Declare sets automatically at action registration.
63
+ attr_accessor :autodeclare
64
+
65
+
66
+ # Non-existing Notify error.
67
+ class NotFound < RuntimeError; end
68
+
69
+ # Redefining Notify error.
70
+ class Redefining < RuntimeError; end
71
+
72
+
73
+ # Create NotifyHub and declare sets.
74
+ #
75
+ # @param id [Array<Symbol>] Notify set(s).
76
+ def NotifyHub.declare( *id )
77
+ NotifyHub.new( *id )
78
+ end
79
+
80
+
81
+ # Create NotifyHub and with autodeclare for sets. Declare sets
82
+ # automatically at action registration.
83
+ #
84
+ # @param id [Array<Symbol>] Notify set(s).
85
+ def NotifyHub.auto( *id )
86
+ n = NotifyHub.new( *id )
87
+ n.autodeclare = true
88
+ n
89
+ end
90
+
91
+
92
+ # Create NotifyHub and run block with it.
93
+ #
94
+ # @yield Block to run with NotifyHub.
95
+ def NotifyHub.create( &blk )
96
+ cg = NotifyHub.new
97
+ if block_given?
98
+ cg.instance_eval( &blk )
99
+ end
100
+ cg
101
+ end
102
+
103
+
104
+ # Instantiation.
105
+ #
106
+ # @param id [Array<Symbol>] Notify set id(s).
107
+ def initialize( *id )
108
+ @autodeclare = false
109
+ @set = {}
110
+ declare( *id )
111
+ end
112
+
113
+
114
+ # Declare Notify by set. Multiple notifiers can exist per set.
115
+ #
116
+ # @param id [Array<Symbol>] Notify set id(s).
117
+ def declare( *id )
118
+ id.each do |i|
119
+ if @set[ i ]
120
+ raise Redefining, "Notify set already declared: #{i.to_s}"
121
+ else
122
+ @set[ i ] = NotifySet.new( i )
123
+ end
124
+ end
125
+ end
126
+
127
+
128
+ # Register action to NotifySet. Multiple notifies can
129
+ # exist per set.
130
+ #
131
+ # @param id [Symbol] Notify set id (class).
132
+ # @param action [Block] Notify action.
133
+ def action( id, &action )
134
+ useSet( id ) do |set|
135
+ set.action( &action )
136
+ end
137
+ end
138
+
139
+ alias register action
140
+ alias with action
141
+
142
+
143
+ # Remove all or one Notify.
144
+ #
145
+ # @param id [Symbol] Notify set id (class).
146
+ # @param notify [Notify] Notify to remove (all if not given).
147
+ def remove( id, notify = nil )
148
+ withSet( id ) do |set|
149
+ set.remove( notify )
150
+ end
151
+ end
152
+
153
+
154
+ # Enable/disable Notify set or all if not set.
155
+ #
156
+ # @param id [Symbol] Notify set id (all if nil given).
157
+ # @param value [Boolean] Enable with true and disable with false.
158
+ def enable( id, value )
159
+ if id
160
+ withSet( id ) do |set|
161
+ set.enable = value
162
+ end
163
+ else
164
+ @set.each_value do |set|
165
+ set.enable = value
166
+ end
167
+ end
168
+ end
169
+
170
+
171
+ # Run all notifiers in Notify set.
172
+ #
173
+ # @param id [Symbol] Notify set id (class).
174
+ # @param args [Array<Object>] Arguments for notifiers.
175
+ def notify( id, *args )
176
+ withSet( id ) do |set|
177
+ set.notify( *args )
178
+ end
179
+ end
180
+
181
+
182
+ # Get NotifySet by ID.
183
+ #
184
+ # @param id [Symbol] Set ID.
185
+ # @return [NotifySet] Set.
186
+ def []( id )
187
+ useSet( id ) do |set|
188
+ set
189
+ end
190
+ end
191
+
192
+
193
+
194
+ private
195
+
196
+ # Check that NotifySet exists (or create it).
197
+ def withSet( id, &blk )
198
+ if @set[id]
199
+ yield @set[ id ]
200
+ else
201
+ raise NotFound, "Uknown notify set: #{id.to_s}"
202
+ end
203
+ end
204
+
205
+
206
+ # Check that NotifySet exists (or create it).
207
+ def useSet( id, &blk )
208
+
209
+ if @set[id] || @autodeclare
210
+
211
+ unless @set[id]
212
+ declare( id )
213
+ end
214
+
215
+ yield @set[ id ]
216
+
217
+ else
218
+
219
+ raise NotFound, "Uknown notify set: #{id.to_s}"
220
+
221
+ end
222
+ end
223
+
224
+ end
225
+
226
+
227
+
228
+ # Notify object that includes disable/enable features.
229
+ class NotifySet
230
+
231
+ # Enable/disable NotifySet.
232
+ attr_accessor :enable
233
+
234
+
235
+ # Instantiation.
236
+ #
237
+ # @param id [Symbol] Id of the set.
238
+ def initialize( id = nil )
239
+ @id = id
240
+ @enable = true
241
+ @list = []
242
+ end
243
+
244
+
245
+ # Enable/disable Notify set.
246
+ #
247
+ # @param value [Boolean] Enable with true and disable with false.
248
+ def enable( value )
249
+ @enable = value
250
+ end
251
+
252
+
253
+ # Register Notify.
254
+ #
255
+ # @param action [Block] Notify action.
256
+ def action( &action )
257
+ n = Notify.new( &action )
258
+ @list.push n
259
+ n
260
+ end
261
+
262
+ alias register action
263
+ alias with action
264
+
265
+
266
+ # Remove all or one Notify.
267
+ #
268
+ # @param notify [Notify] Notify to remove (all if not given).
269
+ def remove( notify = nil )
270
+ if notify
271
+ @list.delete( notify )
272
+ else
273
+ @list = []
274
+ end
275
+ end
276
+
277
+ # Run all notifiers in Notify set.
278
+ #
279
+ # @param args [Array<Object>] Arguments for notifiers.
280
+ def notify( *args )
281
+ if @enable
282
+ @list.each do |n|
283
+ n.notify( *args )
284
+ end
285
+ end
286
+ end
287
+
288
+
289
+ # Iterate over list of notifiers.
290
+ def each
291
+ @list.each do |n|
292
+ yield n
293
+ end
294
+ end
295
+
296
+
297
+ # Get Notify by index.
298
+ def []( idx )
299
+ @list[ idx ]
300
+ end
301
+
302
+ end
303
+
304
+
305
+
306
+ # Notify object including disable/enable possibility.
307
+ class Notify
308
+
309
+ # Enabled/disabled status.
310
+ attr_reader :enable
311
+
312
+
313
+ # Instantiation.
314
+ #
315
+ # @param action [Proc] Notification action.
316
+ def initialize( &action )
317
+ @action = action
318
+ @enable = true
319
+ end
320
+
321
+
322
+ # Perform notification action if enabled.
323
+ #
324
+ # @param args [Array<Object>] Data provided to action.
325
+ def notify( *args )
326
+ if @enable
327
+ @action.yield( *args )
328
+ end
329
+ end
330
+
331
+
332
+ # Enable/disable Notify.
333
+ #
334
+ # @param value [Boolean] Enable with true and disable with false.
335
+ def enable( value )
336
+ @enable = value
337
+ end
338
+
339
+ end
@@ -0,0 +1,229 @@
1
+ require 'test/unit'
2
+ require 'notifyhub'
3
+
4
+ # # Create class that includes interesting events.
5
+ # class Storage
6
+ #
7
+ # # Handle to NotifyHub.
8
+ # attr_accessor :hub
9
+ #
10
+ # def initialize
11
+ # # Create NotifyHub.
12
+ # @hub = NotifyHub.declare( :store, :load, :na )
13
+ # end
14
+ #
15
+ # # Store data and notify clients.
16
+ # def store( data )
17
+ # @data = data
18
+ # @hub[ :store ].notify( @data )
19
+ # end
20
+ #
21
+ # # Load data and notify clients.
22
+ # def load
23
+ # @hub[ :load ].notify( @data )
24
+ # @data
25
+ # end
26
+ # end
27
+ #
28
+ #
29
+ # storage = Storage.new
30
+ #
31
+ # # Setup notify action for store.
32
+ # storage.hub[ :store ].action do |data|
33
+ # puts "store: #{data}"
34
+ # end
35
+ #
36
+ # # Setup notify action for load.
37
+ # storage.hub[ :load ].action do |data|
38
+ # puts "load: #{data}"
39
+ # end
40
+ #
41
+ #
42
+ # # Use storage and get notifications.
43
+ # storage.store( "my data" )
44
+ # data = storage.load
45
+
46
+ class NotifyHubTest < Test::Unit::TestCase
47
+
48
+
49
+ # Create class that includes interesting events.
50
+ class Storage
51
+
52
+ # Handle to NotifyHub.
53
+ attr_accessor :hub
54
+
55
+ def initialize
56
+ # Create NotifyHub.
57
+ @hub = NotifyHub.declare( :store, :load, :na )
58
+ end
59
+
60
+ # Store data and notify clients.
61
+ def store( data )
62
+ @data = data
63
+ @hub[ :store ].notify( @data )
64
+ end
65
+
66
+ # Load data and notify clients.
67
+ def load
68
+ @hub[ :load ].notify( @data )
69
+ @data
70
+ end
71
+ end
72
+
73
+
74
+ def setup
75
+ @check = {}
76
+
77
+ @n = NotifyHub.auto
78
+
79
+ @n[ :on ].action do |val|
80
+ @check[ :create_1 ] = val
81
+ end
82
+
83
+ @n[ :on ].action do |val|
84
+ @check[ :create_2 ] = val
85
+ end
86
+
87
+ @n[ :off ].action do |val|
88
+ @check[ :create_3 ] = val
89
+ end
90
+ end
91
+
92
+
93
+ def test_integration
94
+
95
+ storage = Storage.new
96
+
97
+ store_data = nil
98
+ load_data = nil
99
+
100
+ # Setup notify action for store.
101
+ storage.hub[ :store ].action do |data|
102
+ @check[:store_data] = data
103
+ end
104
+
105
+ # Setup notify action for load.
106
+ storage.hub[ :load ].action do |data|
107
+ @check[:load_data] = data
108
+ end
109
+
110
+ storage.store( "my data" )
111
+ storage.load
112
+
113
+ assert_equal( @check[:store_data], "my data" )
114
+ assert_equal( @check[:load_data], "my data" )
115
+
116
+ end
117
+
118
+
119
+ def test_defining
120
+
121
+ [ :declare, :create, :auto ].each do |type|
122
+
123
+ case type
124
+ when :declare; n = NotifyHub.declare( :on, :off )
125
+ when :create
126
+ n = NotifyHub.create do
127
+ declare( :on, :off )
128
+ end
129
+ when :auto; n = NotifyHub.auto
130
+ end
131
+
132
+ n[ :on ].action do |val|
133
+ @check[ :create_1 ] = val
134
+ end
135
+
136
+ n[ :on ].action do |val|
137
+ @check[ :create_2 ] = val
138
+ end
139
+
140
+ n[ :off ].action do |val|
141
+ @check[ :create_3 ] = val
142
+ end
143
+
144
+ n[ :on ].notify( 1 )
145
+ n.notify( :off, 2 )
146
+
147
+ assert_equal( 1, @check[ :create_1 ] )
148
+ assert_equal( 1, @check[ :create_2 ] )
149
+ assert_equal( 2, @check[ :create_3 ] )
150
+
151
+ n = NotifyHub.create do
152
+ declare( :on, :off )
153
+ end
154
+
155
+ end
156
+
157
+ end
158
+
159
+
160
+ def test_enable_set
161
+ @n[ :off ].enable( false )
162
+ @n[ :off ].notify( 1 )
163
+ assert_equal( nil, @check[ :create_3 ] )
164
+ @n[ :off ].enable( true )
165
+ @n[ :off ].notify( 1 )
166
+ assert_equal( 1, @check[ :create_3 ] )
167
+ end
168
+
169
+
170
+ def test_enable_one
171
+ @n[ :on ][ 0 ].enable( false )
172
+ @n[ :on ].notify( 1 )
173
+ @n[ :off ].notify( 2 )
174
+ assert_equal( nil, @check[ :create_1 ] )
175
+ assert_equal( 1, @check[ :create_2 ] )
176
+ assert_equal( 2, @check[ :create_3 ] )
177
+
178
+ @n[ :on ].each do |i|
179
+ i.enable( true )
180
+ end
181
+
182
+ @n[ :on ].notify( 1 )
183
+ @n[ :off ].notify( 2 )
184
+ assert_equal( 1, @check[ :create_1 ] )
185
+ assert_equal( 1, @check[ :create_2 ] )
186
+ assert_equal( 2, @check[ :create_3 ] )
187
+ end
188
+
189
+
190
+ def test_remove
191
+ @n[ :on ].remove( @n[ :on ][ 0 ] )
192
+ @n[ :on ].notify( 1 )
193
+ @n[ :off ].notify( 2 )
194
+ assert_equal( nil, @check[ :create_1 ] )
195
+ assert_equal( 1, @check[ :create_2 ] )
196
+ assert_equal( 2, @check[ :create_3 ] )
197
+ end
198
+
199
+
200
+ def test_errors
201
+
202
+ n = NotifyHub.declare( :on, :off )
203
+
204
+ begin
205
+ n[ :not ].action do |val|
206
+ puts "This does not activate..."
207
+ end
208
+ rescue NotifyHub::NotFound
209
+ @check[ :error_action ] = true
210
+ end
211
+ assert_equal( true, @check[ :error_action ] )
212
+
213
+ begin
214
+ n[ :not ].notify( 2 )
215
+ rescue NotifyHub::NotFound
216
+ @check[ :error_notify ] = true
217
+ end
218
+ assert_equal( true, @check[ :error_notify ] )
219
+
220
+ begin
221
+ n.declare( :on )
222
+ rescue NotifyHub::Redefining
223
+ @check[ :error_redecl ] = true
224
+ end
225
+ assert_equal( true, @check[ :error_redecl ] )
226
+
227
+ end
228
+
229
+ end