mirror of
https://github.com/jnunemaker/httparty
synced 2023-03-27 23:23:07 -04:00
Adding custom parsers
This commit is contained in:
parent
a2a3f8bb41
commit
e5cbceaf00
2 changed files with 77 additions and 64 deletions
|
@ -3,14 +3,14 @@ require 'uri'
|
|||
module HTTParty
|
||||
class Request #:nodoc:
|
||||
SupportedHTTPMethods = [Net::HTTP::Get, Net::HTTP::Post, Net::HTTP::Put, Net::HTTP::Delete]
|
||||
|
||||
|
||||
attr_accessor :http_method, :path, :options
|
||||
|
||||
|
||||
def initialize(http_method, path, o={})
|
||||
self.http_method = http_method
|
||||
self.path = path
|
||||
self.options = {
|
||||
:limit => o.delete(:no_follow) ? 0 : 5,
|
||||
:limit => o.delete(:no_follow) ? 0 : 5,
|
||||
:default_params => {},
|
||||
}.merge(o)
|
||||
end
|
||||
|
@ -18,22 +18,22 @@ module HTTParty
|
|||
def path=(uri)
|
||||
@path = URI.parse(uri)
|
||||
end
|
||||
|
||||
|
||||
def uri
|
||||
new_uri = path.relative? ? URI.parse("#{options[:base_uri]}#{path}") : path
|
||||
|
||||
|
||||
# avoid double query string on redirects [#12]
|
||||
unless @redirect
|
||||
new_uri.query = query_string(new_uri)
|
||||
end
|
||||
|
||||
|
||||
new_uri
|
||||
end
|
||||
|
||||
|
||||
def format
|
||||
options[:format]
|
||||
end
|
||||
|
||||
|
||||
def perform
|
||||
validate
|
||||
setup_raw_request
|
||||
|
@ -56,11 +56,11 @@ module HTTParty
|
|||
def body
|
||||
options[:body].is_a?(Hash) ? options[:body].to_params : options[:body]
|
||||
end
|
||||
|
||||
|
||||
def username
|
||||
options[:basic_auth][:username]
|
||||
end
|
||||
|
||||
|
||||
def password
|
||||
options[:basic_auth][:password]
|
||||
end
|
||||
|
@ -81,7 +81,7 @@ module HTTParty
|
|||
options[:format] ||= format_from_mimetype(response['content-type'])
|
||||
response
|
||||
end
|
||||
|
||||
|
||||
def query_string(uri)
|
||||
query_string_parts = []
|
||||
query_string_parts << uri.query unless uri.query.nil?
|
||||
|
@ -92,10 +92,10 @@ module HTTParty
|
|||
query_string_parts << options[:default_params].to_params unless options[:default_params].nil?
|
||||
query_string_parts << options[:query] unless options[:query].nil?
|
||||
end
|
||||
|
||||
|
||||
query_string_parts.size > 0 ? query_string_parts.join('&') : nil
|
||||
end
|
||||
|
||||
|
||||
# Raises exception Net::XXX (http error code) if an http error occured
|
||||
def handle_response(response)
|
||||
case response
|
||||
|
@ -111,8 +111,7 @@ module HTTParty
|
|||
Response.new(parsed_response, response.body, response.code, response.message, response.to_hash)
|
||||
end
|
||||
end
|
||||
|
||||
# HTTParty.const_get((self.format.to_s || 'text').capitalize)
|
||||
|
||||
def parse_response(body)
|
||||
return nil if body.nil? or body.empty?
|
||||
if options[:parser].blank?
|
||||
|
@ -134,7 +133,7 @@ module HTTParty
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def capture_cookies(response)
|
||||
return unless response['Set-Cookie']
|
||||
cookies_hash = HTTParty::CookieHash.new()
|
||||
|
@ -143,23 +142,14 @@ module HTTParty
|
|||
options[:headers] ||= {}
|
||||
options[:headers]['Cookie'] = cookies_hash.to_cookie_string
|
||||
end
|
||||
|
||||
def capture_cookies(response)
|
||||
return unless response['Set-Cookie']
|
||||
cookies_hash = HTTParty::CookieHash.new()
|
||||
cookies_hash.add_cookies(options[:headers]['Cookie']) if options[:headers] && options[:headers]['Cookie']
|
||||
cookies_hash.add_cookies(response['Set-Cookie'])
|
||||
options[:headers] ||= {}
|
||||
options[:headers]['Cookie'] = cookies_hash.to_cookie_string
|
||||
end
|
||||
|
||||
|
||||
# Uses the HTTP Content-Type header to determine the format of the response
|
||||
# It compares the MIME type returned to the types stored in the AllowedFormats hash
|
||||
def format_from_mimetype(mimetype)
|
||||
return nil if mimetype.nil?
|
||||
AllowedFormats.each { |k, v| return v if mimetype.include?(k) }
|
||||
end
|
||||
|
||||
|
||||
def validate
|
||||
raise HTTParty::RedirectionTooDeep, 'HTTP redirects too deep' if options[:limit].to_i <= 0
|
||||
raise ArgumentError, 'only get, post, put and delete methods are supported' unless SupportedHTTPMethods.include?(http_method)
|
||||
|
@ -167,7 +157,7 @@ module HTTParty
|
|||
raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].is_a?(Hash)
|
||||
raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].is_a?(Hash)
|
||||
end
|
||||
|
||||
|
||||
def post?
|
||||
Net::HTTP::Post == http_method
|
||||
end
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
||||
|
||||
class CustomParser
|
||||
def self.parse(body)
|
||||
return {:sexy => true}
|
||||
end
|
||||
end
|
||||
|
||||
describe HTTParty do
|
||||
before(:each) do
|
||||
@klass = Class.new
|
||||
|
@ -14,7 +20,7 @@ describe HTTParty do
|
|||
it "should have reader" do
|
||||
@klass.base_uri.should == 'http://api.foo.com/v1'
|
||||
end
|
||||
|
||||
|
||||
it 'should have writer' do
|
||||
@klass.base_uri('http://api.foobar.com')
|
||||
@klass.base_uri.should == 'http://api.foobar.com'
|
||||
|
@ -26,18 +32,18 @@ describe HTTParty do
|
|||
uri.should == 'http://api.foobar.com'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "#normalize_base_uri" do
|
||||
it "should add http if not present for non ssl requests" do
|
||||
uri = HTTParty.normalize_base_uri('api.foobar.com')
|
||||
uri.should == 'http://api.foobar.com'
|
||||
end
|
||||
|
||||
|
||||
it "should add https if not present for ssl requests" do
|
||||
uri = HTTParty.normalize_base_uri('api.foo.com/v1:443')
|
||||
uri.should == 'https://api.foo.com/v1:443'
|
||||
end
|
||||
|
||||
|
||||
it "should not remove https for ssl requests" do
|
||||
uri = HTTParty.normalize_base_uri('https://api.foo.com/v1:443')
|
||||
uri.should == 'https://api.foo.com/v1:443'
|
||||
|
@ -49,7 +55,7 @@ describe HTTParty do
|
|||
uri.should == 'http://api.foobar.com'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "headers" do
|
||||
def expect_headers(header={})
|
||||
HTTParty::Request.should_receive(:new) \
|
||||
|
@ -170,47 +176,64 @@ describe HTTParty do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "default params" do
|
||||
it "should default to empty hash" do
|
||||
@klass.default_params.should == {}
|
||||
end
|
||||
|
||||
|
||||
it "should be able to be updated" do
|
||||
new_defaults = {:foo => 'bar', :baz => 'spax'}
|
||||
@klass.default_params new_defaults
|
||||
@klass.default_params.should == new_defaults
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "basic http authentication" do
|
||||
it "should work" do
|
||||
@klass.basic_auth 'foobar', 'secret'
|
||||
@klass.default_options[:basic_auth].should == {:username => 'foobar', :password => 'secret'}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "parser" do
|
||||
before(:each) do
|
||||
@parser = Proc.new{ |data| CustomParser.parse(data) }
|
||||
@klass.parser @parser
|
||||
end
|
||||
|
||||
it "should set parser options" do
|
||||
@klass.default_options[:parser].should == @parser
|
||||
end
|
||||
|
||||
it "should be able parse response with custom parser" do
|
||||
FakeWeb.register_uri(:get, 'http://twitter.com/statuses/public_timeline.xml', :body => 'tweets')
|
||||
custom_parsed_response = @klass.get('http://twitter.com/statuses/public_timeline.xml')
|
||||
custom_parsed_response[:sexy].should == true
|
||||
end
|
||||
end
|
||||
|
||||
describe "format" do
|
||||
it "should allow xml" do
|
||||
@klass.format :xml
|
||||
@klass.default_options[:format].should == :xml
|
||||
end
|
||||
|
||||
|
||||
it "should allow json" do
|
||||
@klass.format :json
|
||||
@klass.default_options[:format].should == :json
|
||||
end
|
||||
|
||||
|
||||
it "should allow yaml" do
|
||||
@klass.format :yaml
|
||||
@klass.default_options[:format].should == :yaml
|
||||
end
|
||||
|
||||
|
||||
it "should allow plain" do
|
||||
@klass.format :plain
|
||||
@klass.default_options[:format].should == :plain
|
||||
end
|
||||
|
||||
|
||||
it 'should not allow funky format' do
|
||||
lambda do
|
||||
@klass.format :foobar
|
||||
|
@ -251,7 +274,7 @@ describe HTTParty do
|
|||
end.should raise_error(HTTParty::RedirectionTooDeep)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "with multiple class definitions" do
|
||||
before(:each) do
|
||||
@klass.instance_eval do
|
||||
|
@ -272,57 +295,57 @@ describe HTTParty do
|
|||
@additional_klass.default_options.should == { :base_uri => 'http://second.com', :default_params => { :two => 2 } }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe "#get" do
|
||||
it "should be able to get html" do
|
||||
stub_http_response_with('google.html')
|
||||
HTTParty.get('http://www.google.com').should == file_fixture('google.html')
|
||||
end
|
||||
|
||||
|
||||
it "should be able parse response type json automatically" do
|
||||
stub_http_response_with('twitter.json')
|
||||
tweets = HTTParty.get('http://twitter.com/statuses/public_timeline.json')
|
||||
tweets.size.should == 20
|
||||
tweets.first['user'].should == {
|
||||
"name" => "Pyk",
|
||||
"url" => nil,
|
||||
"id" => "7694602",
|
||||
"description" => nil,
|
||||
"protected" => false,
|
||||
"screen_name" => "Pyk",
|
||||
"followers_count" => 1,
|
||||
"location" => "Opera Plaza, California",
|
||||
"name" => "Pyk",
|
||||
"url" => nil,
|
||||
"id" => "7694602",
|
||||
"description" => nil,
|
||||
"protected" => false,
|
||||
"screen_name" => "Pyk",
|
||||
"followers_count" => 1,
|
||||
"location" => "Opera Plaza, California",
|
||||
"profile_image_url" => "http://static.twitter.com/images/default_profile_normal.png"
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
it "should be able parse response type xml automatically" do
|
||||
stub_http_response_with('twitter.xml')
|
||||
tweets = HTTParty.get('http://twitter.com/statuses/public_timeline.xml')
|
||||
tweets['statuses'].size.should == 20
|
||||
tweets['statuses'].first['user'].should == {
|
||||
"name" => "Magic 8 Bot",
|
||||
"url" => nil,
|
||||
"id" => "17656026",
|
||||
"description" => "ask me a question",
|
||||
"protected" => "false",
|
||||
"screen_name" => "magic8bot",
|
||||
"followers_count" => "90",
|
||||
"profile_image_url" => "http://s3.amazonaws.com/twitter_production/profile_images/65565851/8ball_large_normal.jpg",
|
||||
"name" => "Magic 8 Bot",
|
||||
"url" => nil,
|
||||
"id" => "17656026",
|
||||
"description" => "ask me a question",
|
||||
"protected" => "false",
|
||||
"screen_name" => "magic8bot",
|
||||
"followers_count" => "90",
|
||||
"profile_image_url" => "http://s3.amazonaws.com/twitter_production/profile_images/65565851/8ball_large_normal.jpg",
|
||||
"location" => nil
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
it "should not get undefined method add_node for nil class for the following xml" do
|
||||
stub_http_response_with('undefined_method_add_node_for_nil.xml')
|
||||
result = HTTParty.get('http://foobar.com')
|
||||
result.should == {"Entities"=>{"href"=>"https://s3-sandbox.parature.com/api/v1/5578/5633/Account", "results"=>"0", "total"=>"0", "page_size"=>"25", "page"=>"1"}}
|
||||
end
|
||||
|
||||
|
||||
it "should parse empty response fine" do
|
||||
stub_http_response_with('empty.xml')
|
||||
result = HTTParty.get('http://foobar.com')
|
||||
result.should == nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue