eventmachine 0.8.1 → 0.9.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.
@@ -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