eventmachine 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ added per-instance configurability to SmtpServer
2
+ --This line, and those below, will be ignored--
3
+
4
+ M protocols/smtpserver.rb
data/tests/test_basic.rb CHANGED
@@ -1,4 +1,4 @@
1
- # $Id: test_basic.rb 452 2007-07-21 13:35:16Z blackhedd $
1
+ # $Id: test_basic.rb 500 2007-08-17 09:45:20Z blackhedd $
2
2
  #
3
3
  # Author:: Francis Cianfrocca (gmail: blackhedd)
4
4
  # Homepage:: http://rubyeventmachine.com
@@ -93,6 +93,18 @@ class TestBasic < Test::Unit::TestCase
93
93
 
94
94
  #--------------------------------------
95
95
 
96
+ # EventMachine#run_block starts the reactor loop, runs the supplied block, and then STOPS
97
+ # the loop automatically. Contrast with EventMachine#run, which keeps running the reactor
98
+ # even after the supplied block completes.
99
+ def test_run_block
100
+ a = nil
101
+ EM.run_block { a = "Worked" }
102
+ assert a
103
+ end
104
+
105
+
106
+ #--------------------------------------
107
+
96
108
  end
97
109
 
98
110
 
@@ -1,4 +1,4 @@
1
- # $Id: test_futures.rb 323 2007-05-22 22:22:43Z blackhedd $
1
+ # $Id: test_futures.rb 534 2007-09-15 23:06:15Z blackhedd $
2
2
  #
3
3
  # Author:: Francis Cianfrocca (gmail: blackhedd)
4
4
  # Homepage:: http://rubyeventmachine.com
@@ -126,11 +126,88 @@ class TestFutures < Test::Unit::TestCase
126
126
  assert_equal(3, n)
127
127
  end
128
128
 
129
- def test_syntactic_sugar
130
- rc = RecursiveCallback.new
131
- rc.set_deferred_success 100
132
- rc.set_deferred_failure 200
133
- end
129
+
130
+
131
+ def test_syntactic_sugar
132
+ rc = RecursiveCallback.new
133
+ rc.set_deferred_success 100
134
+ rc.set_deferred_failure 200
135
+ end
136
+
137
+
138
+
139
+ # It doesn't raise an error to set deferred status more than once.
140
+ # In fact, this is a desired and useful idiom when it happens INSIDE
141
+ # a callback or errback.
142
+ # However, it's less useful otherwise, and in fact would generally be
143
+ # indicative of a programming error. However, we would like to be resistant
144
+ # to such errors. So whenever we set deferred status, we also clear BOTH
145
+ # stacks of handlers.
146
+ #
147
+ def test_double_calls
148
+ s = 0
149
+ e = 0
150
+
151
+ d = EM::DefaultDeferrable.new
152
+ d.callback {s += 1}
153
+ d.errback {e += 1}
154
+
155
+ d.succeed # We expect the callback to be called, and the errback to be DISCARDED.
156
+ d.fail # Presumably an error. We expect the errback NOT to be called.
157
+ d.succeed # We expect the callback to have been discarded and NOT to be called again.
158
+
159
+ assert_equal(1, s)
160
+ assert_equal(0, e)
161
+ end
162
+
163
+
164
+ # Adding a callback to a Deferrable that is already in a success state executes the callback
165
+ # immediately. The same applies to a an errback added to an already-failed Deferrable.
166
+ # HOWEVER, we expect NOT to be able to add errbacks to succeeded Deferrables, or callbacks
167
+ # to failed ones.
168
+ #
169
+ # We illustrate this with a rather contrived test. The test calls #fail after #succeed,
170
+ # which ordinarily would not happen in a real program.
171
+ #
172
+ # What we're NOT attempting to specify is what happens if a Deferrable is succeeded and then
173
+ # failed (or vice-versa). Should we then be able to add callbacks/errbacks of the appropriate
174
+ # type for immediate execution? For now at least, the official answer is "don't do that."
175
+ #
176
+ def test_delayed_callbacks
177
+ s1 = 0
178
+ s2 = 0
179
+ e = 0
180
+
181
+ d = EM::DefaultDeferrable.new
182
+ d.callback {s1 += 1}
183
+
184
+ d.succeed # Triggers and discards the callback.
185
+
186
+ d.callback {s2 += 1} # This callback is executed immediately and discarded.
187
+
188
+ d.errback {e += 1} # This errback should be DISCARDED and never execute.
189
+ d.fail # To prove it, let's
190
+
191
+ assert_equal( [1,1], [s1,s2] )
192
+ assert_equal( 0, e )
193
+ end
194
+
195
+
196
+
197
+
198
+ #
199
+ #
200
+ #
201
+ def test_timeout
202
+ n = 0
203
+ EM.run {
204
+ d = EM::DefaultDeferrable.new
205
+ d.callback {n = 1; EM.stop}
206
+ d.errback {n = 2; EM.stop}
207
+ d.timeout(1)
208
+ }
209
+ assert_equal( 2, n )
210
+ end
134
211
 
