eventmachine 0.12.6-x86-mswin32-60 → 0.12.8-x86-mswin32-60

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.
Files changed (116) hide show
  1. data/{docs/README → README} +21 -13
  2. data/Rakefile +14 -4
  3. data/docs/DEFERRABLES +0 -5
  4. data/docs/INSTALL +2 -4
  5. data/docs/LEGAL +1 -1
  6. data/docs/LIGHTWEIGHT_CONCURRENCY +0 -2
  7. data/docs/PURE_RUBY +0 -2
  8. data/docs/RELEASE_NOTES +0 -2
  9. data/docs/SMTP +0 -7
  10. data/docs/SPAWNED_PROCESSES +0 -4
  11. data/docs/TODO +0 -2
  12. data/eventmachine.gemspec +41 -32
  13. data/examples/ex_channel.rb +43 -0
  14. data/examples/ex_queue.rb +2 -0
  15. data/examples/helper.rb +2 -0
  16. data/ext/cmain.cpp +685 -586
  17. data/ext/cplusplus.cpp +15 -6
  18. data/ext/ed.cpp +1732 -1522
  19. data/ext/ed.h +407 -380
  20. data/ext/em.cpp +2263 -1937
  21. data/ext/em.h +223 -186
  22. data/ext/eventmachine.h +111 -98
  23. data/ext/eventmachine_cpp.h +1 -0
  24. data/ext/extconf.rb +4 -0
  25. data/ext/kb.cpp +81 -82
  26. data/ext/pipe.cpp +349 -351
  27. data/ext/project.h +21 -0
  28. data/ext/rubymain.cpp +1047 -847
  29. data/ext/ssl.cpp +38 -1
  30. data/ext/ssl.h +5 -1
  31. data/java/src/com/rubyeventmachine/Application.java +7 -3
  32. data/java/src/com/rubyeventmachine/EmReactor.java +16 -1
  33. data/java/src/com/rubyeventmachine/tests/ConnectTest.java +25 -3
  34. data/lib/{protocols → em}/buftok.rb +16 -5
  35. data/lib/em/callback.rb +26 -0
  36. data/lib/em/channel.rb +57 -0
  37. data/lib/em/connection.rb +505 -0
  38. data/lib/em/deferrable.rb +144 -165
  39. data/lib/em/file_watch.rb +54 -0
  40. data/lib/em/future.rb +24 -25
  41. data/lib/em/messages.rb +1 -1
  42. data/lib/em/process_watch.rb +44 -0
  43. data/lib/em/processes.rb +119 -113
  44. data/lib/em/protocols.rb +35 -0
  45. data/lib/em/protocols/header_and_content.rb +138 -0
  46. data/lib/em/protocols/httpclient.rb +263 -0
  47. data/lib/em/protocols/httpclient2.rb +582 -0
  48. data/lib/{protocols → em/protocols}/line_and_text.rb +2 -2
  49. data/lib/em/protocols/linetext2.rb +160 -0
  50. data/lib/{protocols → em/protocols}/memcache.rb +37 -7
  51. data/lib/em/protocols/object_protocol.rb +39 -0
  52. data/lib/em/protocols/postgres3.rb +247 -0
  53. data/lib/em/protocols/saslauth.rb +175 -0
  54. data/lib/em/protocols/smtpclient.rb +331 -0
  55. data/lib/em/protocols/smtpserver.rb +547 -0
  56. data/lib/em/protocols/stomp.rb +200 -0
  57. data/lib/{protocols → em/protocols}/tcptest.rb +21 -25
  58. data/lib/em/queue.rb +61 -0
  59. data/lib/em/spawnable.rb +53 -56
  60. data/lib/em/streamer.rb +92 -74
  61. data/lib/em/timers.rb +55 -0
  62. data/lib/em/version.rb +3 -0
  63. data/lib/eventmachine.rb +1636 -1926
  64. data/lib/evma.rb +1 -1
  65. data/lib/jeventmachine.rb +106 -101
  66. data/lib/pr_eventmachine.rb +47 -36
  67. data/tasks/project.rake +2 -1
  68. data/tests/client.crt +31 -0
  69. data/tests/client.key +51 -0
  70. data/tests/test_attach.rb +18 -0
  71. data/tests/test_basic.rb +285 -231
  72. data/tests/test_channel.rb +63 -0
  73. data/tests/test_connection_count.rb +2 -2
  74. data/tests/test_epoll.rb +162 -163
  75. data/tests/test_errors.rb +36 -36
  76. data/tests/test_exc.rb +22 -25
  77. data/tests/test_file_watch.rb +49 -0
  78. data/tests/test_futures.rb +77 -93
  79. data/tests/test_hc.rb +2 -2
  80. data/tests/test_httpclient.rb +55 -52
  81. data/tests/test_httpclient2.rb +153 -155
  82. data/tests/test_inactivity_timeout.rb +30 -0
  83. data/tests/test_kb.rb +8 -9
  84. data/tests/test_ltp2.rb +274 -277
  85. data/tests/test_next_tick.rb +135 -109
  86. data/tests/test_object_protocol.rb +37 -0
  87. data/tests/test_process_watch.rb +48 -0
  88. data/tests/test_processes.rb +128 -95
  89. data/tests/test_proxy_connection.rb +92 -0
  90. data/tests/test_pure.rb +1 -5
  91. data/tests/test_queue.rb +44 -0
  92. data/tests/test_running.rb +9 -14
  93. data/tests/test_sasl.rb +32 -34
  94. data/tests/test_send_file.rb +175 -176
  95. data/tests/test_servers.rb +37 -41
  96. data/tests/test_smtpserver.rb +47 -55
  97. data/tests/test_spawn.rb +284 -291
  98. data/tests/test_ssl_args.rb +1 -1
  99. data/tests/test_ssl_methods.rb +1 -1
  100. data/tests/test_ssl_verify.rb +82 -0
  101. data/tests/test_timers.rb +81 -88
  102. data/tests/test_ud.rb +0 -7
  103. data/tests/testem.rb +1 -1
  104. metadata +52 -36
  105. data/lib/em/eventable.rb +0 -39
  106. data/lib/eventmachine_version.rb +0 -31
  107. data/lib/protocols/header_and_content.rb +0 -129
  108. data/lib/protocols/httpcli2.rb +0 -803
  109. data/lib/protocols/httpclient.rb +0 -270
  110. data/lib/protocols/linetext2.rb +0 -161
  111. data/lib/protocols/postgres.rb +0 -261
  112. data/lib/protocols/saslauth.rb +0 -179
  113. data/lib/protocols/smtpclient.rb +0 -308
  114. data/lib/protocols/smtpserver.rb +0 -556
  115. data/lib/protocols/stomp.rb +0 -153
  116. data/tests/test_eventables.rb +0 -77
