eventmachine 0.12.10-java → 1.0.0.beta.1-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +1 -0
- data/README +1 -2
- data/Rakefile +4 -76
- data/docs/DEFERRABLES +183 -70
- data/docs/KEYBOARD +15 -11
- data/docs/LIGHTWEIGHT_CONCURRENCY +84 -24
- data/docs/SMTP +3 -1
- data/docs/SPAWNED_PROCESSES +84 -25
- data/eventmachine.gemspec +19 -26
- data/examples/ex_tick_loop_array.rb +15 -0
- data/examples/ex_tick_loop_counter.rb +32 -0
- data/ext/binder.cpp +0 -1
- data/ext/cmain.cpp +36 -11
- data/ext/cplusplus.cpp +1 -1
- data/ext/ed.cpp +104 -113
- data/ext/ed.h +24 -30
- data/ext/em.cpp +347 -248
- data/ext/em.h +23 -16
- data/ext/eventmachine.h +5 -3
- data/ext/extconf.rb +5 -3
- data/ext/fastfilereader/extconf.rb +5 -3
- data/ext/fastfilereader/mapper.cpp +1 -1
- data/ext/kb.cpp +1 -3
- data/ext/pipe.cpp +9 -11
- data/ext/project.h +12 -4
- data/ext/rubymain.cpp +138 -89
- data/java/src/com/rubyeventmachine/EmReactor.java +1 -0
- data/lib/em/channel.rb +1 -1
- data/lib/em/connection.rb +6 -1
- data/lib/em/deferrable.rb +16 -2
- data/lib/em/iterator.rb +270 -0
- data/lib/em/protocols.rb +1 -1
- data/lib/em/protocols/httpclient.rb +5 -0
- data/lib/em/protocols/line_protocol.rb +28 -0
- data/lib/em/protocols/smtpserver.rb +101 -8
- data/lib/em/protocols/stomp.rb +1 -1
- data/lib/{pr_eventmachine.rb → em/pure_ruby.rb} +1 -11
- data/lib/em/queue.rb +1 -0
- data/lib/em/streamer.rb +1 -1
- data/lib/em/tick_loop.rb +85 -0
- data/lib/em/timers.rb +2 -1
- data/lib/em/version.rb +1 -1
- data/lib/eventmachine.rb +38 -84
- data/lib/jeventmachine.rb +1 -0
- data/tests/test_attach.rb +13 -3
- data/tests/test_basic.rb +60 -95
- data/tests/test_channel.rb +3 -2
- data/tests/test_defer.rb +14 -12
- data/tests/test_deferrable.rb +35 -0
- data/tests/test_file_watch.rb +1 -1
- data/tests/test_futures.rb +1 -1
- data/tests/test_hc.rb +40 -68
- data/tests/test_httpclient.rb +15 -6
- data/tests/test_httpclient2.rb +3 -2
- data/tests/test_inactivity_timeout.rb +3 -3
- data/tests/test_ltp.rb +13 -5
- data/tests/test_next_tick.rb +1 -1
- data/tests/test_pending_connect_timeout.rb +2 -2
- data/tests/test_process_watch.rb +36 -34
- data/tests/test_proxy_connection.rb +52 -0
- data/tests/test_pure.rb +10 -1
- data/tests/test_sasl.rb +1 -1
- data/tests/test_send_file.rb +16 -7
- data/tests/test_servers.rb +1 -1
- data/tests/test_tick_loop.rb +59 -0
- data/tests/test_timers.rb +13 -15
- metadata +45 -17
- data/web/whatis +0 -7
data/.gitignore
CHANGED
data/Gemfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
gemspec
|
data/README
CHANGED
@@ -3,9 +3,8 @@
|
|
3
3
|
Homepage:: http://rubyeventmachine.com
|
4
4
|
Rubyforge Page:: http://rubyforge.org/projects/eventmachine
|
5
5
|
Google Group:: http://groups.google.com/group/eventmachine
|
6
|
-
Mailing List:: http://rubyforge.org/pipermail/eventmachine-talk
|
7
6
|
RDoc:: http://eventmachine.rubyforge.org
|
8
|
-
IRC::
|
7
|
+
IRC:: #eventmachine on irc.freenode.net
|
9
8
|
Copyright:: (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
10
9
|
Email:: gmail address: garbagecat10
|
11
10
|
|
data/Rakefile
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
|
-
|
2
|
+
#
|
3
3
|
# Ruby/EventMachine
|
4
4
|
# http://rubyeventmachine.com
|
5
5
|
# Copyright (C) 2006-07 by Francis Cianfrocca
|
@@ -9,23 +9,6 @@
|
|
9
9
|
# COPYING in the EventMachine distribution for full licensing
|
10
10
|
# information.
|
11
11
|
#
|
12
|
-
# $Id$
|
13
|
-
#++
|
14
|
-
|
15
|
-
### OLD RAKE: ###
|
16
|
-
# # The tasks and external gemspecs we used to generate binary gems are now
|
17
|
-
# # obsolete. Use Patrick Hurley's gembuilder to build binary gems for any
|
18
|
-
# # desired platform.
|
19
|
-
# # To build a binary gem on Win32, ensure that the include and lib paths
|
20
|
-
# # both contain the proper references to OPENSSL. Use the static version
|
21
|
-
# # of the libraries, not the dynamic, otherwise we expose the user to a
|
22
|
-
# # runtime dependency.
|
23
|
-
#
|
24
|
-
# # To build a binary gem for win32, first build rubyeventmachine.so
|
25
|
-
# # using VC6 outside of the build tree (the normal way: ruby extconf.rb,
|
26
|
-
# # and then nmake). Then copy rubyeventmachine.so into the lib directory,
|
27
|
-
# # and run rake gemwin32.
|
28
|
-
#
|
29
12
|
|
30
13
|
require 'rubygems' unless defined?(Gem)
|
31
14
|
require 'rake' unless defined?(Rake)
|
@@ -33,10 +16,6 @@ require 'rake' unless defined?(Rake)
|
|
33
16
|
Package = false # Build zips and tarballs?
|
34
17
|
Dir.glob('tasks/*.rake').each { |r| Rake.application.add_import r }
|
35
18
|
|
36
|
-
# e.g. rake EVENTMACHINE_LIBRARY=java for forcing java build tasks as defaults!
|
37
|
-
$eventmachine_library = :java if RUBY_PLATFORM =~ /java/ || ENV['EVENTMACHINE_LIBRARY'] == 'java'
|
38
|
-
$eventmachine_library = :pure_ruby if ENV['EVENTMACHINE_LIBRARY'] == 'pure_ruby'
|
39
|
-
|
40
19
|
MAKE = ENV['MAKE'] || if RUBY_PLATFORM =~ /mswin/ # mingw uses make.
|
41
20
|
'nmake'
|
42
21
|
else
|
@@ -48,8 +27,7 @@ task :default => [:build, :test]
|
|
48
27
|
|
49
28
|
desc "Build extension (or EVENTMACHINE_LIBRARY) and place in lib"
|
50
29
|
build_task = 'ext:build'
|
51
|
-
build_task = 'java:build' if
|
52
|
-
build_task = :dummy_build if $eventmachine_library == :pure_ruby
|
30
|
+
build_task = 'java:build' if RUBY_PLATFORM =~ /java/
|
53
31
|
task :build => build_task do |t|
|
54
32
|
Dir.glob('{ext,java/src,ext/fastfilereader}/*.{so,bundle,dll,jar}').each do |f|
|
55
33
|
mv f, "lib"
|
@@ -77,52 +55,7 @@ task :clean do
|
|
77
55
|
Dir.glob('ext/**/conftest.dSYM').each{ |file| rm_rf file }
|
78
56
|
end
|
79
57
|
|
80
|
-
Spec =
|
81
|
-
s.name = "eventmachine"
|
82
|
-
s.summary = "Ruby/EventMachine library"
|
83
|
-
s.platform = Gem::Platform::RUBY
|
84
|
-
|
85
|
-
s.has_rdoc = true
|
86
|
-
s.rdoc_options = %w(--title EventMachine --main README --line-numbers -x lib/em/version -x lib/emva -x lib/evma/ -x lib/pr_eventmachine -x lib/jeventmachine)
|
87
|
-
s.extra_rdoc_files = Dir['README,docs/*']
|
88
|
-
|
89
|
-
s.files = `git ls-files`.split("\n")
|
90
|
-
|
91
|
-
s.require_path = 'lib'
|
92
|
-
|
93
|
-
# TODO / XXX - should we enable this? rubygems fails the install if anything
|
94
|
-
# is broken. What we could do is CI submission, though, and always terminate
|
95
|
-
# with a positive code...
|
96
|
-
# s.test_file = "tests/testem.rb"
|
97
|
-
|
98
|
-
# XXX Using rake to compile extensions breaks when you have multiple ruby installations
|
99
|
-
# and your path isn't set. We can switch back to this once the Gem.exec patch is merged.
|
100
|
-
# s.extensions = "Rakefile"
|
101
|
-
s.extensions = ["ext/extconf.rb", "ext/fastfilereader/extconf.rb"]
|
102
|
-
|
103
|
-
s.author = "Francis Cianfrocca"
|
104
|
-
s.email = "garbagecat10@gmail.com"
|
105
|
-
s.rubyforge_project = 'eventmachine'
|
106
|
-
s.homepage = "http://rubyeventmachine.com"
|
107
|
-
|
108
|
-
# Pulled in from readme, as code to pull from readme was not working!
|
109
|
-
# Might be worth removing as no one seems to use gem info anyway.
|
110
|
-
s.description = <<-EOD
|
111
|
-
EventMachine implements a fast, single-threaded engine for arbitrary network
|
112
|
-
communications. It's extremely easy to use in Ruby. EventMachine wraps all
|
113
|
-
interactions with IP sockets, allowing programs to concentrate on the
|
114
|
-
implementation of network protocols. It can be used to create both network
|
115
|
-
servers and clients. To create a server or client, a Ruby program only needs
|
116
|
-
to specify the IP address and port, and provide a Module that implements the
|
117
|
-
communications protocol. Implementations of several standard network protocols
|
118
|
-
are provided with the package, primarily to serve as examples. The real goal
|
119
|
-
of EventMachine is to enable programs to easily interface with other programs
|
120
|
-
using TCP/IP, especially if custom protocols are required.
|
121
|
-
EOD
|
122
|
-
|
123
|
-
require 'lib/em/version'
|
124
|
-
s.version = EventMachine::VERSION
|
125
|
-
end
|
58
|
+
Spec = eval(File.read(File.expand_path('../eventmachine.gemspec', __FILE__)))
|
126
59
|
|
127
60
|
if RUBY_PLATFORM =~ /mswin/
|
128
61
|
Spec.platform = 'x86-mswin32-60'
|
@@ -305,7 +238,7 @@ rescue LoadError
|
|
305
238
|
require 'rake/rdoctask'
|
306
239
|
Rake::RDocTask
|
307
240
|
end
|
308
|
-
df = begin; require 'rdoc/generator/darkfish'; true; rescue LoadError; end
|
241
|
+
df = begin; require 'rdoc/rdoc'; require 'rdoc/generator/darkfish'; true; rescue LoadError; end
|
309
242
|
rdtask = rdoc_task_type.new do |rd|
|
310
243
|
rd.title = Spec.name
|
311
244
|
rd.rdoc_dir = 'rdoc'
|
@@ -363,11 +296,6 @@ namespace :gem do
|
|
363
296
|
task :uninstall do
|
364
297
|
gem_cmd(:uninstall, "#{Spec.name}", "-v=#{Spec.version}")
|
365
298
|
end
|
366
|
-
|
367
|
-
desc "Generate new gemspec"
|
368
|
-
task :spec => :clobber do
|
369
|
-
open("eventmachine.gemspec", 'w') { |f| f.write Spec.to_ruby }
|
370
|
-
end
|
371
299
|
end
|
372
300
|
|
373
301
|
task :clobber => :clean
|
data/docs/DEFERRABLES
CHANGED
@@ -1,115 +1,199 @@
|
|
1
|
-
EventMachine (EM) adds two different formalisms for lightweight concurrency
|
1
|
+
EventMachine (EM) adds two different formalisms for lightweight concurrency
|
2
|
+
to the Ruby programmer's toolbox: spawned processes and deferrables. This
|
3
|
+
note will show you how to use deferrables. For more information, see the
|
4
|
+
separate document LIGHTWEIGHT_CONCURRENCY.
|
2
5
|
|
3
6
|
=== What are Deferrables?
|
4
7
|
|
5
|
-
EventMachine's Deferrable borrows heavily from the "deferred" object in
|
8
|
+
EventMachine's Deferrable borrows heavily from the "deferred" object in
|
9
|
+
Python's "Twisted" event-handling framework. Here's a minimal example that
|
10
|
+
illustrates Deferrable:
|
6
11
|
|
7
12
|
require 'eventmachine'
|
8
|
-
|
13
|
+
|
9
14
|
class MyClass
|
10
15
|
include EM::Deferrable
|
11
|
-
|
16
|
+
|
12
17
|
def print_value x
|
13
18
|
puts "MyClass instance received #{x}"
|
14
19
|
end
|
15
20
|
end
|
16
|
-
|
21
|
+
|
17
22
|
EM.run {
|
18
23
|
df = MyClass.new
|
19
24
|
df.callback {|x|
|
20
25
|
df.print_value(x)
|
21
26
|
EM.stop
|
22
27
|
}
|
23
|
-
|
28
|
+
|
24
29
|
EM::Timer.new(2) {
|
25
30
|
df.set_deferred_status :succeeded, 100
|
26
31
|
}
|
27
32
|
}
|
28
|
-
|
29
|
-
|
30
|
-
This program will spin for two seconds, print out the string "MyClass instance received 100" and then exit. The Deferrable pattern relies on an unusual metaphor that may be unfamiliar to you, unless you've used Python's Twisted. You may need to read the following material through more than once before you get the idea.
|
31
|
-
|
32
|
-
EventMachine::Deferrable is simply a Ruby Module that you can include in your own classes. (There also is a class named EventMachine::DefaultDeferrable for when you want to create one without including it in code of your own.)
|
33
|
-
|
34
|
-
An object that includes EventMachine::Deferrable is like any other Ruby object: it can be created whenever you want, returned from your functions, or passed as an argument to other functions.
|
35
|
-
|
36
|
-
The Deferrable pattern allows you to specify any number of Ruby code blocks (callbacks or errbacks) that will be executed at some future time when the status of the Deferrable object changes.
|
37
|
-
|
38
|
-
How might that be useful? Well, imagine that you're implementing an HTTP server, but you need to make a call to some other server in order to fulfill a client request.
|
39
|
-
|
40
|
-
When you receive a request from one of your clients, you can create and return a Deferrable object. Some other section of your program can add a callback to the Deferrable that will cause the client's request to be fulfilled. Simultaneously, you initiate an event-driven or threaded client request to some different server. And then your EM program will continue to process other events and service other client requests.
|
41
|
-
|
42
|
-
When your client request to the other server completes some time later, you will call the #set_deferred_status method on the Deferrable object, passing either a success or failure status, and an arbitrary number of parameters (which might include the data you received from the other server).
|
43
|
-
|
44
|
-
At that point, the status of the Deferrable object becomes known, and its callback or errback methods are immediately executed. Callbacks and errbacks are code blocks that are attached to Deferrable objects at any time through the methods #callback and #errback.
|
45
|
-
|
46
|
-
The deep beauty of this pattern is that it decouples the disposition of one operation (such as a client request to an outboard server) from the subsequent operations that depend on that disposition (which may include responding to a different client or any other operation).
|
47
|
-
|
48
|
-
The code which invokes the deferred operation (that will eventually result in a success or failure status together with associated data) is completely separate from the code which depends on that status and data. This achieves one of the primary goals for which threading is typically used in sophisticated applications, with none of the nondeterminacy or debugging difficulties of threads.
|
49
|
-
|
50
|
-
As soon as the deferred status of a Deferrable becomes known by way of a call to #set_deferred_status, the Deferrable will IMMEDIATELY execute all of its callbacks or errbacks in the order in which they were added to the Deferrable.
|
51
|
-
|
52
|
-
Callbacks and errbacks can be added to a Deferrable object at any time, not just when the object is created. They can even be added after the status of the object has been determined! (In this case, they will be executed immediately when they are added.)
|
53
|
-
|
54
|
-
A call to Deferrable#set_deferred_status takes :succeeded or :failed as its first argument. (This determines whether the object will call its callbacks or its errbacks.) #set_deferred_status also takes zero or more additional parameters, that will in turn be passed as parameters to the callbacks or errbacks.
|
55
33
|
|
56
|
-
In general, you can only call #set_deferred_status ONCE on a Deferrable object. A call to #set_deferred_status will not return until all of the associated callbacks or errbacks have been called. If you add callbacks or errbacks AFTER making a call to #set_deferred_status, those additional callbacks or errbacks will execute IMMEDIATELY. Any given callback or errback will be executed AT MOST once.
|
57
34
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
35
|
+
This program will spin for two seconds, print out the string "MyClass
|
36
|
+
instance received 100" and then exit. The Deferrable pattern relies on
|
37
|
+
an unusual metaphor that may be unfamiliar to you, unless you've used
|
38
|
+
Python's Twisted. You may need to read the following material through
|
39
|
+
more than once before you get the idea.
|
40
|
+
|
41
|
+
EventMachine::Deferrable is simply a Ruby Module that you can include
|
42
|
+
in your own classes. (There also is a class named
|
43
|
+
EventMachine::DefaultDeferrable for when you want to create one without
|
44
|
+
including it in code of your own.)
|
45
|
+
|
46
|
+
An object that includes EventMachine::Deferrable is like any other Ruby
|
47
|
+
object: it can be created whenever you want, returned from your functions,
|
48
|
+
or passed as an argument to other functions.
|
49
|
+
|
50
|
+
The Deferrable pattern allows you to specify any number of Ruby code
|
51
|
+
blocks (callbacks or errbacks) that will be executed at some future time
|
52
|
+
when the status of the Deferrable object changes.
|
53
|
+
|
54
|
+
How might that be useful? Well, imagine that you're implementing an HTTP
|
55
|
+
server, but you need to make a call to some other server in order to fulfill
|
56
|
+
a client request.
|
57
|
+
|
58
|
+
When you receive a request from one of your clients, you can create and
|
59
|
+
return a Deferrable object. Some other section of your program can add a
|
60
|
+
callback to the Deferrable that will cause the client's request to be
|
61
|
+
fulfilled. Simultaneously, you initiate an event-driven or threaded client
|
62
|
+
request to some different server. And then your EM program will continue to
|
63
|
+
process other events and service other client requests.
|
64
|
+
|
65
|
+
When your client request to the other server completes some time later, you
|
66
|
+
will call the #set_deferred_status method on the Deferrable object, passing
|
67
|
+
either a success or failure status, and an arbitrary number of parameters
|
68
|
+
(which might include the data you received from the other server).
|
69
|
+
|
70
|
+
At that point, the status of the Deferrable object becomes known, and its
|
71
|
+
callback or errback methods are immediately executed. Callbacks and errbacks
|
72
|
+
are code blocks that are attached to Deferrable objects at any time through
|
73
|
+
the methods #callback and #errback.
|
74
|
+
|
75
|
+
The deep beauty of this pattern is that it decouples the disposition of one
|
76
|
+
operation (such as a client request to an outboard server) from the
|
77
|
+
subsequent operations that depend on that disposition (which may include
|
78
|
+
responding to a different client or any other operation).
|
79
|
+
|
80
|
+
The code which invokes the deferred operation (that will eventually result
|
81
|
+
in a success or failure status together with associated data) is completely
|
82
|
+
separate from the code which depends on that status and data. This achieves
|
83
|
+
one of the primary goals for which threading is typically used in
|
84
|
+
sophisticated applications, with none of the nondeterminacy or debugging
|
85
|
+
difficulties of threads.
|
86
|
+
|
87
|
+
As soon as the deferred status of a Deferrable becomes known by way of a call
|
88
|
+
to #set_deferred_status, the Deferrable will IMMEDIATELY execute all of its
|
89
|
+
callbacks or errbacks in the order in which they were added to the Deferrable.
|
90
|
+
|
91
|
+
Callbacks and errbacks can be added to a Deferrable object at any time, not
|
92
|
+
just when the object is created. They can even be added after the status of
|
93
|
+
the object has been determined! (In this case, they will be executed
|
94
|
+
immediately when they are added.)
|
95
|
+
|
96
|
+
A call to Deferrable#set_deferred_status takes :succeeded or :failed as its
|
97
|
+
first argument. (This determines whether the object will call its callbacks
|
98
|
+
or its errbacks.) #set_deferred_status also takes zero or more additional
|
99
|
+
parameters, that will in turn be passed as parameters to the callbacks or
|
100
|
+
errbacks.
|
101
|
+
|
102
|
+
In general, you can only call #set_deferred_status ONCE on a Deferrable
|
103
|
+
object. A call to #set_deferred_status will not return until all of the
|
104
|
+
associated callbacks or errbacks have been called. If you add callbacks or
|
105
|
+
errbacks AFTER making a call to #set_deferred_status, those additional
|
106
|
+
callbacks or errbacks will execute IMMEDIATELY. Any given callback or
|
107
|
+
errback will be executed AT MOST once.
|
108
|
+
|
109
|
+
It's possible to call #set_deferred_status AGAIN, during the execution a
|
110
|
+
callback or errback. This makes it possible to change the parameters which
|
111
|
+
will be sent to the callbacks or errbacks farther down the chain, enabling
|
112
|
+
some extremely elegant use-cases. You can transform the data returned from
|
113
|
+
a deferred operation in arbitrary ways as needed by subsequent users, without
|
114
|
+
changing any of the code that generated the original data.
|
115
|
+
|
116
|
+
A call to #set_deferred_status will not return until all of the associated
|
117
|
+
callbacks or errbacks have been called. If you add callbacks or errbacks
|
118
|
+
AFTER making a call to #set_deferred_status, those additional callbacks or
|
119
|
+
errbacks will execute IMMEDIATELY.
|
120
|
+
|
121
|
+
Let's look at some more sample code. It turns out that many of the internal
|
122
|
+
protocol implementations in the EventMachine package rely on Deferrable. One
|
123
|
+
of these is EM::Protocols::HttpClient.
|
124
|
+
|
125
|
+
To make an evented HTTP request, use the module function
|
126
|
+
EM::Protocols::HttpClient#request, which returns a Deferrable object.
|
127
|
+
Here's how:
|
65
128
|
|
66
129
|
require 'eventmachine'
|
67
|
-
|
130
|
+
|
68
131
|
EM.run {
|
69
|
-
df = EM::Protocols::HttpClient.request( :host=>"www.example.com",
|
70
|
-
|
132
|
+
df = EM::Protocols::HttpClient.request( :host=>"www.example.com",
|
133
|
+
:request=>"/index.html" )
|
134
|
+
|
71
135
|
df.callback {|response|
|
72
136
|
puts "Succeeded: #{response[:content]}"
|
73
137
|
EM.stop
|
74
138
|
}
|
75
|
-
|
139
|
+
|
76
140
|
df.errback {|response|
|
77
141
|
puts "ERROR: #{response[:status]}"
|
78
142
|
EM.stop
|
79
143
|
}
|
80
144
|
}
|
81
145
|
|
82
|
-
(See the documentation of EventMachine::Protocols::HttpClient for information
|
146
|
+
(See the documentation of EventMachine::Protocols::HttpClient for information
|
147
|
+
on the object returned by #request.)
|
83
148
|
|
84
|
-
In this code, we make a call to HttpClient#request, which immediately returns
|
149
|
+
In this code, we make a call to HttpClient#request, which immediately returns
|
150
|
+
a Deferrable object. In the background, an HTTP client request is being made
|
151
|
+
to www.example.com, although your code will continue to run concurrently.
|
85
152
|
|
86
|
-
At some future point, the HTTP client request will complete, and the code in
|
153
|
+
At some future point, the HTTP client request will complete, and the code in
|
154
|
+
EM::Protocols::HttpClient will process either a valid HTTP response (including
|
155
|
+
returned content), or an error.
|
87
156
|
|
88
|
-
At that point, EM::Protocols::HttpClient will call
|
157
|
+
At that point, EM::Protocols::HttpClient will call
|
158
|
+
EM::Deferrable#set_deferred_status on the Deferrable object that was returned
|
159
|
+
to your program, as the return value from EM::Protocols::HttpClient.request.
|
160
|
+
You don't have to do anything to make this happen. All you have to do is tell
|
161
|
+
the Deferrable what to do in case of either success, failure, or both.
|
89
162
|
|
90
|
-
In our code sample, we set one callback and one errback. The former will be
|
163
|
+
In our code sample, we set one callback and one errback. The former will be
|
164
|
+
called if the HTTP call succeeds, and the latter if it fails. (For
|
165
|
+
simplicity, we have both of them calling EM#stop to end the program, although
|
166
|
+
real programs would be very unlikely to do this.)
|
91
167
|
|
92
|
-
Setting callbacks and errbacks is optional. They are handlers to defined
|
168
|
+
Setting callbacks and errbacks is optional. They are handlers to defined
|
169
|
+
events in the lifecycle of the Deferrable event. It's not an error if you
|
170
|
+
fail to set either a callback, an errback, or both. But of course your
|
171
|
+
program will then fail to receive those notifications.
|
93
172
|
|
94
|
-
If through some bug it turns out that #set_deferred_status is never called
|
173
|
+
If through some bug it turns out that #set_deferred_status is never called
|
174
|
+
on a Deferrable object, then that object's callbacks or errbacks will NEVER
|
175
|
+
be called. It's also possible to set a timeout on a Deferrable. If the
|
176
|
+
timeout elapses before any other call to #set_deferred_status, the Deferrable
|
177
|
+
object will behave as is you had called set_deferred_status(:failed) on it.
|
95
178
|
|
96
179
|
|
97
180
|
Now let's modify the example to illustrate some additional points:
|
98
181
|
|
99
182
|
require 'eventmachine'
|
100
|
-
|
183
|
+
|
101
184
|
EM.run {
|
102
|
-
df = EM::Protocols::HttpClient.request( :host=>"www.example.com",
|
103
|
-
|
185
|
+
df = EM::Protocols::HttpClient.request( :host=>"www.example.com",
|
186
|
+
:request=>"/index.html" )
|
187
|
+
|
104
188
|
df.callback {|response|
|
105
189
|
df.set_deferred_status :succeeded, response[:content]
|
106
190
|
}
|
107
|
-
|
191
|
+
|
108
192
|
df.callback {|string|
|
109
193
|
puts "Succeeded: #{string}"
|
110
194
|
EM.stop
|
111
195
|
}
|
112
|
-
|
196
|
+
|
113
197
|
df.errback {|response|
|
114
198
|
puts "ERROR: #{response[:status]}"
|
115
199
|
EM.stop
|
@@ -117,17 +201,46 @@ Now let's modify the example to illustrate some additional points:
|
|
117
201
|
}
|
118
202
|
|
119
203
|
|
120
|
-
Just for the sake of illustration, we've now set two callbacks instead of
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
But
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
204
|
+
Just for the sake of illustration, we've now set two callbacks instead of
|
205
|
+
one. If the deferrable operation (the HTTP client-request) succeeds, then
|
206
|
+
both of the callbacks will be executed in order.
|
207
|
+
|
208
|
+
But notice that we've also made our own call to #set_deferred_status in the
|
209
|
+
first callback. This isn't required, because the HttpClient implementation
|
210
|
+
already made a call to #set_deferred_status. (Otherwise, of course, the
|
211
|
+
callback would not be executing.)
|
212
|
+
|
213
|
+
But we used #set_deferred_status in the first callback in order to change the
|
214
|
+
parameters that will be sent to subsequent callbacks in the chain. In this
|
215
|
+
way, you can construct powerful sequences of layered functionality. If you
|
216
|
+
want, you can even change the status of the Deferrable from :succeeded to
|
217
|
+
:failed, which would abort the chain of callback calls, and invoke the chain
|
218
|
+
of errbacks instead.
|
219
|
+
|
220
|
+
Now of course it's somewhat trivial to define two callbacks in the same
|
221
|
+
method, even with the parameter-changing effect we just described. It would
|
222
|
+
be much more interesting to pass the Deferrable to some other function (for
|
223
|
+
example, a function defined in another module or a different gem), that would
|
224
|
+
in turn add callbacks and/or errbacks of its own. That would illustrate the
|
225
|
+
true power of the Deferrable pattern: to isolate the HTTP client-request
|
226
|
+
from other functions that use the data that it returns without caring where
|
227
|
+
those data came from.
|
228
|
+
|
229
|
+
Remember that you can add a callback or an errback to a Deferrable at any
|
230
|
+
point in time, regardless of whether the status of the deferred operation is
|
231
|
+
known (more precisely, regardless of when #set_deferred_status is called on
|
232
|
+
the object). Even hours or days later.
|
233
|
+
|
234
|
+
When you add a callback or errback to a Deferrable object on which
|
235
|
+
#set_deferred_status has not yet been called, the callback/errback is queued
|
236
|
+
up for future execution, inside the Deferrable object. When you add a
|
237
|
+
callback or errback to a Deferrable on which #set_deferred_status has
|
238
|
+
already been called, the callback/errback will be executed immediately.
|
239
|
+
Your code doesn't have to worry about the ordering, and there are no timing
|
240
|
+
issues, as there would be with a threaded approach.
|
241
|
+
|
242
|
+
For more information on Deferrables and their typical usage patterns, look
|
243
|
+
in the EM unit tests. There are also quite a few sugarings (including
|
244
|
+
EM::Deferrable#future) that make typical Deferrable usages syntactically
|
245
|
+
easier to work with.
|
133
246
|
|