135
212
  end
136
213
 
@@ -1,4 +1,4 @@
1
- # $Id: test_httpclient.rb 398 2007-07-11 02:46:22Z blackhedd $
1
+ # $Id: test_httpclient.rb 518 2007-08-30 10:17:02Z blackhedd $
2
2
  #
3
3
  # Author:: Francis Cianfrocca (gmail: blackhedd)
4
4
  # Homepage:: http://rubyeventmachine.com
@@ -172,6 +172,22 @@ class TestHttpClient < Test::Unit::TestCase
172
172
  assert_equal( "0123456789", response[:content] )
173
173
  end
174
174
 
175
+
176
+ # TODO, need a more intelligent cookie tester.
177
+ # In fact, this whole test-harness needs a beefier server implementation.
178
+ def test_cookie
179
+ ok = false
180
+ EM.run {
181
+ c = EM::Protocols::HttpClient.send :request, :host => "www.bayshorenetworks.com", :port => 80, :cookie=>"aaa=bbb"
182
+ c.callback {|result|
183
+ ok = true;
184
+ EventMachine.stop
185
+ }
186
+ c.errback {EventMachine.stop}
187
+ }
188
+ assert ok
189
+ end
190
+
175
191
  end
176
192
 
177
193
 
data/tests/test_kb.rb ADDED
@@ -0,0 +1,60 @@
1
+ # $Id: test_kb.rb 502 2007-08-24 09:29:53Z blackhedd $
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 8 April 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+ #
26
+
27
+ $:.unshift "../lib"
28
+ require 'eventmachine'
29
+
30
+ class TestKeyboardEvents < Test::Unit::TestCase
31
+
32
+ def setup
33
+ end
34
+
35
+ def teardown
36
+ end
37
+
38
+ module KbHandler
39
+ include EM::Protocols::LineText2
40
+ def receive_line d
41
+ EM::stop if d == "STOP"
42
+ end
43
+ end
44
+
45
+ # This test doesn't actually do anything useful but is here to
46
+ # illustrate the usage. If you removed the timer and ran this test
47
+ # by itself on a console, and then typed into the console, it would
48
+ # work.
49
+ # I don't know how to get the test harness to simulate actual keystrokes.
50
+ # When someone figures that out, then we can make this a real test.
51
+ #
52
+ def test_kb
53
+ EM.run {
54
+ EM.open_keyboard KbHandler
55
+ EM::Timer.new(1) { EM.stop }
56
+ }
57
+ end
58
+
59
+ end
60
+
@@ -0,0 +1,46 @@
1
+ # $Id: test_running.rb 493 2007-08-13 20:10:46Z blackhedd $
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 8 April 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+ #
26
+
27
+ $:.unshift "../lib"
28
+ require 'eventmachine'
29
+
30
+ class TestRunning < Test::Unit::TestCase
31
+ def setup
32
+ end
33
+ def teardown
34
+ end
35
+
36
+ def test_running
37
+ assert_equal( false, EM::reactor_running? )
38
+ r = false
39
+ EM.run {
40
+ r = EM::reactor_running?
41
+ EM.stop
42
+ }
43
+ assert_equal( true, r )
44
+ end
45
+ end
46
+
@@ -0,0 +1,80 @@
1
+ # $Id: test_smtpclient.rb 535 2007-09-16 19:35:05Z blackhedd $
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 8 April 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+ #
26
+
27
+ $:.unshift "../lib"
28
+ require 'eventmachine'
29
+
30
+ class TestSmtpClient < Test::Unit::TestCase
31
+
32
+ Localhost = "127.0.0.1"
33
+ Localport = 9801
34
+
35
+ def setup
36
+ end
37
+
38
+ def teardown
39
+ end
40
+
41
+ def test_a
42
+ # No real tests until we have a server implementation to test against.
43
+ # This is what the call looks like, though:
44
+
45
+ EM.run {
46
+ d = EM::Protocols::SmtpClient.send :domain=>"example.com",
47
+ :host=>Localhost,
48
+ :port=>Localport, # optional, defaults 25
49
+ :starttls=>true,
50
+ :from=>"sender@example.com",
51
+ :to=> ["to_1@example.com", "to_2@example.com"],
52
+ :header=> {"Subject" => "This is a subject line"},
53
+ :body=> "This is the body of the email",
54
+ :verbose=>true
55
+ d.errback {|e|
56
+ p e
57
+ EM.stop
58
+ }
59
+ }
60
+ end
61
+
62
+ def test_content
63
+
64
+ EM.run {
65
+ d = EM::Protocols::SmtpClient.send :domain=>"example.com",
66
+ :host=>Localhost,
67
+ :port=>Localport, # optional, defaults 25
68
+ :starttls=>true,
69
+ :from=>"sender@example.com",
70
+ :to=> ["to_1@example.com", "to_2@example.com"],
71
+ :content => ["Subject: xxx\r\n\r\ndata\r\n.\r\n"],
72
+ :verbose=>true
73
+ d.errback {|e|
74
+ p e
75
+ EM.stop
76
+ }
77
+ }
78
+ end
79
+
80
+ end
@@ -0,0 +1,92 @@
1
+ # $Id: test_smtpserver.rb 523 2007-09-05 23:29:02Z blackhedd $
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 8 April 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+ #
26
+
27
+ $:.unshift "../lib"
28
+ require 'eventmachine'
29
+
30
+ class TestSmtpServer < Test::Unit::TestCase
31
+
32
+ # Don't test on port 25. It requires superuser and there's probably
33
+ # a mail server already running there anyway.
34
+ Localhost = "127.0.0.1"
35
+ Localport = 25001
36
+
37
+ # This class is an example of what you need to write in order
38
+ # to implement a mail server. You override the methods you are
39
+ # interested in. Some, but not all, of these are illustrated here.
40
+ #
41
+ class Mailserver < EM::Protocols::SmtpServer
42
+
43
+ attr_reader :my_msg_body, :my_sender, :my_recipients
44
+
45
+ def initialize *args
46
+ super
47
+ end
48
+ def receive_sender sender
49
+ @my_sender = sender
50
+ p sender
51
+ true
52
+ end
53
+ def receive_recipient rcpt
54
+ @my_recipients ||= []
55
+ @my_recipients << rcpt
56
+ true
57
+ end
58
+ def receive_data_chunk c
59
+ @my_msg_body = c.last
60
+ end
61
+ def connection_ended
62
+ EM.stop
63
+ end
64
+ end
65
+
66
+
67
+ def setup
68
+ end
69
+
70
+ def teardown
71
+ end
72
+
73
+ def test_mail
74
+ c = nil
75
+ EM.run {
76
+ EM.start_server( Localhost, Localport, Mailserver ) {|conn| c = conn}
77
+ EM::Timer.new(2) {EM.stop} # prevent hanging the test suite in case of error
78
+ EM::Protocols::SmtpClient.send :host=>Localhost,
79
+ :port=>Localport,
80
+ :domain=>"bogus",
81
+ :from=>"me@example.com",
82
+ :to=>"you@example.com",
83
+ :header=> {"Subject"=>"Email subject line", "Reply-to"=>"me@example.com"},
84
+ :body=>"Not much of interest here."
85
+
86
+ }
87
+ assert_equal( "Not much of interest here.", c.my_msg_body )
88
+ assert_equal( "<me@example.com>", c.my_sender )
89
+ assert_equal( ["<you@example.com>"], c.my_recipients )
90
+ end
91
+ end
92
+
@@ -0,0 +1,328 @@
1
+ # $Id: test_spawn.rb 532 2007-09-13 21:44:23Z blackhedd $
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 25 Aug 2007
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #---------------------------------------------------------------------------
23
+ #
24
+ #
25
+ #
26
+ #
27
+
28
+
29
+ $:.unshift "../lib"
30
+ require 'eventmachine'
31
+
32
+
33
+
34
+ class TestSpawn < Test::Unit::TestCase
35
+
36
+ def setup
37
+ end
38
+
39
+ def teardown
40
+ end
41
+
42
+
43
+ # Spawn a process that simply stops the reactor.
44
+ # Assert that the notification runs after the block that calls it.
45
+ #
46
+ def test_stop
47
+ x = nil
48
+ EM.run {
49
+ s = EM.spawn {EM.stop}
50
+ s.notify
51
+ x = true
52
+ }
53
+ assert x
54
+ end
55
+
56
+
57
+ # Pass a parameter to a spawned process.
58
+ #
59
+ def test_parms
60
+ val = 5
61
+ EM.run {
62
+ s = EM.spawn {|v| val *= v; EM.stop}
63
+ s.notify 3
64
+ }
65
+ assert_equal( 15, val )
66
+ end
67
+
68
+ # Pass multiple parameters to a spawned process.
69
+ #
70
+ def test_multiparms
71
+ val = 5
72
+ EM.run {
73
+ s = EM.spawn {|v1,v2| val *= (v1 + v2); EM.stop}
74
+ s.notify 3,4
75
+ }
76
+ assert_equal( 35, val )
77
+ end
78
+
79
+
80
+ # This test demonstrates that a notification does not happen immediately,
81
+ # but rather is scheduled sometime after the current code path completes.
82
+ #
83
+ def test_race
84
+ x = 0
85
+ EM.run {
86
+ s = EM.spawn {x *= 2; EM.stop}
87
+ s.notify
88
+ x = 2
89
+ }
90
+ assert_equal( 4, x)
91
+ end
92
+
93
+
94
+ # Spawn a process and notify it 25 times to run fibonacci
95
+ # on a pair of global variables.
96
+ #
97
+ def test_fibonacci
98
+ x = 1
99
+ y = 1
100
+ EM.run {
101
+ s = EM.spawn {x,y = y,x+y}
102
+ 25.times {s.notify}
103
+
104
+ t = EM.spawn {EM.stop}
105
+ t.notify
106
+ }
107
+ assert_equal( 121393, x)
108
+ assert_equal( 196418, y)
109
+ end
110
+
111
+ # This one spawns 25 distinct processes, and notifies each one once,
112
+ # rather than notifying a single process 25 times.
113
+ #
114
+ def test_another_fibonacci
115
+ x = 1
116
+ y = 1
117
+ EM.run {
118
+ 25.times {
119
+ s = EM.spawn {x,y = y,x+y}
120
+ s.notify
121
+ }
122
+
123
+ t = EM.spawn {EM.stop}
124
+ t.notify
125
+ }
126
+ assert_equal( 121393, x)
127
+ assert_equal( 196418, y)
128
+ end
129
+
130
+
131
+ # Make a chain of processes that notify each other in turn
132
+ # with intermediate fibonacci results. The final process in
133
+ # the chain stops the loop and returns the result.
134
+ #
135
+ def test_fibonacci_chain
136
+ a,b = nil
137
+
138
+ EM.run {
139
+ nextpid = EM.spawn {|x,y|
140
+ a,b = x,y
141
+ EM.stop
142
+ }
143
+
144
+ 25.times {
145
+ n = nextpid
146
+ nextpid = EM.spawn {|x,y| n.notify( y, x+y )}
147
+ }
148
+
149
+ nextpid.notify( 1, 1 )
150
+ }
151
+
152
+ assert_equal( 121393, a)
153
+ assert_equal( 196418, b)
154
+ end
155
+
156
+
157
+ # EM#yield gives a spawed process to yield control to other processes
158
+ # (in other words, to stop running), and to specify a different code block
159
+ # that will run on its next notification.
160
+ #
161
+ def test_yield
162
+ a = 0
163
+ EM.run {
164
+ n = EM.spawn {
165
+ a += 10
166
+ EM.yield {
167
+ a += 20
168
+ EM.yield {
169
+ a += 30
170
+ EM.stop
171
+ }
172
+ }
173
+ }
174
+ n.notify
175
+ n.notify
176
+ n.notify
177
+ }
178
+ assert_equal( 60, a )
179
+ end
180
+
181
+ # EM#yield_and_notify behaves like EM#yield, except that it also notifies the
182
+ # yielding process. This may sound trivial, since the yield block will run very
183
+ # shortly after with no action by the program, but this actually can be very useful,
184
+ # because it causes the reactor core to execute once before the yielding process
185
+ # gets control back. So it can be used to allow heavily-used network connections
186
+ # to clear buffers, or allow other processes to process their notifications.
187
+ #
188
+ # Notice in this test code that only a simple notify is needed at the bottom
189
+ # of the initial block. Even so, all of the yielded blocks will execute.
190
+ #
191
+ def test_yield_and_notify
192
+ a = 0
193
+ EM.run {
194
+ n = EM.spawn {
195
+ a += 10
196
+ EM.yield_and_notify {
197
+ a += 20
198
+ EM.yield_and_notify {
199
+ a += 30
200
+ EM.stop
201
+ }
202
+ }
203
+ }
204
+ n.notify
205
+ }
206
+ assert_equal( 60, a )
207
+ end
208
+
209
+ # resume is an alias for notify.
210
+ #
211
+ def test_resume
212
+ EM.run {
213
+ n = EM.spawn {EM.stop}
214
+ n.resume
215
+ }
216
+ assert true
217
+ end
218
+
219
+ # run is an idiomatic alias for notify.
220
+ #
221
+ def test_run
222
+ EM.run {
223
+ (EM.spawn {EM.stop}).run
224
+ }
225
+ assert true
226
+ end
227
+
228
+
229
+ # Clones the ping-pong example from the Erlang tutorial, in much less code.
230
+ # Illustrates that a spawned block executes in the context of a SpawnableObject.
231
+ # (Meaning, we can pass self as a parameter to another process that can then
232
+ # notify us.)
233
+ #
234
+ def test_ping_pong
235
+ n_pongs = 0
236
+ EM.run {
237
+ pong = EM.spawn {|x, ping|
238
+ n_pongs += 1
239
+ ping.notify( x-1 )
240
+ }
241
+ ping = EM.spawn {|x|
242
+ if x > 0
243
+ pong.notify x, self
244
+ else
245
+ EM.stop
246
+ end
247
+ }
248
+ ping.notify 3
249
+ }
250
+ assert_equal( 3, n_pongs )
251
+ end
252
+
253
+ # Illustrates that you can call notify inside a notification, and it will cause
254
+ # the currently-executing process to be re-notified. Of course, the new notification
255
+ # won't run until sometime after the current one completes.
256
+ #
257
+ def test_self_notify
258
+ n = 0
259
+ EM.run {
260
+ pid = EM.spawn {|x|
261
+ if x > 0
262
+ n += x
263
+ notify( x-1 )
264
+ else
265
+ EM.stop
266
+ end
267
+ }
268
+ pid.notify 3
269
+ }
270
+ assert_equal( 6, n )
271
+ end
272
+
273
+
274
+ # Illustrates that the block passed to #spawn executes in the context of a
275
+ # SpawnedProcess object, NOT in the local context. This can often be deceptive.
276
+ #
277
+ class BlockScopeTest
278
+ attr_reader :var
279
+ def run
280
+ # The following line correctly raises a NameError.
281
+ # The problem is that the programmer expected the spawned block to
282
+ # execute in the local context, but it doesn't.
283
+ #
284
+ # (EM.spawn { do_something }).notify ### NO! BAD!
285
+
286
+
287
+
288
+ # The following line correctly passes self as a parameter to the
289
+ # notified process.
290
+ #
291
+ (EM.spawn {|obj| obj.do_something }).notify(self)
292
+
293
+
294
+
295
+ # Here's another way to do it. This works because "myself" is bound
296
+ # in the local scope, unlike "self," so the spawned block sees it.
297
+ #
298
+ myself = self
299
+ (EM.spawn { myself.do_something }).notify
300
+
301
+
302
+
303
+ # And we end the loop.
304
+ # This is a tangential point, but observe that #notify never blocks.
305
+ # It merely appends a message to the internal queue of a spawned process
306
+ # and returns. As it turns out, the reactor processes notifications for ALL
307
+ # spawned processes in the order that #notify is called. So there is a
308
+ # reasonable expectation that the process which stops the reactor will
309
+ # execute after the previous ones in this method. HOWEVER, this is NOT
310
+ # a documented behavior and is subject to change.
311
+ #
312
+ (EM.spawn {EM.stop}).notify
313
+ end
314
+ def do_something
315
+ @var ||= 0
316
+ @var += 100
317
+ end
318
+ end
319
+
320
+ def test_block_scope
321
+ bs = BlockScopeTest.new
322
+ EM.run {
323
+ bs.run
324
+ }
325
+ assert_equal( 200, bs.var )
326
+ end
327
+
328
+ end