mirror of
https://github.com/rest-client/rest-client.git
synced 2022-11-09 13:49:40 -05:00
Cleaner structure: Response is no more a String, and the mixin is replaced by an abstract_response
This commit is contained in:
parent
58ed49a2b5
commit
7563fd5a88
14 changed files with 102 additions and 107 deletions
2
Rakefile
2
Rakefile
|
@ -3,7 +3,7 @@ require 'rake'
|
|||
require 'jeweler'
|
||||
|
||||
Jeweler::Tasks.new do |s|
|
||||
s.name = "rest-client"
|
||||
s.name = "rest-client-next"
|
||||
s.description = "A simple HTTP and REST client for Ruby, inspired by the Sinatra microframework style of specifying actions: get, put, post, delete."
|
||||
s.summary = "Simple HTTP and REST client for Ruby, inspired by microframework syntax for specifying actions."
|
||||
s.author = "Adam Wiggins"
|
||||
|
|
|
@ -11,7 +11,7 @@ end
|
|||
|
||||
require File.dirname(__FILE__) + '/restclient/exceptions'
|
||||
require File.dirname(__FILE__) + '/restclient/request'
|
||||
require File.dirname(__FILE__) + '/restclient/mixin/response'
|
||||
require File.dirname(__FILE__) + '/restclient/abstract_response'
|
||||
require File.dirname(__FILE__) + '/restclient/response'
|
||||
require File.dirname(__FILE__) + '/restclient/raw_response'
|
||||
require File.dirname(__FILE__) + '/restclient/resource'
|
||||
|
|
58
lib/restclient/abstract_response.rb
Normal file
58
lib/restclient/abstract_response.rb
Normal file
|
@ -0,0 +1,58 @@
|
|||
module RestClient
|
||||
|
||||
class AbstractResponse
|
||||
|
||||
attr_reader :net_http_res
|
||||
|
||||
# HTTP status code
|
||||
def code
|
||||
@code ||= @net_http_res.code.to_i
|
||||
end
|
||||
|
||||
# A hash of the headers, beautified with symbols and underscores.
|
||||
# e.g. "Content-type" will become :content_type.
|
||||
def headers
|
||||
@headers ||= self.class.beautify_headers(@net_http_res.to_hash)
|
||||
end
|
||||
|
||||
# The raw headers.
|
||||
def raw_headers
|
||||
@raw_headers ||= @net_http_res.to_hash
|
||||
end
|
||||
|
||||
# Hash of cookies extracted from response headers
|
||||
def cookies
|
||||
@cookies ||= (self.headers[:set_cookie] || []).inject({}) do |out, cookie_content|
|
||||
# correctly parse comma-separated cookies containing HTTP dates (which also contain a comma)
|
||||
cookie_content.split(/,\s*/).inject([""]) { |array, blob|
|
||||
blob =~ /expires=.+?$/ ? array.push(blob) : array.last.concat(blob)
|
||||
array
|
||||
}.each do |cookie|
|
||||
next if cookie.empty?
|
||||
key, *val = cookie.split(";").first.split("=")
|
||||
out[key] = val.join("=")
|
||||
end
|
||||
out
|
||||
end
|
||||
end
|
||||
|
||||
# Return the default behavior corresponding to the response code:
|
||||
# the response itself for code in 200..206 and an exception in other cases
|
||||
def return!
|
||||
if (200..206).include? code
|
||||
self
|
||||
elsif Exceptions::EXCEPTIONS_MAP[code]
|
||||
raise Exceptions::EXCEPTIONS_MAP[code], self
|
||||
else
|
||||
raise RequestFailed, self
|
||||
end
|
||||
end
|
||||
|
||||
def AbstractResponse.beautify_headers(headers)
|
||||
headers.inject({}) do |out, (key, value)|
|
||||
out[key.gsub(/-/, '_').downcase.to_sym] = %w{set-cookie}.include?(key.downcase) ? value : value.first
|
||||
out
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -19,7 +19,7 @@ module RestClient
|
|||
end
|
||||
|
||||
def http_body
|
||||
@response
|
||||
@response.body
|
||||
end
|
||||
|
||||
def inspect
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
module RestClient
|
||||
module Mixin
|
||||
module Response
|
||||
attr_reader :net_http_res
|
||||
|
||||
# HTTP status code
|
||||
def code
|
||||
@code ||= @net_http_res.code.to_i
|
||||
end
|
||||
|
||||
# A hash of the headers, beautified with symbols and underscores.
|
||||
# e.g. "Content-type" will become :content_type.
|
||||
def headers
|
||||
@headers ||= self.class.beautify_headers(@net_http_res.to_hash)
|
||||
end
|
||||
|
||||
# The raw headers.
|
||||
def raw_headers
|
||||
@raw_headers ||= @net_http_res.to_hash
|
||||
end
|
||||
|
||||
# Hash of cookies extracted from response headers
|
||||
def cookies
|
||||
@cookies ||= (self.headers[:set_cookie] || []).inject({}) do |out, cookie_content|
|
||||
# correctly parse comma-separated cookies containing HTTP dates (which also contain a comma)
|
||||
cookie_content.split(/,\s*/).inject([""]) { |array, blob|
|
||||
blob =~ /expires=.+?$/ ? array.push(blob) : array.last.concat(blob)
|
||||
array
|
||||
}.each do |cookie|
|
||||
next if cookie.empty?
|
||||
key, *val = cookie.split(";").first.split("=")
|
||||
out[key] = val.join("=")
|
||||
end
|
||||
out
|
||||
end
|
||||
end
|
||||
|
||||
# Return the default behavior corresponding to the response code:
|
||||
# the response itself for code in 200..206 and an exception in other cases
|
||||
def return!
|
||||
if (200..206).include? code
|
||||
self
|
||||
elsif Exceptions::EXCEPTIONS_MAP[code]
|
||||
raise Exceptions::EXCEPTIONS_MAP[code], self
|
||||
else
|
||||
raise RequestFailed, self
|
||||
end
|
||||
end
|
||||
|
||||
def self.included(receiver)
|
||||
receiver.extend(RestClient::Mixin::Response::ClassMethods)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def beautify_headers(headers)
|
||||
headers.inject({}) do |out, (key, value)|
|
||||
out[key.gsub(/-/, '_').downcase.to_sym] = %w{set-cookie}.include?(key.downcase) ? value : value.first
|
||||
out
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -88,7 +88,7 @@ module RestClient
|
|||
end
|
||||
|
||||
def short_inspect
|
||||
(size > 100 ? "#{size} byte length" : inspect)
|
||||
(size > 100 ? "#{size} byte(s) length" : inspect)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
require File.dirname(__FILE__) + '/mixin/response'
|
||||
|
||||
module RestClient
|
||||
# The response from RestClient on a raw request looks like a string, but is
|
||||
# actually one of these. 99% of the time you're making a rest call all you
|
||||
|
@ -11,8 +9,7 @@ module RestClient
|
|||
# In addition, if you do not use the response as a string, you can access
|
||||
# a Tempfile object at res.file, which contains the path to the raw
|
||||
# downloaded request body.
|
||||
class RawResponse
|
||||
include RestClient::Mixin::Response
|
||||
class RawResponse < AbstractResponse
|
||||
|
||||
attr_reader :file
|
||||
|
||||
|
|
|
@ -1,19 +1,31 @@
|
|||
require File.dirname(__FILE__) + '/mixin/response'
|
||||
|
||||
module RestClient
|
||||
# The response from RestClient looks like a string, but is actually one of
|
||||
# these. 99% of the time you're making a rest call all you care about is
|
||||
# the body, but on the occassion you want to fetch the headers you can:
|
||||
#
|
||||
# RestClient.get('http://example.com').headers[:content_type]
|
||||
#
|
||||
class Response < String
|
||||
|
||||
include RestClient::Mixin::Response
|
||||
# A Response from RestClient, you can access the response body, the code or the headers.
|
||||
#
|
||||
class Response < AbstractResponse
|
||||
|
||||
def initialize(string, net_http_res)
|
||||
attr_reader :body
|
||||
|
||||
def initialize(body, net_http_res)
|
||||
@net_http_res = net_http_res
|
||||
super(string || "")
|
||||
@body = body || ""
|
||||
end
|
||||
|
||||
def method_missing symbol, *args
|
||||
if body.respond_to? symbol
|
||||
warn "[warning] The Response is no more a String, please update your code"
|
||||
body.send symbol, *args
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
body.to_s
|
||||
end
|
||||
|
||||
def inspect
|
||||
"Code #{code} #{headers[:content_type] ? "#{headers[:content_type] } ": ''} #{body.size} byte(s)"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
BIN
rest-client-next-1.3.0.gem
Normal file
BIN
rest-client-next-1.3.0.gem
Normal file
Binary file not shown.
|
@ -1,7 +1,7 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = %q{rest-client}
|
||||
s.name = %q{rest-client-next}
|
||||
s.version = "1.3.0"
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||
s.authors = ["Adam Wiggins", "Julien Kirch"]
|
||||
|
@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|||
"lib/rest_client.rb",
|
||||
"lib/restclient.rb",
|
||||
"lib/restclient/exceptions.rb",
|
||||
"lib/restclient/mixin/response.rb",
|
||||
"lib/restclient/abstract_response.rb",
|
||||
"lib/restclient/net_http_ext.rb",
|
||||
"lib/restclient/payload.rb",
|
||||
"lib/restclient/raw_response.rb",
|
||||
|
@ -32,7 +32,7 @@ Gem::Specification.new do |s|
|
|||
"spec/exceptions_spec.rb",
|
||||
"spec/integration_spec.rb",
|
||||
"spec/master_shake.jpg",
|
||||
"spec/mixin/response_spec.rb",
|
||||
"spec/abstract_response_spec.rb",
|
||||
"spec/payload_spec.rb",
|
||||
"spec/raw_response_spec.rb",
|
||||
"spec/request_spec.rb",
|
||||
|
|
|
@ -1,18 +1,9 @@
|
|||
require File.dirname(__FILE__) + '/../base'
|
||||
require File.dirname(__FILE__) + '/base'
|
||||
|
||||
class MockResponse
|
||||
include RestClient::Mixin::Response
|
||||
|
||||
def initialize(body, res)
|
||||
@net_http_res = res
|
||||
@body = body
|
||||
end
|
||||
end
|
||||
|
||||
describe RestClient::Mixin::Response do
|
||||
describe RestClient::AbstractResponse do
|
||||
before do
|
||||
@net_http_res = mock('net http response')
|
||||
@response = MockResponse.new('abc', @net_http_res)
|
||||
@response = AbstractResponse.new('abc', @net_http_res)
|
||||
end
|
||||
|
||||
it "fetches the numeric response code" do
|
|
@ -10,14 +10,14 @@ describe RestClient do
|
|||
stub_request(:get, "www.example.com").to_return(:body => body, :status => 200)
|
||||
response = RestClient.get "www.example.com"
|
||||
response.code.should == 200
|
||||
response.should == body
|
||||
response.body.should == body
|
||||
end
|
||||
|
||||
it "a simple request with gzipped content" do
|
||||
stub_request(:get, "www.example.com").with(:headers => { 'Accept-Encoding' => 'gzip, deflate' }).to_return(:body => "\037\213\b\b\006'\252H\000\003t\000\313T\317UH\257\312,HM\341\002\000G\242(\r\v\000\000\000", :status => 200, :headers => { 'Content-Encoding' => 'gzip' } )
|
||||
response = RestClient.get "www.example.com"
|
||||
response.code.should == 200
|
||||
response.should == "i'm gziped\n"
|
||||
response.body.should == "i'm gziped\n"
|
||||
end
|
||||
|
||||
it "a 404" do
|
||||
|
@ -29,7 +29,7 @@ describe RestClient do
|
|||
rescue RestClient::ResourceNotFound => e
|
||||
e.http_code.should == 404
|
||||
e.response.code.should == 404
|
||||
e.response.should == body
|
||||
e.response.body.should == body
|
||||
e.http_body.should == body
|
||||
end
|
||||
end
|
||||
|
|
|
@ -45,7 +45,8 @@ describe RestClient::Request do
|
|||
res.stub!(:code).and_return("200")
|
||||
res.stub!(:body).and_return('body')
|
||||
res.stub!(:[]).with('content-encoding').and_return(nil)
|
||||
@request.process_result(res).should == 'body'
|
||||
@request.process_result(res).body.should == 'body'
|
||||
@request.process_result(res).to_s.should == 'body'
|
||||
end
|
||||
|
||||
it "doesn't classify successful requests as failed" do
|
||||
|
@ -324,8 +325,8 @@ describe RestClient::Request do
|
|||
it "logs a post request with a large payload" do
|
||||
log = RestClient.log = []
|
||||
RestClient::Request.new(:method => :post, :url => 'http://url', :payload => ('x' * 1000)).log_request
|
||||
['RestClient.post "http://url", 1000 byte length, "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"1000", "Accept"=>"*/*; q=0.5, application/xml"' + "\n",
|
||||
'RestClient.post "http://url", 1000 byte length, "Accept"=>"*/*; q=0.5, application/xml", "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"1000"' + "\n"].should include(log[0])
|
||||
['RestClient.post "http://url", 1000 byte(s) length, "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"1000", "Accept"=>"*/*; q=0.5, application/xml"' + "\n",
|
||||
'RestClient.post "http://url", 1000 byte(s) length, "Accept"=>"*/*; q=0.5, application/xml", "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"1000"' + "\n"].should include(log[0])
|
||||
end
|
||||
|
||||
it "logs input headers as a hash" do
|
||||
|
|
|
@ -7,11 +7,11 @@ describe RestClient::Response do
|
|||
end
|
||||
|
||||
it "behaves like string" do
|
||||
@response.should == 'abc'
|
||||
@response.should.to_s == 'abc'
|
||||
end
|
||||
|
||||
it "accepts nil strings and sets it to empty for the case of HEAD" do
|
||||
RestClient::Response.new(nil, @net_http_res).should == ""
|
||||
RestClient::Response.new(nil, @net_http_res).should.to_s == ""
|
||||
end
|
||||
|
||||
it "test headers and raw headers" do
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue