wj_eventmachine 1.3.0.dev.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.
Files changed (180) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +179 -0
  3. data/GNU +281 -0
  4. data/LICENSE +60 -0
  5. data/README.md +110 -0
  6. data/docs/DocumentationGuidesIndex.md +27 -0
  7. data/docs/GettingStarted.md +520 -0
  8. data/docs/old/ChangeLog +211 -0
  9. data/docs/old/DEFERRABLES +246 -0
  10. data/docs/old/EPOLL +141 -0
  11. data/docs/old/INSTALL +13 -0
  12. data/docs/old/KEYBOARD +42 -0
  13. data/docs/old/LEGAL +25 -0
  14. data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
  15. data/docs/old/PURE_RUBY +75 -0
  16. data/docs/old/RELEASE_NOTES +94 -0
  17. data/docs/old/SMTP +4 -0
  18. data/docs/old/SPAWNED_PROCESSES +148 -0
  19. data/docs/old/TODO +8 -0
  20. data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
  21. data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
  22. data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
  23. data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
  24. data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
  25. data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
  26. data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
  27. data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
  28. data/examples/old/ex_channel.rb +43 -0
  29. data/examples/old/ex_queue.rb +2 -0
  30. data/examples/old/ex_tick_loop_array.rb +15 -0
  31. data/examples/old/ex_tick_loop_counter.rb +32 -0
  32. data/examples/old/helper.rb +2 -0
  33. data/ext/binder.cpp +124 -0
  34. data/ext/binder.h +52 -0
  35. data/ext/cmain.cpp +1046 -0
  36. data/ext/ed.cpp +2238 -0
  37. data/ext/ed.h +460 -0
  38. data/ext/em.cpp +2378 -0
  39. data/ext/em.h +266 -0
  40. data/ext/eventmachine.h +152 -0
  41. data/ext/extconf.rb +285 -0
  42. data/ext/fastfilereader/extconf.rb +120 -0
  43. data/ext/fastfilereader/mapper.cpp +214 -0
  44. data/ext/fastfilereader/mapper.h +59 -0
  45. data/ext/fastfilereader/rubymain.cpp +126 -0
  46. data/ext/kb.cpp +79 -0
  47. data/ext/page.cpp +107 -0
  48. data/ext/page.h +51 -0
  49. data/ext/pipe.cpp +354 -0
  50. data/ext/project.h +174 -0
  51. data/ext/rubymain.cpp +1610 -0
  52. data/ext/ssl.cpp +627 -0
  53. data/ext/ssl.h +103 -0
  54. data/ext/wait_for_single_fd.h +36 -0
  55. data/java/.classpath +8 -0
  56. data/java/.project +17 -0
  57. data/java/src/com/rubyeventmachine/EmReactor.java +625 -0
  58. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  59. data/java/src/com/rubyeventmachine/EmReactorInterface.java +70 -0
  60. data/java/src/com/rubyeventmachine/EventableChannel.java +72 -0
  61. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +201 -0
  62. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +415 -0
  63. data/java/src/com/rubyeventmachine/NullEmReactor.java +157 -0
  64. data/java/src/com/rubyeventmachine/NullEventableChannel.java +81 -0
  65. data/lib/em/buftok.rb +59 -0
  66. data/lib/em/callback.rb +58 -0
  67. data/lib/em/channel.rb +69 -0
  68. data/lib/em/completion.rb +307 -0
  69. data/lib/em/connection.rb +776 -0
  70. data/lib/em/deferrable.rb +210 -0
  71. data/lib/em/deferrable/pool.rb +2 -0
  72. data/lib/em/file_watch.rb +73 -0
  73. data/lib/em/future.rb +61 -0
  74. data/lib/em/io_streamer.rb +68 -0
  75. data/lib/em/iterator.rb +252 -0
  76. data/lib/em/messages.rb +66 -0
  77. data/lib/em/pool.rb +151 -0
  78. data/lib/em/process_watch.rb +45 -0
  79. data/lib/em/processes.rb +123 -0
  80. data/lib/em/protocols.rb +37 -0
  81. data/lib/em/protocols/header_and_content.rb +138 -0
  82. data/lib/em/protocols/httpclient.rb +303 -0
  83. data/lib/em/protocols/httpclient2.rb +602 -0
  84. data/lib/em/protocols/line_and_text.rb +125 -0
  85. data/lib/em/protocols/line_protocol.rb +33 -0
  86. data/lib/em/protocols/linetext2.rb +179 -0
  87. data/lib/em/protocols/memcache.rb +331 -0
  88. data/lib/em/protocols/object_protocol.rb +46 -0
  89. data/lib/em/protocols/postgres3.rb +246 -0
  90. data/lib/em/protocols/saslauth.rb +175 -0
  91. data/lib/em/protocols/smtpclient.rb +394 -0
  92. data/lib/em/protocols/smtpserver.rb +666 -0
  93. data/lib/em/protocols/socks4.rb +66 -0
  94. data/lib/em/protocols/stomp.rb +205 -0
  95. data/lib/em/protocols/tcptest.rb +54 -0
  96. data/lib/em/pure_ruby.rb +1299 -0
  97. data/lib/em/queue.rb +80 -0
  98. data/lib/em/resolver.rb +232 -0
  99. data/lib/em/spawnable.rb +84 -0
  100. data/lib/em/streamer.rb +118 -0
  101. data/lib/em/threaded_resource.rb +90 -0
  102. data/lib/em/tick_loop.rb +85 -0
  103. data/lib/em/timers.rb +61 -0
  104. data/lib/em/version.rb +3 -0
  105. data/lib/eventmachine.rb +1602 -0
  106. data/lib/jeventmachine.rb +318 -0
  107. data/rakelib/package.rake +120 -0
  108. data/rakelib/test.rake +6 -0
  109. data/rakelib/test_pure.rake +11 -0
  110. data/tests/client.crt +31 -0
  111. data/tests/client.key +51 -0
  112. data/tests/dhparam.pem +13 -0
  113. data/tests/em_ssl_handlers.rb +153 -0
  114. data/tests/em_test_helper.rb +198 -0
  115. data/tests/jruby/test_jeventmachine.rb +38 -0
  116. data/tests/test_attach.rb +199 -0
  117. data/tests/test_basic.rb +321 -0
  118. data/tests/test_channel.rb +75 -0
  119. data/tests/test_completion.rb +178 -0
  120. data/tests/test_connection_count.rb +83 -0
  121. data/tests/test_connection_write.rb +35 -0
  122. data/tests/test_defer.rb +35 -0
  123. data/tests/test_deferrable.rb +35 -0
  124. data/tests/test_epoll.rb +141 -0
  125. data/tests/test_error_handler.rb +38 -0
  126. data/tests/test_exc.rb +37 -0
  127. data/tests/test_file_watch.rb +86 -0
  128. data/tests/test_fork.rb +75 -0
  129. data/tests/test_futures.rb +170 -0
  130. data/tests/test_handler_check.rb +35 -0
  131. data/tests/test_hc.rb +155 -0
  132. data/tests/test_httpclient.rb +238 -0
  133. data/tests/test_httpclient2.rb +132 -0
  134. data/tests/test_idle_connection.rb +31 -0
  135. data/tests/test_inactivity_timeout.rb +102 -0
  136. data/tests/test_io_streamer.rb +47 -0
  137. data/tests/test_ipv4.rb +96 -0
  138. data/tests/test_ipv6.rb +107 -0
  139. data/tests/test_iterator.rb +122 -0
  140. data/tests/test_kb.rb +28 -0
  141. data/tests/test_keepalive.rb +113 -0
  142. data/tests/test_line_protocol.rb +33 -0
  143. data/tests/test_ltp.rb +155 -0
  144. data/tests/test_ltp2.rb +332 -0
  145. data/tests/test_many_fds.rb +21 -0
  146. data/tests/test_next_tick.rb +104 -0
  147. data/tests/test_object_protocol.rb +36 -0
  148. data/tests/test_pause.rb +109 -0
  149. data/tests/test_pending_connect_timeout.rb +52 -0
  150. data/tests/test_pool.rb +196 -0
  151. data/tests/test_process_watch.rb +50 -0
  152. data/tests/test_processes.rb +128 -0
  153. data/tests/test_proxy_connection.rb +180 -0
  154. data/tests/test_pure.rb +156 -0
  155. data/tests/test_queue.rb +64 -0
  156. data/tests/test_resolver.rb +129 -0
  157. data/tests/test_running.rb +14 -0
  158. data/tests/test_sasl.rb +46 -0
  159. data/tests/test_send_file.rb +217 -0
  160. data/tests/test_servers.rb +32 -0
  161. data/tests/test_shutdown_hooks.rb +23 -0
  162. data/tests/test_smtpclient.rb +75 -0
  163. data/tests/test_smtpserver.rb +90 -0
  164. data/tests/test_sock_opt.rb +53 -0
  165. data/tests/test_spawn.rb +290 -0
  166. data/tests/test_ssl_args.rb +41 -0
  167. data/tests/test_ssl_dhparam.rb +57 -0
  168. data/tests/test_ssl_ecdh_curve.rb +57 -0
  169. data/tests/test_ssl_extensions.rb +24 -0
  170. data/tests/test_ssl_methods.rb +31 -0
  171. data/tests/test_ssl_protocols.rb +190 -0
  172. data/tests/test_ssl_verify.rb +52 -0
  173. data/tests/test_stomp.rb +38 -0
  174. data/tests/test_system.rb +46 -0
  175. data/tests/test_threaded_resource.rb +68 -0
  176. data/tests/test_tick_loop.rb +58 -0
  177. data/tests/test_timers.rb +150 -0
  178. data/tests/test_ud.rb +8 -0
  179. data/tests/test_unbind_reason.rb +40 -0
  180. metadata +384 -0
@@ -0,0 +1,32 @@
1
+ require_relative 'em_test_helper'
2
+
3
+ class TestServers < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @port = next_port
7
+ end
8
+
9
+ def server_alive?
10
+ port_in_use?(@port)
11
+ end
12
+
13
+ def run_test_stop_server
14
+ EM.run {
15
+ sig = EM.start_server("127.0.0.1", @port)
16
+ assert server_alive?, "Server didn't start"
17
+ EM.stop_server sig
18
+ # Give the server some time to shutdown.
19
+ EM.add_timer(0.1) {
20
+ assert !server_alive?, "Server didn't stop"
21
+ EM.stop
22
+ }
23
+ }
24
+ end
25
+
26
+ def test_stop_server
27
+ assert !server_alive?, "Port already in use"
28
+ 2.times { run_test_stop_server }
29
+ assert !server_alive?, "Servers didn't stop"
30
+ end
31
+
32
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'em_test_helper'
2
+
3
+ class TestShutdownHooks < Test::Unit::TestCase
4
+ def test_shutdown_hooks
5
+ r = false
6
+ EM.run {
7
+ EM.add_shutdown_hook { r = true }
8
+ EM.stop
9
+ }
10
+ assert_equal( true, r )
11
+ end
12
+
13
+ def test_hook_order
14
+ r = []
15
+ EM.run {
16
+ EM.add_shutdown_hook { r << 2 }
17
+ EM.add_shutdown_hook { r << 1 }
18
+ EM.stop
19
+ }
20
+ assert_equal( [1, 2], r )
21
+ end
22
+ end
23
+
@@ -0,0 +1,75 @@
1
+ require_relative 'em_test_helper'
2
+
3
+ class TestSmtpClient < Test::Unit::TestCase
4
+
5
+ Localhost = "127.0.0.1"
6
+ Localport = 9801
7
+
8
+ def setup
9
+ end
10
+
11
+ def teardown
12
+ end
13
+
14
+ def test_a
15
+ # No real tests until we have a server implementation to test against.
16
+ # This is what the call looks like, though:
17
+ err = nil
18
+ EM.run {
19
+ d = EM::Protocols::SmtpClient.send :domain=>"example.com",
20
+ :host=>Localhost,
21
+ :port=>Localport, # optional, defaults 25
22
+ :starttls=>true,
23
+ :from=>"sender@example.com",
24
+ :to=> ["to_1@example.com", "to_2@example.com"],
25
+ :header=> {"Subject" => "This is a subject line"},
26
+ :body=> "This is the body of the email",
27
+ :verbose=>true
28
+ d.errback {|e|
29
+ err = e
30
+ EM.stop
31
+ }
32
+ }
33
+ assert(err)
34
+ end
35
+
36
+ def test_content
37
+ err = nil
38
+ EM.run {
39
+ d = EM::Protocols::SmtpClient.send :domain=>"example.com",
40
+ :host=>Localhost,
41
+ :port=>Localport, # optional, defaults 25
42
+ :starttls=>true,
43
+ :from=>"sender@example.com",
44
+ :to=> ["to_1@example.com", "to_2@example.com"],
45
+ :content => ["Subject: xxx\r\n\r\ndata\r\n.\r\n"],
46
+ :verbose=>true
47
+ d.errback {|e|
48
+ err = e
49
+ EM.stop
50
+ }
51
+ }
52
+ assert(err)
53
+ end
54
+
55
+
56
+ EM::Protocols::SmtpClient.__send__(:public, :escape_leading_dots)
57
+
58
+ def test_escaping
59
+ smtp = EM::Protocols::SmtpClient.new :domain => "example.com"
60
+
61
+ expectations = {
62
+ "Hello\r\n" => "Hello\r\n",
63
+ "\r\n.whatever\r\n" => "\r\n..whatever\r\n",
64
+ "\r\n.\r\n" => "\r\n..\r\n",
65
+ "\r\n.\r\n." => "\r\n..\r\n..",
66
+ ".\r\n.\r\n" => "..\r\n..\r\n",
67
+ "..\r\n" => "...\r\n"
68
+ }
69
+
70
+ expectations.each do |input, output|
71
+ assert_equal output, smtp.escape_leading_dots(input)
72
+ end
73
+ end
74
+
75
+ end
@@ -0,0 +1,90 @@
1
+ require_relative 'em_test_helper'
2
+ require 'net/smtp'
3
+
4
+ class TestSmtpServer < Test::Unit::TestCase
5
+
6
+ # Don't test on port 25. It requires superuser and there's probably
7
+ # a mail server already running there anyway.
8
+ Localhost = "127.0.0.1"
9
+ Localport = 25001
10
+
11
+ # This class is an example of what you need to write in order
12
+ # to implement a mail server. You override the methods you are
13
+ # interested in. Some, but not all, of these are illustrated here.
14
+ #
15
+ class Mailserver < EM::Protocols::SmtpServer
16
+
17
+ attr_reader :my_msg_body, :my_sender, :my_recipients, :messages_count
18
+
19
+ def initialize *args
20
+ super
21
+ end
22
+
23
+ def receive_sender sender
24
+ @my_sender = sender
25
+ #p sender
26
+ true
27
+ end
28
+
29
+ def receive_recipient rcpt
30
+ @my_recipients ||= []
31
+ @my_recipients << rcpt
32
+ true
33
+ end
34
+
35
+ def receive_data_chunk c
36
+ @my_msg_body = c.last
37
+ end
38
+
39
+ def receive_message
40
+ @messages_count ||= 0
41
+ @messages_count += 1
42
+ true
43
+ end
44
+
45
+ def connection_ended
46
+ EM.stop
47
+ end
48
+ end
49
+
50
+ def run_server
51
+ c = nil
52
+ EM.run {
53
+ EM.start_server( Localhost, Localport, Mailserver ) {|conn| c = conn}
54
+ EM::Timer.new(2) {EM.stop} # prevent hanging the test suite in case of error
55
+ yield if block_given?
56
+ }
57
+ c
58
+ end
59
+
60
+ def test_mail
61
+ c = run_server do
62
+ EM::Protocols::SmtpClient.send :host=>Localhost,
63
+ :port=>Localport,
64
+ :domain=>"bogus",
65
+ :from=>"me@example.com",
66
+ :to=>"you@example.com",
67
+ :header=> {"Subject"=>"Email subject line", "Reply-to"=>"me@example.com"},
68
+ :body=>"Not much of interest here."
69
+ end
70
+ assert_equal( "Not much of interest here.", c.my_msg_body )
71
+ assert_equal( "<me@example.com>", c.my_sender )
72
+ assert_equal( ["<you@example.com>"], c.my_recipients )
73
+ end
74
+
75
+
76
+
77
+ def test_multiple_messages_per_connection
78
+ c = run_server do
79
+ Thread.new do
80
+ Net::SMTP.start( Localhost, Localport, Localhost ) do |smtp|
81
+ 2.times do
82
+ smtp.send_message "This is a test e-mail message.", 'me@fromdomain.com', 'test@todomain.com'
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ assert_equal( 2, c.messages_count )
89
+ end
90
+ end
@@ -0,0 +1,53 @@
1
+ require_relative 'em_test_helper'
2
+
3
+ class TestSockOpt < Test::Unit::TestCase
4
+ def setup
5
+ assert(!EM.reactor_running?)
6
+ @port = next_port
7
+ end
8
+
9
+ def teardown
10
+ assert(!EM.reactor_running?)
11
+ end
12
+
13
+ def test_set_sock_opt
14
+ omit_if(windows?)
15
+ omit_if(!EM.respond_to?(:set_sock_opt))
16
+
17
+ val = nil
18
+ test_module = Module.new do
19
+ define_method :post_init do
20
+ val = set_sock_opt Socket::SOL_SOCKET, Socket::SO_BROADCAST, true
21
+ EM.stop
22
+ end
23
+ end
24
+
25
+ EM.run do
26
+ EM.start_server '127.0.0.1', @port
27
+ EM.connect '127.0.0.1', @port, test_module
28
+ end
29
+
30
+ assert_equal 0, val
31
+ end
32
+
33
+ def test_get_sock_opt
34
+ omit_if(windows?)
35
+ omit_if(!EM.respond_to?(:set_sock_opt))
36
+
37
+ val = nil
38
+ test_module = Module.new do
39
+ define_method :connection_completed do
40
+ val = get_sock_opt Socket::SOL_SOCKET, Socket::SO_ERROR
41
+ EM.stop
42
+ end
43
+ end
44
+
45
+ EM.run do
46
+ EM.start_server '127.0.0.1', @port
47
+ EM.connect '127.0.0.1', @port, test_module
48
+ end
49
+
50
+ assert_equal "\0\0\0\0", val
51
+ end
52
+
53
+ end
@@ -0,0 +1,290 @@
1
+ require_relative 'em_test_helper'
2
+
3
+ class TestSpawn < Test::Unit::TestCase
4
+
5
+ # Spawn a process that simply stops the reactor.
6
+ # Assert that the notification runs after the block that calls it.
7
+ #
8
+ def test_stop
9
+ x = nil
10
+ EM.run {
11
+ s = EM.spawn {EM.stop}
12
+ s.notify
13
+ x = true
14
+ }
15
+ assert x
16
+ end
17
+
18
+
19
+ # Pass a parameter to a spawned process.
20
+ #
21
+ def test_parms
22
+ val = 5
23
+ EM.run {
24
+ s = EM.spawn {|v| val *= v; EM.stop}
25
+ s.notify 3
26
+ }
27
+ assert_equal( 15, val )
28
+ end
29
+
30
+ # Pass multiple parameters to a spawned process.
31
+ #
32
+ def test_multiparms
33
+ val = 5
34
+ EM.run {
35
+ s = EM.spawn {|v1,v2| val *= (v1 + v2); EM.stop}
36
+ s.notify 3,4
37
+ }
38
+ assert_equal( 35, val )
39
+ end
40
+
41
+
42
+ # This test demonstrates that a notification does not happen immediately,
43
+ # but rather is scheduled sometime after the current code path completes.
44
+ #
45
+ def test_race
46
+ x = 0
47
+ EM.run {
48
+ s = EM.spawn {x *= 2; EM.stop}
49
+ s.notify
50
+ x = 2
51
+ }
52
+ assert_equal( 4, x)
53
+ end
54
+
55
+
56
+ # Spawn a process and notify it 25 times to run fibonacci
57
+ # on a pair of global variables.
58
+ #
59
+ def test_fibonacci
60
+ x = 1
61
+ y = 1
62
+ EM.run {
63
+ s = EM.spawn {x,y = y,x+y}
64
+ 25.times {s.notify}
65
+
66
+ t = EM.spawn {EM.stop}
67
+ t.notify
68
+ }
69
+ assert_equal( 121393, x)
70
+ assert_equal( 196418, y)
71
+ end
72
+
73
+ # This one spawns 25 distinct processes, and notifies each one once,
74
+ # rather than notifying a single process 25 times.
75
+ #
76
+ def test_another_fibonacci
77
+ x = 1
78
+ y = 1
79
+ EM.run {
80
+ 25.times {
81
+ s = EM.spawn {x,y = y,x+y}
82
+ s.notify
83
+ }
84
+
85
+ t = EM.spawn {EM.stop}
86
+ t.notify
87
+ }
88
+ assert_equal( 121393, x)
89
+ assert_equal( 196418, y)
90
+ end
91
+
92
+
93
+ # Make a chain of processes that notify each other in turn
94
+ # with intermediate fibonacci results. The final process in
95
+ # the chain stops the loop and returns the result.
96
+ #
97
+ def test_fibonacci_chain
98
+ a,b = nil
99
+
100
+ EM.run {
101
+ nextpid = EM.spawn {|x,y|
102
+ a,b = x,y
103
+ EM.stop
104
+ }
105
+
106
+ 25.times {
107
+ n = nextpid
108
+ nextpid = EM.spawn {|x,y| n.notify( y, x+y )}
109
+ }
110
+
111
+ nextpid.notify( 1, 1 )
112
+ }
113
+
114
+ assert_equal( 121393, a)
115
+ assert_equal( 196418, b)
116
+ end
117
+
118
+
119
+ # EM#yield gives a spawed process to yield control to other processes
120
+ # (in other words, to stop running), and to specify a different code block
121
+ # that will run on its next notification.
122
+ #
123
+ def test_yield
124
+ a = 0
125
+ EM.run {
126
+ n = EM.spawn {
127
+ a += 10
128
+ EM.yield {
129
+ a += 20
130
+ EM.yield {
131
+ a += 30
132
+ EM.stop
133
+ }
134
+ }
135
+ }
136
+ n.notify
137
+ n.notify
138
+ n.notify
139
+ }
140
+ assert_equal( 60, a )
141
+ end
142
+
143
+ # EM#yield_and_notify behaves like EM#yield, except that it also notifies the
144
+ # yielding process. This may sound trivial, since the yield block will run very
145
+ # shortly after with no action by the program, but this actually can be very useful,
146
+ # because it causes the reactor core to execute once before the yielding process
147
+ # gets control back. So it can be used to allow heavily-used network connections
148
+ # to clear buffers, or allow other processes to process their notifications.
149
+ #
150
+ # Notice in this test code that only a simple notify is needed at the bottom
151
+ # of the initial block. Even so, all of the yielded blocks will execute.
152
+ #
153
+ def test_yield_and_notify
154
+ a = 0
155
+ EM.run {
156
+ n = EM.spawn {
157
+ a += 10
158
+ EM.yield_and_notify {
159
+ a += 20
160
+ EM.yield_and_notify {
161
+ a += 30
162
+ EM.stop
163
+ }
164
+ }
165
+ }
166
+ n.notify
167
+ }
168
+ assert_equal( 60, a )
169
+ end
170
+
171
+ # resume is an alias for notify.
172
+ #
173
+ def test_resume
174
+ EM.run {
175
+ n = EM.spawn {EM.stop}
176
+ n.resume
177
+ }
178
+ assert true
179
+ end
180
+
181
+ # run is an idiomatic alias for notify.
182
+ #
183
+ def test_run
184
+ EM.run {
185
+ (EM.spawn {EM.stop}).run
186
+ }
187
+ assert true
188
+ end
189
+
190
+
191
+ # Clones the ping-pong example from the Erlang tutorial, in much less code.
192
+ # Illustrates that a spawned block executes in the context of a SpawnableObject.
193
+ # (Meaning, we can pass self as a parameter to another process that can then
194
+ # notify us.)
195
+ #
196
+ def test_ping_pong
197
+ n_pongs = 0
198
+ EM.run {
199
+ pong = EM.spawn {|x, ping|
200
+ n_pongs += 1
201
+ ping.notify( x-1 )
202
+ }
203
+ ping = EM.spawn {|x|
204
+ if x > 0
205
+ pong.notify x, self
206
+ else
207
+ EM.stop
208
+ end
209
+ }
210
+ ping.notify 3
211
+ }
212
+ assert_equal( 3, n_pongs )
213
+ end
214
+
215
+ # Illustrates that you can call notify inside a notification, and it will cause
216
+ # the currently-executing process to be re-notified. Of course, the new notification
217
+ # won't run until sometime after the current one completes.
218
+ #
219
+ def test_self_notify
220
+ n = 0
221
+ EM.run {
222
+ pid = EM.spawn {|x|
223
+ if x > 0
224
+ n += x
225
+ notify( x-1 )
226
+ else
227
+ EM.stop
228
+ end
229
+ }
230
+ pid.notify 3
231
+ }
232
+ assert_equal( 6, n )
233
+ end
234
+
235
+
236
+ # Illustrates that the block passed to #spawn executes in the context of a
237
+ # SpawnedProcess object, NOT in the local context. This can often be deceptive.
238
+ #
239
+ class BlockScopeTest
240
+ attr_reader :var
241
+ def run
242
+ # The following line correctly raises a NameError.
243
+ # The problem is that the programmer expected the spawned block to
244
+ # execute in the local context, but it doesn't.
245
+ #
246
+ # (EM.spawn { do_something }).notify ### NO! BAD!
247
+
248
+
249
+
250
+ # The following line correctly passes self as a parameter to the
251
+ # notified process.
252
+ #
253
+ (EM.spawn {|obj| obj.do_something }).notify(self)
254
+
255
+
256
+
257
+ # Here's another way to do it. This works because "myself" is bound
258
+ # in the local scope, unlike "self," so the spawned block sees it.
259
+ #
260
+ myself = self
261
+ (EM.spawn { myself.do_something }).notify
262
+
263
+
264
+
265
+ # And we end the loop.
266
+ # This is a tangential point, but observe that #notify never blocks.
267
+ # It merely appends a message to the internal queue of a spawned process
268
+ # and returns. As it turns out, the reactor processes notifications for ALL
269
+ # spawned processes in the order that #notify is called. So there is a
270
+ # reasonable expectation that the process which stops the reactor will
271
+ # execute after the previous ones in this method. HOWEVER, this is NOT
272
+ # a documented behavior and is subject to change.
273
+ #
274
+ (EM.spawn {EM.stop}).notify
275
+ end
276
+ def do_something
277
+ @var ||= 0
278
+ @var += 100
279
+ end
280
+ end
281
+
282
+ def test_block_scope
283
+ bs = BlockScopeTest.new
284
+ EM.run {
285
+ bs.run
286
+ }
287
+ assert_equal( 200, bs.var )
288
+ end
289
+
290
+ end