From 9fd5259c8dab00e426082b66af44ede2c9068f45 Mon Sep 17 00:00:00 2001 From: John Nunemaker Date: Sat, 21 Apr 2012 22:49:45 -0400 Subject: [PATCH] Lazy parsing of responses to allow for response code checking prior to parsing. Fixes #79 --- lib/httparty/request.rb | 2 +- lib/httparty/response.rb | 20 ++++++++++++-------- spec/httparty/request_spec.rb | 10 ++++++++++ spec/httparty/response_spec.rb | 29 +++++++++-------------------- 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/lib/httparty/request.rb b/lib/httparty/request.rb index ef34a08c..db556a08 100644 --- a/lib/httparty/request.rb +++ b/lib/httparty/request.rb @@ -208,7 +208,7 @@ def handle_response(body) perform else body = body || last_response.body - Response.new(self, last_response, parse_response(body), :body => body) + Response.new(self, last_response, lambda { parse_response(body) }, :body => body) end end diff --git a/lib/httparty/response.rb b/lib/httparty/response.rb index 6bb889a0..3193b998 100644 --- a/lib/httparty/response.rb +++ b/lib/httparty/response.rb @@ -4,14 +4,18 @@ def self.underscore(string) string.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z])([A-Z])/,'\1_\2').downcase end - attr_reader :request, :response, :parsed_response, :body, :headers + attr_reader :request, :response, :body, :headers - def initialize(request, response, parsed_response, options={}) - @request = request - @response = response - @body = response.body || options[:body] - @parsed_response = parsed_response - @headers = Headers.new(response.to_hash) + def initialize(request, response, parsed_block, options={}) + @request = request + @response = response + @body = response.body || options[:body] + @parsed_block = parsed_block + @headers = Headers.new(response.to_hash) + end + + def parsed_response + @parsed_response ||= @parsed_block.call end def class @@ -24,7 +28,7 @@ def code def inspect inspect_id = "%x" % (object_id * 2) - %(#<#{self.class}:0x#{inspect_id} @parsed_response=#{parsed_response.inspect}, @response=#{response.inspect}, @headers=#{headers.inspect}>) + %(#<#{self.class}:0x#{inspect_id} parsed_response=#{parsed_response.inspect}, @response=#{response.inspect}, @headers=#{headers.inspect}>) end CODES_TO_OBJ = ::Net::HTTPResponse::CODE_CLASS_TO_OBJ.merge ::Net::HTTPResponse::CODE_TO_OBJ diff --git a/spec/httparty/request_spec.rb b/spec/httparty/request_spec.rb index 7b723740..f233dd12 100644 --- a/spec/httparty/request_spec.rb +++ b/spec/httparty/request_spec.rb @@ -411,6 +411,16 @@ resp.body.should == "error" resp['foo']['bar'].should == "error" end + + it "parses response lazily so codes can be checked prior" do + stub_response 'not xml', 500 + @request.options[:format] = :xml + lambda { + response = @request.perform + response.code.should == 500 + response.body.should == 'not xml' + }.should_not raise_error + end end end diff --git a/spec/httparty/response_spec.rb b/spec/httparty/response_spec.rb index 99aad1f3..35380d52 100644 --- a/spec/httparty/response_spec.rb +++ b/spec/httparty/response_spec.rb @@ -9,7 +9,7 @@ @response_object.stub(:body => "{foo:'bar'}") @response_object['last-modified'] = @last_modified @response_object['content-length'] = @content_length - @parsed_response = {"foo" => "bar"} + @parsed_response = lambda { {"foo" => "bar"} } @response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) end @@ -51,42 +51,42 @@ end it "should send missing methods to delegate" do - response = HTTParty::Response.new(@request_object, @response_object, {'foo' => 'bar'}) + response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response['foo'].should == 'bar' end it "response to request" do - response = HTTParty::Response.new(@request_object, @response_object, {'foo' => 'bar'}) + response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.respond_to?(:request).should be_true end it "responds to response" do - response = HTTParty::Response.new(@request_object, @response_object, {'foo' => 'bar'}) + response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.respond_to?(:response).should be_true end it "responds to body" do - response = HTTParty::Response.new(@request_object, @response_object, {'foo' => 'bar'}) + response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.respond_to?(:body).should be_true end it "responds to headers" do - response = HTTParty::Response.new(@request_object, @response_object, {'foo' => 'bar'}) + response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.respond_to?(:headers).should be_true end it "responds to parsed_response" do - response = HTTParty::Response.new(@request_object, @response_object, {'foo' => 'bar'}) + response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.respond_to?(:parsed_response).should be_true end it "responds to anything parsed_response responds to" do - response = HTTParty::Response.new(@request_object, @response_object, {'foo' => 'bar'}) + response = HTTParty::Response.new(@request_object, @response_object, @parsed_response) response.respond_to?(:[]).should be_true end it "should be able to iterate if it is array" do - response = HTTParty::Response.new(@request_object, @response_object, [{'foo' => 'bar'}, {'foo' => 'baz'}]) + response = HTTParty::Response.new(@request_object, @response_object, lambda { [{'foo' => 'bar'}, {'foo' => 'baz'}] }) response.size.should == 2 expect { response.each { |item| } @@ -114,17 +114,6 @@ end end - xit "should allow hashes to be accessed with dot notation" do - response = HTTParty::Response.new(@request_object, {'foo' => 'bar'}, "{foo:'bar'}", 200, 'OK') - response.foo.should == 'bar' - end - - xit "should allow nested hashes to be accessed with dot notation" do - response = HTTParty::Response.new(@request_object, {'foo' => {'bar' => 'baz'}}, "{foo: {bar:'baz'}}", 200, 'OK') - response.foo.should == {'bar' => 'baz'} - response.foo.bar.should == 'baz' - end - describe "semantic methods for response codes" do def response_mock(klass) response = klass.new('', '', '')