ruby-oauth にブロックを渡せるようにする

Ruby には既に OAuth ライブラリ があるが,ブロックを渡せないのでちょっとずつ body を読み込みつつ何かする,というような処理ができない.
最終的には net/http を使っているので,適当にブロックを運ぶように書き換えて

consumer = OAuth::Consumer.new(consumer_key, consumer_secret, :site => 'http://twitter.com')
access_token = OAuth::AccessToken.new(consumer, token, token_secret)
access_token.get('http://chirpstream.twitter.com/2b/user.json?replies=all') do |res|
  if res.code == '200'
    res.read_body do |s|
      do_something s
    end
  end
end

とも書けるようにした.


以下 0.4.2 に対する差分.

--- lib-orig/oauth/consumer.rb
+++ lib/oauth/consumer.rb
@@ -151,7 +151,7 @@ module OAuth
     #   @consumer.request(:get,  '/people', @token, { :scheme => :query_string })
     #   @consumer.request(:post, '/people', @token, {}, @person.to_xml, { 'Content-Type' => 'application/xml' })
     #
-    def request(http_method, path, token = nil, request_options = {}, *arguments)
+    def request(http_method, path, token = nil, request_options = {}, *arguments, &block)
       if path !~ /^\//
         @http = create_http(path)
         _uri = URI.parse(path)
@@ -160,7 +160,10 @@ module OAuth
 
       # override the request with your own, this is useful for file uploads which Net::HTTP does not do
       req = create_signed_request(http_method, path, token, request_options, *arguments)
-      return nil if block_given? and yield(req) == :done
+      if block_given?
+        http.request(req, &block)
+        return nil
+      end
       rsp = http.request(req)
       # check for an error reported by the Problem Reporting extension
       # (http://wiki.oauth.net/ProblemReporting)
--- lib-orig/oauth/tokens/access_token.rb
+++ lib/oauth/tokens/access_token.rb
@@ -3,12 +3,16 @@ module OAuth
   class AccessToken < ConsumerToken
     # The less intrusive way. Otherwise, if we are to do it correctly inside consumer,
     # we need to restructure and touch more methods: request(), sign!(), etc.
-    def request(http_method, path, *arguments)
+    def request(http_method, path, *arguments, &block)
       request_uri = URI.parse(path)
       site_uri = consumer.uri
       is_service_uri_different = (request_uri.absolute? && request_uri != site_uri)
       consumer.uri(request_uri) if is_service_uri_different
-      @response = super(http_method, path, *arguments)
+      if block_given?
+        return super(http_method, path, *arguments, &block)
+      else
+        @response = super(http_method, path, *arguments)
+      end
       # NOTE: reset for wholesomeness? meaning that we admit only AccessToken service calls may use different URIs?
       # so reset in case consumer is still used for other token-management tasks subsequently?
       consumer.uri(site_uri) if is_service_uri_different
@@ -20,8 +24,8 @@ module OAuth
     #   @response = @token.get('/people')
     #   @response = @token.get('/people', { 'Accept'=>'application/xml' })
     #
-    def get(path, headers = {})
-      request(:get, path, headers)
+    def get(path, headers = {}, &block)
+      request(:get, path, headers, &block)
     end
 
     # Make a regular HEAD request using AccessToken
@@ -40,8 +44,8 @@ module OAuth
     #   @response = @token.post('/people', nil, {'Accept' => 'application/xml' })
     #   @response = @token.post('/people', @person.to_xml, { 'Accept'=>'application/xml', 'Content-Type' => 'application/xml' })
     #
-    def post(path, body = '', headers = {})
-      request(:post, path, body, headers)
+    def post(path, body = '', headers = {}, &block)
+      request(:post, path, body, headers, &block)
     end
 
     # Make a regular PUT request using AccessToken
@@ -52,8 +56,8 @@ module OAuth
     #   @response = @token.put('/people/123', nil, { 'Accept' => 'application/xml' })
     #   @response = @token.put('/people/123', @person.to_xml, { 'Accept' => 'application/xml', 'Content-Type' => 'application/xml' })
     #
-    def put(path, body = '', headers = {})
-      request(:put, path, body, headers)
+    def put(path, body = '', headers = {}, &block)
+      request(:put, path, body, headers, &block)
     end
 
     # Make a regular DELETE request using AccessToken
@@ -61,8 +65,8 @@ module OAuth
     #   @response = @token.delete('/people/123')
     #   @response = @token.delete('/people/123', { 'Accept' => 'application/xml' })
     #
-    def delete(path, headers = {})
-      request(:delete, path, headers)
+    def delete(path, headers = {}, &block)
+      request(:delete, path, headers, &block)
     end
   end
 end
--- lib-orig/oauth/tokens/consumer_token.rb
+++ lib/oauth/tokens/consumer_token.rb
@@ -21,8 +21,12 @@ module OAuth
     #   @token.request(:get,  '/people')
     #   @token.request(:post, '/people', @person.to_xml, { 'Content-Type' => 'application/xml' })
     #
-    def request(http_method, path, *arguments)
-      @response = consumer.request(http_method, path, self, {}, *arguments)
+    def request(http_method, path, *arguments, &block)
+      if block_given?
+        consumer.request(http_method, path, self, {}, *arguments, &block)
+      else
+        @response = consumer.request(http_method, path, self, {}, *arguments)
+      end
     end
 
     # Sign a request generated elsewhere using Net:HTTP::Post.new or friends