@@ -29,52 +29,48 @@ require 'eventmachine'
29
29
  require 'socket'
30
30
  require 'test/unit'
31
31
 
32
-
33
32
  class TestServers < Test::Unit::TestCase
34
33
 
35
- Host = "127.0.0.1"
36
- Port = 9555
37
-
38
- module NetstatHelper
39
- GlobalUdp4Rexp = /udp.*\s+(?:\*|(?:0\.){3}0)[:.](\d+)\s/i
40
- GlobalTcp4Rexp = /tcp.*\s+(?:\*|(?:0\.){3}0)[:.](\d+)\s/i
41
- LocalUdpRexp = /udp.*\s+(?:127\.0\.0\.1|::1)[:.](\d+)\s/i
42
- LocalTcpRexp = /tcp.*\s+(?:127\.0\.0\.1|::1)[:.](\d+)\s/i
43
- def grep_netstat(pattern)
44
- `netstat -an`.scan(/^.*$/).grep(pattern)
34
+ Host = "127.0.0.1"
35
+ Port = 9555
36
+
37
+ module NetstatHelper
38
+ GlobalUdp4Rexp = /udp.*\s+(?:\*|(?:0\.){3}0)[:.](\d+)\s/i
39
+ GlobalTcp4Rexp = /tcp.*\s+(?:\*|(?:0\.){3}0)[:.](\d+)\s/i
40
+ LocalUdpRexp = /udp.*\s+(?:127\.0\.0\.1|::1)[:.](\d+)\s/i
41
+ LocalTcpRexp = /tcp.*\s+(?:127\.0\.0\.1|::1)[:.](\d+)\s/i
42
+ def grep_netstat(pattern)
43
+ `netstat -an`.scan(/^.*$/).grep(pattern)
45
44
  end
