diff --git a/lib/em-synchrony.rb b/lib/em-synchrony.rb index c78eea7..46034f9 100644 --- a/lib/em-synchrony.rb +++ b/lib/em-synchrony.rb @@ -24,4 +24,29 @@ def self.synchrony(blk=nil, tail=nil, &block) self.run(context, tail) end -end + module Synchrony + + # sync is a close relative to inclineCallbacks from Twisted (Python) + # + # Synchrony.sync allows you to write sequential code while using asynchronous + # or callback-based methods under the hood. Example: + # + # result = EM::Synchrony.sync EventMachine::HttpRequest.new(URL).get + # p result.response + # + # As long as the asynchronous function returns a Deferrable object, which + # has a "callback" and an "errback", the sync methond will automatically + # yield and automatically resume your code (via Fibers) when the call + # either succeeds or fails. You do not need to patch or modify the + # Deferrable object, simply pass it to EM::Synchrony.sync + # + def self.sync(df) + f = Fiber.current + df.callback { |r| f.resume(r) } + df.errback { |r| f.resume(r) } + + Fiber.yield + end + end + +end \ No newline at end of file diff --git a/spec/inlinesync_spec.rb b/spec/inlinesync_spec.rb new file mode 100644 index 0000000..e91568f --- /dev/null +++ b/spec/inlinesync_spec.rb @@ -0,0 +1,37 @@ +require "spec/helper/all" +require "em-synchrony/iterator" + +describe EventMachine::Synchrony do + + URL = "http://localhost:8081/" + DELAY = 0.01 + + it "should allow inline callbacks for Deferrable object" do + EM.synchrony do + s = StubServer.new("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nFoo", DELAY) + + result = EM::Synchrony.sync EventMachine::HttpRequest.new(URL).aget + result.response.should match(/Foo/) + + EM.stop + end + end + + it "should inline errback/callback cases" do + EM.synchrony do + class E + include EventMachine::Deferrable + def run + EM.add_timer(0.01) {fail("uh oh!")} + self + end + end + + result = EM::Synchrony.sync E.new.run + result.should match(/uh oh!/) + + EM.stop + end + end + +end