46
45
  end
47
- include NetstatHelper
46
+ include NetstatHelper
48
47
 
49
- class TestStopServer < EM::Connection
50
- def initialize *args
51
- super
52
- end
53
- def post_init
54
- # TODO,sucks that this isn't OOPy enough.
55
- EM.stop_server @server_instance
56
- end
57
- end
58
-
59
- def run_test_stop_server
60
- EM.run {
61
- sig = EM.start_server(Host, Port)
62
- assert(grep_netstat(LocalTcpRexp).grep(%r(#{Port})).size >= 1, "Server didn't start")
63
- EM.stop_server sig
64
- # Give the server some time to shutdown.
65
- EM.add_timer(0.1) {
66
- assert(grep_netstat(LocalTcpRexp).grep(%r(#{Port})).empty?, "Servers didn't stop")
67
- EM.stop
68
- }
69
- }
70
- end
71
- def test_stop_server
72
- assert(grep_netstat(LocalTcpRexp).grep(Port).empty?, "Port already in use")
73
- 5.times {run_test_stop_server}
74
- assert(grep_netstat(LocalTcpRexp).grep(%r(#{Port})).empty?, "Servers didn't stop")
75
- end
48
+ class TestStopServer < EM::Connection
49
+ def initialize *args
50
+ super
51
+ end
52
+ def post_init
53
+ # TODO,sucks that this isn't OOPy enough.
54
+ EM.stop_server @server_instance
55
+ end
56
+ end
76
57
 
58
+ def run_test_stop_server
59
+ EM.run {
60
+ sig = EM.start_server(Host, Port)
61
+ assert(grep_netstat(LocalTcpRexp).grep(%r(#{Port})).size >= 1, "Server didn't start")
62
+ EM.stop_server sig
63
+ # Give the server some time to shutdown.
64
+ EM.add_timer(0.1) {
65
+ assert(grep_netstat(LocalTcpRexp).grep(%r(#{Port})).empty?, "Servers didn't stop")
66
+ EM.stop
67
+ }
68
+ }
69
+ end
70
+ def test_stop_server
71
+ assert(grep_netstat(LocalTcpRexp).grep(Port).empty?, "Port already in use")
72
+ 5.times {run_test_stop_server}
73
+ assert(grep_netstat(LocalTcpRexp).grep(%r(#{Port})).empty?, "Servers didn't stop")
74
+ end
77
75
 
78
76
  end
79
-
80
-
@@ -30,64 +30,56 @@ require 'test/unit'
30
30
 
31
31
  class TestSmtpServer < Test::Unit::TestCase
32
32
 
33
- # Don't test on port 25. It requires superuser and there's probably
34
- # a mail server already running there anyway.
35
- Localhost = "127.0.0.1"
36
- Localport = 25001
33
+ # Don't test on port 25. It requires superuser and there's probably
34
+ # a mail server already running there anyway.
35
+ Localhost = "127.0.0.1"
36
+ Localport = 25001
37
37
 
38
- # This class is an example of what you need to write in order
39
- # to implement a mail server. You override the methods you are
40
- # interested in. Some, but not all, of these are illustrated here.
41
- #
42
- class Mailserver < EM::Protocols::SmtpServer
38
+ # This class is an example of what you need to write in order
39
+ # to implement a mail server. You override the methods you are
40
+ # interested in. Some, but not all, of these are illustrated here.
41
+ #
42
+ class Mailserver < EM::Protocols::SmtpServer
43
43
 
44
- attr_reader :my_msg_body, :my_sender, :my_recipients
44
+ attr_reader :my_msg_body, :my_sender, :my_recipients
45
45
 
46
- def initialize *args
47
- super
48
- end
49
- def receive_sender sender
50
- @my_sender = sender
51
- #p sender
52
- true
53
- end
54
- def receive_recipient rcpt
55
- @my_recipients ||= []
56
- @my_recipients << rcpt
57
- true
58
- end
59
- def receive_data_chunk c
60
- @my_msg_body = c.last
61
- end
62
- def connection_ended
63
- EM.stop
64
- end
65
- end
46
+ def initialize *args
47
+ super
48
+ end
49
+ def receive_sender sender
50
+ @my_sender = sender
51
+ #p sender
52
+ true
53
+ end
54
+ def receive_recipient rcpt
55
+ @my_recipients ||= []
56
+ @my_recipients << rcpt
57
+ true
58
+ end
59
+ def receive_data_chunk c
60
+ @my_msg_body = c.last
61
+ end
62
+ def connection_ended
63
+ EM.stop
64
+ end
65
+ end
66
66
 
67
+ def test_mail
68
+ c = nil
69
+ EM.run {
70
+ EM.start_server( Localhost, Localport, Mailserver ) {|conn| c = conn}
71
+ EM::Timer.new(2) {EM.stop} # prevent hanging the test suite in case of error
72
+ EM::Protocols::SmtpClient.send :host=>Localhost,
73
+ :port=>Localport,
74
+ :domain=>"bogus",
75
+ :from=>"me@example.com",
76
+ :to=>"you@example.com",
77
+ :header=> {"Subject"=>"Email subject line", "Reply-to"=>"me@example.com"},
78
+ :body=>"Not much of interest here."
67
79
 
68
- def setup
69
- end
70
-
71
- def teardown
72
- end
73
-
74
- def test_mail
75
- c = nil
76
- EM.run {
77
- EM.start_server( Localhost, Localport, Mailserver ) {|conn| c = conn}
78
- EM::Timer.new(2) {EM.stop} # prevent hanging the test suite in case of error
79
- EM::Protocols::SmtpClient.send :host=>Localhost,
80
- :port=>Localport,
81
- :domain=>"bogus",
82
- :from=>"me@example.com",
83
- :to=>"you@example.com",
84
- :header=> {"Subject"=>"Email subject line", "Reply-to"=>"me@example.com"},
85
- :body=>"Not much of interest here."
86
-
87
- }
88
- assert_equal( "Not much of interest here.", c.my_msg_body )
89
- assert_equal( "<me@example.com>", c.my_sender )
90
- assert_equal( ["<you@example.com>"], c.my_recipients )
91
- end
80
+ }
81
+ assert_equal( "Not much of interest here.", c.my_msg_body )
82
+ assert_equal( "<me@example.com>", c.my_sender )
83
+ assert_equal( ["<you@example.com>"], c.my_recipients )
84
+ end
92
85
  end
93
-
data/tests/test_spawn.rb CHANGED
@@ -34,296 +34,289 @@ require 'test/unit'
34
34
 
35
35
  class TestSpawn < Test::Unit::TestCase
36
36
 
37
- def setup
38
- end
39
-
40
- def teardown
41
- end
42
-
43
-
44
- # Spawn a process that simply stops the reactor.
45
- # Assert that the notification runs after the block that calls it.
46
- #
47
- def test_stop
48
- x = nil
49
- EM.run {
50
- s = EM.spawn {EM.stop}
51
- s.notify
52
- x = true
53
- }
54
- assert x
55
- end
56
-
57
-
58
- # Pass a parameter to a spawned process.
59
- #
60
- def test_parms
61
- val = 5
62
- EM.run {
63
- s = EM.spawn {|v| val *= v; EM.stop}
64
- s.notify 3
65
- }
66
- assert_equal( 15, val )
67
- end
68
-
69
- # Pass multiple parameters to a spawned process.
70
- #
71
- def test_multiparms
72
- val = 5
73
- EM.run {
74
- s = EM.spawn {|v1,v2| val *= (v1 + v2); EM.stop}
75
- s.notify 3,4
76
- }
77
- assert_equal( 35, val )
78
- end
79
-
80
-
81
- # This test demonstrates that a notification does not happen immediately,
82
- # but rather is scheduled sometime after the current code path completes.
83
- #
84
- def test_race
85
- x = 0
86
- EM.run {
87
- s = EM.spawn {x *= 2; EM.stop}
88
- s.notify
89
- x = 2
90
- }
91
- assert_equal( 4, x)
92
- end
93
-
94
-
95
- # Spawn a process and notify it 25 times to run fibonacci
96
- # on a pair of global variables.
97
- #
98
- def test_fibonacci
99
- x = 1
100
- y = 1
101
- EM.run {
102
- s = EM.spawn {x,y = y,x+y}
103
- 25.times {s.notify}
104
-
105
- t = EM.spawn {EM.stop}
106
- t.notify
107
- }
108
- assert_equal( 121393, x)
109
- assert_equal( 196418, y)
110
- end
111
-
112
- # This one spawns 25 distinct processes, and notifies each one once,
113
- # rather than notifying a single process 25 times.
114
- #
115
- def test_another_fibonacci
116
- x = 1
117
- y = 1
118
- EM.run {
119
- 25.times {
120
- s = EM.spawn {x,y = y,x+y}
121
- s.notify
122
- }
123
-
124
- t = EM.spawn {EM.stop}
125
- t.notify
126
- }
127
- assert_equal( 121393, x)
128
- assert_equal( 196418, y)
129
- end
130
-
131
-
132
- # Make a chain of processes that notify each other in turn
133
- # with intermediate fibonacci results. The final process in
134
- # the chain stops the loop and returns the result.
135
- #
136
- def test_fibonacci_chain
137
- a,b = nil
138
-
139
- EM.run {
140
- nextpid = EM.spawn {|x,y|
141
- a,b = x,y
142
- EM.stop
143
- }
144
-
145
- 25.times {
146
- n = nextpid
147
- nextpid = EM.spawn {|x,y| n.notify( y, x+y )}
148
- }
149
-
150
- nextpid.notify( 1, 1 )
151
- }
152
-
153
- assert_equal( 121393, a)
154
- assert_equal( 196418, b)
155
- end
156
-
157
-
158
- # EM#yield gives a spawed process to yield control to other processes
159
- # (in other words, to stop running), and to specify a different code block
160
- # that will run on its next notification.
161
- #
162
- def test_yield
163
- a = 0
164
- EM.run {
165
- n = EM.spawn {
166
- a += 10
167
- EM.yield {
168
- a += 20
169
- EM.yield {
170
- a += 30
171
- EM.stop
172
- }
173
- }
174
- }
175
- n.notify
176
- n.notify
177
- n.notify
178
- }
179
- assert_equal( 60, a )
180
- end
181
-
182
- # EM#yield_and_notify behaves like EM#yield, except that it also notifies the
183
- # yielding process. This may sound trivial, since the yield block will run very
184
- # shortly after with no action by the program, but this actually can be very useful,
185
- # because it causes the reactor core to execute once before the yielding process
186
- # gets control back. So it can be used to allow heavily-used network connections
187
- # to clear buffers, or allow other processes to process their notifications.
188
- #
189
- # Notice in this test code that only a simple notify is needed at the bottom
190
- # of the initial block. Even so, all of the yielded blocks will execute.
191
- #
192
- def test_yield_and_notify
193
- a = 0
194
- EM.run {
195
- n = EM.spawn {
196
- a += 10
197
- EM.yield_and_notify {
198
- a += 20
199
- EM.yield_and_notify {
200
- a += 30
201
- EM.stop
202
- }
203
- }
204
- }
205
- n.notify
206
- }
207
- assert_equal( 60, a )
208
- end
209
-
210
- # resume is an alias for notify.
211
- #
212
- def test_resume
213
- EM.run {
214
- n = EM.spawn {EM.stop}
215
- n.resume
216
- }
217
- assert true
218
- end
219
-
220
- # run is an idiomatic alias for notify.
221
- #
222
- def test_run
223
- EM.run {
224
- (EM.spawn {EM.stop}).run
225
- }
226
- assert true
227
- end
228
-
229
-
230
- # Clones the ping-pong example from the Erlang tutorial, in much less code.
231
- # Illustrates that a spawned block executes in the context of a SpawnableObject.
232
- # (Meaning, we can pass self as a parameter to another process that can then
233
- # notify us.)
234
- #
235
- def test_ping_pong
236
- n_pongs = 0
237
- EM.run {
238
- pong = EM.spawn {|x, ping|
239
- n_pongs += 1
240
- ping.notify( x-1 )
241
- }
242
- ping = EM.spawn {|x|
243
- if x > 0
244
- pong.notify x, self
245
- else
246
- EM.stop
247
- end
248
- }
249
- ping.notify 3
250
- }
251
- assert_equal( 3, n_pongs )
252
- end
253
-
254
- # Illustrates that you can call notify inside a notification, and it will cause
255
- # the currently-executing process to be re-notified. Of course, the new notification
256
- # won't run until sometime after the current one completes.
257
- #
258
- def test_self_notify
259
- n = 0
260
- EM.run {
261
- pid = EM.spawn {|x|
262
- if x > 0
263
- n += x
264
- notify( x-1 )
265
- else
266
- EM.stop
267
- end
268
- }
269
- pid.notify 3
270
- }
271
- assert_equal( 6, n )
272
- end
273
-
274
-
275
- # Illustrates that the block passed to #spawn executes in the context of a
276
- # SpawnedProcess object, NOT in the local context. This can often be deceptive.
277
- #
278
- class BlockScopeTest
279
- attr_reader :var
280
- def run
281
- # The following line correctly raises a NameError.
282
- # The problem is that the programmer expected the spawned block to
283
- # execute in the local context, but it doesn't.
284
- #
285
- # (EM.spawn { do_something }).notify ### NO! BAD!
286
-
287
-
288
-
289
- # The following line correctly passes self as a parameter to the
290
- # notified process.
291
- #
292
- (EM.spawn {|obj| obj.do_something }).notify(self)
293
-
294
-
295
-
296
- # Here's another way to do it. This works because "myself" is bound
297
- # in the local scope, unlike "self," so the spawned block sees it.
298
- #
299
- myself = self
300
- (EM.spawn { myself.do_something }).notify
301
-
302
-
303
-
304
- # And we end the loop.
305
- # This is a tangential point, but observe that #notify never blocks.
306
- # It merely appends a message to the internal queue of a spawned process
307
- # and returns. As it turns out, the reactor processes notifications for ALL
308
- # spawned processes in the order that #notify is called. So there is a
309
- # reasonable expectation that the process which stops the reactor will
310
- # execute after the previous ones in this method. HOWEVER, this is NOT
311
- # a documented behavior and is subject to change.
312
- #
313
- (EM.spawn {EM.stop}).notify
314
- end
315
- def do_something
316
- @var ||= 0
317
- @var += 100
318
- end
319
- end
320
-
321
- def test_block_scope
322
- bs = BlockScopeTest.new
323
- EM.run {
324
- bs.run
325
- }
326
- assert_equal( 200, bs.var )
327
- end
37
+ # Spawn a process that simply stops the reactor.
38
+ # Assert that the notification runs after the block that calls it.
39
+ #
40
+ def test_stop
41
+ x = nil
42
+ EM.run {
43
+ s = EM.spawn {EM.stop}
44
+ s.notify
45
+ x = true
46
+ }
47
+ assert x
48
+ end
49
+
50
+
51
+ # Pass a parameter to a spawned process.
52
+ #
53
+ def test_parms
54
+ val = 5
55
+ EM.run {
56
+ s = EM.spawn {|v| val *= v; EM.stop}
57
+ s.notify 3
58
+ }
59
+ assert_equal( 15, val )
60
+ end
61
+
62
+ # Pass multiple parameters to a spawned process.
63
+ #
64
+ def test_multiparms
65
+ val = 5
66
+ EM.run {
67
+ s = EM.spawn {|v1,v2| val *= (v1 + v2); EM.stop}
68
+ s.notify 3,4
69
+ }
70
+ assert_equal( 35, val )
71
+ end
72
+
73
+
74
+ # This test demonstrates that a notification does not happen immediately,
75
+ # but rather is scheduled sometime after the current code path completes.
76
+ #
77
+ def test_race
78
+ x = 0
79
+ EM.run {
80
+ s = EM.spawn {x *= 2; EM.stop}
81
+ s.notify
82
+ x = 2
83
+ }
84
+ assert_equal( 4, x)
85
+ end
86
+
87
+
88
+ # Spawn a process and notify it 25 times to run fibonacci
89
+ # on a pair of global variables.
90
+ #
91
+ def test_fibonacci
92
+ x = 1
93
+ y = 1
94
+ EM.run {
95
+ s = EM.spawn {x,y = y,x+y}
96
+ 25.times {s.notify}
97
+
98
+ t = EM.spawn {EM.stop}
99
+ t.notify
100
+ }
101
+ assert_equal( 121393, x)
102
+ assert_equal( 196418, y)
103
+ end
104
+
105
+ # This one spawns 25 distinct processes, and notifies each one once,
106
+ # rather than notifying a single process 25 times.
107
+ #
108
+ def test_another_fibonacci
109
+ x = 1
110
+ y = 1
111
+ EM.run {
112
+ 25.times {
113
+ s = EM.spawn {x,y = y,x+y}
114
+ s.notify
115
+ }
116
+
117
+ t = EM.spawn {EM.stop}
118
+ t.notify
119
+ }
120
+ assert_equal( 121393, x)
121
+ assert_equal( 196418, y)
122
+ end
123
+
124
+
125
+ # Make a chain of processes that notify each other in turn
126
+ # with intermediate fibonacci results. The final process in
127
+ # the chain stops the loop and returns the result.
128
+ #
129
+ def test_fibonacci_chain
130
+ a,b = nil
131
+
132
+ EM.run {
133
+ nextpid = EM.spawn {|x,y|
134
+ a,b = x,y
135
+ EM.stop
136
+ }
137
+
138
+ 25.times {
139
+ n = nextpid
140
+ nextpid = EM.spawn {|x,y| n.notify( y, x+y )}
141
+ }
142
+
143
+ nextpid.notify( 1, 1 )
144
+ }
145
+
146
+ assert_equal( 121393, a)
147
+ assert_equal( 196418, b)
148
+ end
149
+
150
+
151
+ # EM#yield gives a spawed process to yield control to other processes
152
+ # (in other words, to stop running), and to specify a different code block
153
+ # that will run on its next notification.
154
+ #
155
+ def test_yield
156
+ a = 0
157
+ EM.run {
158
+ n = EM.spawn {
159
+ a += 10
160
+ EM.yield {
161
+ a += 20
162
+ EM.yield {
163
+ a += 30
164
+ EM.stop
165
+ }
166
+ }
167
+ }
168
+ n.notify
169
+ n.notify
170
+ n.notify
171
+ }
172
+ assert_equal( 60, a )
173
+ end
174
+
175
+ # EM#yield_and_notify behaves like EM#yield, except that it also notifies the
176
+ # yielding process. This may sound trivial, since the yield block will run very
177
+ # shortly after with no action by the program, but this actually can be very useful,
178
+ # because it causes the reactor core to execute once before the yielding process
179
+ # gets control back. So it can be used to allow heavily-used network connections
180
+ # to clear buffers, or allow other processes to process their notifications.
181
+ #
182
+ # Notice in this test code that only a simple notify is needed at the bottom
183
+ # of the initial block. Even so, all of the yielded blocks will execute.
184
+ #
185
+ def test_yield_and_notify
186
+ a = 0
187
+ EM.run {
188
+ n = EM.spawn {
189
+ a += 10
190
+ EM.yield_and_notify {
191
+ a += 20
192
+ EM.yield_and_notify {
193
+ a += 30
194
+ EM.stop
195
+ }
196
+ }
197
+ }
198
+ n.notify
199
+ }
200
+ assert_equal( 60, a )
201
+ end
202
+
203
+ # resume is an alias for notify.
204
+ #
205
+ def test_resume
206
+ EM.run {
207
+ n = EM.spawn {EM.stop}
208
+ n.resume
209
+ }
210
+ assert true
211
+ end
212
+
213
+ # run is an idiomatic alias for notify.
214
+ #
215
+ def test_run
216
+ EM.run {
217
+ (EM.spawn {EM.stop}).run
218
+ }
219
+ assert true
220
+ end
221
+
222
+
223
+ # Clones the ping-pong example from the Erlang tutorial, in much less code.
224
+ # Illustrates that a spawned block executes in the context of a SpawnableObject.
225
+ # (Meaning, we can pass self as a parameter to another process that can then
226
+ # notify us.)
227
+ #
228
+ def test_ping_pong
229
+ n_pongs = 0
230
+ EM.run {
231
+ pong = EM.spawn {|x, ping|
232
+ n_pongs += 1
233
+ ping.notify( x-1 )
234
+ }
235
+ ping = EM.spawn {|x|
236
+ if x > 0
237
+ pong.notify x, self
238
+ else
239
+ EM.stop
240
+ end
241
+ }
242
+ ping.notify 3
243
+ }
244
+ assert_equal( 3, n_pongs )
245
+ end
246
+
247
+ # Illustrates that you can call notify inside a notification, and it will cause
248
+ # the currently-executing process to be re-notified. Of course, the new notification
249
+ # won't run until sometime after the current one completes.
250
+ #
251
+ def test_self_notify
252
+ n = 0
253
+ EM.run {
254
+ pid = EM.spawn {|x|
255
+ if x > 0
256
+ n += x
257
+ notify( x-1 )
258
+ else
259
+ EM.stop
260
+ end
261
+ }
262
+ pid.notify 3
263
+ }
264
+ assert_equal( 6, n )
265
+ end
266
+
267
+
268
+ # Illustrates that the block passed to #spawn executes in the context of a
269
+ # SpawnedProcess object, NOT in the local context. This can often be deceptive.
270
+ #
271
+ class BlockScopeTest
272
+ attr_reader :var
273
+ def run
274
+ # The following line correctly raises a NameError.
275
+ # The problem is that the programmer expected the spawned block to
276
+ # execute in the local context, but it doesn't.
277
+ #
278
+ # (EM.spawn { do_something }).notify ### NO! BAD!
279
+
280
+
281
+
282
+ # The following line correctly passes self as a parameter to the
283
+ # notified process.
284
+ #
285
+ (EM.spawn {|obj| obj.do_something }).notify(self)
286
+
287
+
288
+
289
+ # Here's another way to do it. This works because "myself" is bound
290
+ # in the local scope, unlike "self," so the spawned block sees it.
291
+ #
292
+ myself = self
293
+ (EM.spawn { myself.do_something }).notify
294
+
295
+
296
+
297
+ # And we end the loop.
298
+ # This is a tangential point, but observe that #notify never blocks.
299
+ # It merely appends a message to the internal queue of a spawned process
300
+ # and returns. As it turns out, the reactor processes notifications for ALL
301
+ # spawned processes in the order that #notify is called. So there is a
302
+ # reasonable expectation that the process which stops the reactor will
303
+ # execute after the previous ones in this method. HOWEVER, this is NOT
304
+ # a documented behavior and is subject to change.
305
+ #
306
+ (EM.spawn {EM.stop}).notify
307
+ end
308
+ def do_something
309
+ @var ||= 0
310
+ @var += 100
311
+ end
312
+ end
313
+
314
+ def test_block_scope
315
+ bs = BlockScopeTest.new
316
+ EM.run {
317
+ bs.run
318
+ }
319
+ assert_equal( 200, bs.var )
320
+ end
328
321
 
329
322
  end