jnunemaker-httparty 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +6 -1
- data/Manifest.txt +2 -1
- data/examples/google.rb +1 -0
- data/httparty.gemspec +7 -5
- data/lib/httparty.rb +31 -105
- data/lib/httparty/request.rb +104 -0
- data/lib/httparty/version.rb +1 -1
- data/spec/httparty/request_spec.rb +107 -0
- data/spec/httparty_spec.rb +26 -127
- data/spec/spec.opts +3 -1
- metadata +4 -3
data/History.txt
CHANGED
@@ -1,5 +1,10 @@
|
|
1
|
+
== 0.1.5 2008-11-14
|
2
|
+
* 2 major enhancements
|
3
|
+
* Refactored send request method out into its own object.
|
4
|
+
* Added :html format if you just want to do that.
|
5
|
+
|
1
6
|
== 0.1.4 2008-11-08
|
2
|
-
*
|
7
|
+
* 3 major enhancements:
|
3
8
|
* Removed some cruft
|
4
9
|
* Added ability to follow redirects automatically and turn that off (Alex Vollmer)
|
5
10
|
|
data/Manifest.txt
CHANGED
@@ -13,13 +13,14 @@ examples/twitter.rb
|
|
13
13
|
examples/whoismyrep.rb
|
14
14
|
httparty.gemspec
|
15
15
|
lib/httparty.rb
|
16
|
+
lib/httparty/request.rb
|
16
17
|
lib/httparty/version.rb
|
17
18
|
script/console
|
18
19
|
script/destroy
|
19
20
|
script/generate
|
20
21
|
script/txt2html
|
21
22
|
setup.rb
|
22
|
-
spec/
|
23
|
+
spec/httparty/request_spec.rb
|
23
24
|
spec/httparty_spec.rb
|
24
25
|
spec/spec.opts
|
25
26
|
spec/spec_helper.rb
|
data/examples/google.rb
CHANGED
data/httparty.gemspec
CHANGED
@@ -1,28 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
1
3
|
Gem::Specification.new do |s|
|
2
4
|
s.name = %q{httparty}
|
3
|
-
s.version = "0.1.
|
5
|
+
s.version = "0.1.5"
|
4
6
|
|
5
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
6
8
|
s.authors = ["John Nunemaker"]
|
7
|
-
s.date = %q{2008-11-
|
9
|
+
s.date = %q{2008-11-14}
|
8
10
|
s.description = %q{Makes http fun! Also, makes consuming restful web services dead easy.}
|
9
11
|
s.email = ["nunemaker@gmail.com"]
|
10
12
|
s.extra_rdoc_files = ["History.txt", "License.txt", "Manifest.txt", "PostInstall.txt", "README.txt"]
|
11
|
-
s.files = ["History.txt", "License.txt", "Manifest.txt", "PostInstall.txt", "README.txt", "Rakefile", "config/hoe.rb", "config/requirements.rb", "examples/aaws.rb", "examples/delicious.rb", "examples/google.rb", "examples/twitter.rb", "examples/whoismyrep.rb", "httparty.gemspec", "lib/httparty.rb", "lib/httparty/version.rb", "script/console", "script/destroy", "script/generate", "script/txt2html", "setup.rb", "spec/
|
13
|
+
s.files = ["History.txt", "License.txt", "Manifest.txt", "PostInstall.txt", "README.txt", "Rakefile", "config/hoe.rb", "config/requirements.rb", "examples/aaws.rb", "examples/delicious.rb", "examples/google.rb", "examples/twitter.rb", "examples/whoismyrep.rb", "httparty.gemspec", "lib/httparty.rb", "lib/httparty/request.rb", "lib/httparty/version.rb", "script/console", "script/destroy", "script/generate", "script/txt2html", "setup.rb", "spec/httparty/request_spec.rb", "spec/httparty_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/deployment.rake", "tasks/environment.rake", "tasks/website.rake", "website/css/common.css", "website/index.html"]
|
12
14
|
s.has_rdoc = true
|
13
15
|
s.homepage = %q{http://httparty.rubyforge.org}
|
14
16
|
s.post_install_message = %q{When you HTTParty, you must party hard!}
|
15
17
|
s.rdoc_options = ["--main", "README.txt"]
|
16
18
|
s.require_paths = ["lib"]
|
17
19
|
s.rubyforge_project = %q{httparty}
|
18
|
-
s.rubygems_version = %q{1.
|
20
|
+
s.rubygems_version = %q{1.3.1}
|
19
21
|
s.summary = %q{Makes http fun! Also, makes consuming restful web services dead easy.}
|
20
22
|
|
21
23
|
if s.respond_to? :specification_version then
|
22
24
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
23
25
|
s.specification_version = 2
|
24
26
|
|
25
|
-
if
|
27
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
26
28
|
s.add_runtime_dependency(%q<activesupport>, [">= 2.1"])
|
27
29
|
s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
|
28
30
|
else
|
data/lib/httparty.rb
CHANGED
@@ -8,162 +8,88 @@ require 'active_support'
|
|
8
8
|
directory = File.dirname(__FILE__)
|
9
9
|
$:.unshift(directory) unless $:.include?(directory) || $:.include?(File.expand_path(directory))
|
10
10
|
|
11
|
+
require 'httparty/request'
|
12
|
+
|
11
13
|
module HTTParty
|
12
14
|
class UnsupportedFormat < StandardError; end
|
13
15
|
class RedirectionTooDeep < StandardError; end
|
16
|
+
|
17
|
+
AllowedFormats = {:xml => 'text/xml', :json => 'application/json', :html => 'text/html'}
|
14
18
|
|
15
19
|
def self.included(base)
|
16
20
|
base.extend ClassMethods
|
17
21
|
end
|
18
22
|
|
19
|
-
|
20
|
-
|
21
|
-
|
23
|
+
module ClassMethods
|
24
|
+
def default_options
|
25
|
+
@@default_options ||= {}
|
26
|
+
end
|
27
|
+
|
22
28
|
#
|
23
29
|
# Set an http proxy
|
24
30
|
#
|
25
31
|
# class Twitter
|
26
32
|
# include HTTParty
|
27
|
-
# http_proxy http://myProxy, 1080
|
33
|
+
# http_proxy 'http://myProxy', 1080
|
28
34
|
# ....
|
29
35
|
def http_proxy(addr=nil, port = nil)
|
30
|
-
|
31
|
-
|
36
|
+
default_options[:http_proxyaddr] = addr
|
37
|
+
default_options[:http_proxyport] = port
|
32
38
|
end
|
33
39
|
|
34
|
-
def base_uri(
|
35
|
-
return
|
36
|
-
|
40
|
+
def base_uri(uri=nil)
|
41
|
+
return default_options[:base_uri] unless uri
|
42
|
+
default_options[:base_uri] = normalize_base_uri(uri)
|
37
43
|
end
|
38
|
-
|
39
|
-
# Warning: This is not thread safe most likely and
|
40
|
-
# only works if you use one set of credentials. I
|
41
|
-
# leave it because it is convenient on some occasions.
|
44
|
+
|
42
45
|
def basic_auth(u, p)
|
43
|
-
|
46
|
+
default_options[:basic_auth] = {:username => u, :password => p}
|
44
47
|
end
|
45
48
|
|
46
|
-
# Updates the default query string parameters
|
47
|
-
# that should be appended to each request.
|
48
49
|
def default_params(h={})
|
49
50
|
raise ArgumentError, 'Default params must be a hash' unless h.is_a?(Hash)
|
50
|
-
|
51
|
-
|
52
|
-
@default_params.merge!(h)
|
51
|
+
default_options[:default_params] ||= {}
|
52
|
+
default_options[:default_params].merge!(h)
|
53
53
|
end
|
54
54
|
|
55
55
|
def headers(h={})
|
56
56
|
raise ArgumentError, 'Headers must be a hash' unless h.is_a?(Hash)
|
57
|
-
|
58
|
-
|
59
|
-
@headers.merge!(h)
|
57
|
+
default_options[:headers] ||= {}
|
58
|
+
default_options[:headers].merge!(h)
|
60
59
|
end
|
61
60
|
|
62
61
|
def format(f)
|
63
62
|
raise UnsupportedFormat, "Must be one of: #{AllowedFormats.keys.join(', ')}" unless AllowedFormats.key?(f)
|
64
|
-
|
63
|
+
default_options[:format] = f
|
65
64
|
end
|
66
65
|
|
67
|
-
# TODO: spec out this
|
68
66
|
def get(path, options={})
|
69
|
-
|
67
|
+
perform_request Net::HTTP::Get, path, options
|
70
68
|
end
|
71
69
|
|
72
|
-
# TODO: spec out this
|
73
70
|
def post(path, options={})
|
74
|
-
|
71
|
+
perform_request Net::HTTP::Post, path, options
|
75
72
|
end
|
76
73
|
|
77
|
-
# TODO: spec out this
|
78
74
|
def put(path, options={})
|
79
|
-
|
75
|
+
perform_request Net::HTTP::Put, path, options
|
80
76
|
end
|
81
77
|
|
82
|
-
# TODO: spec out this
|
83
78
|
def delete(path, options={})
|
84
|
-
|
79
|
+
perform_request Net::HTTP::Delete, path, options
|
85
80
|
end
|
86
|
-
|
87
|
-
private
|
88
|
-
def http(uri) #:nodoc:
|
89
|
-
http = Net::HTTP.new(uri.host, uri.port, @http_proxyaddr, @http_proxyport)
|
90
|
-
http.use_ssl = (uri.port == 443)
|
91
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
92
|
-
http
|
93
|
-
end
|
94
|
-
|
95
|
-
# FIXME: this method is doing way to much and needs to be split up
|
96
|
-
# options can be any or all of:
|
97
|
-
# query => hash of keys/values or a query string (foo=bar&baz=poo)
|
98
|
-
# body => hash of keys/values or a query string (foo=bar&baz=poo)
|
99
|
-
# headers => hash of headers to send request with
|
100
|
-
# basic_auth => :username and :password to use as basic http authentication (overrides @auth class instance variable)
|
101
|
-
# Raises exception Net::XXX (http error code) if an http error occured
|
102
|
-
def send_request(method, path, options={}) #:nodoc:
|
103
|
-
options = {:limit => 5}.merge(options)
|
104
|
-
options[:limit] = 0 if options.delete(:no_follow)
|
105
|
-
|
106
|
-
raise HTTParty::RedirectionTooDeep, 'HTTP redirects too deep' if options[:limit].to_i <= 0
|
107
|
-
raise ArgumentError, 'only get, post, put and delete methods are supported' unless %w[get post put delete].include?(method.to_s)
|
108
|
-
raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].is_a?(Hash)
|
109
|
-
raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].is_a?(Hash)
|
110
|
-
|
111
|
-
path = URI.parse(path)
|
112
|
-
uri = path.relative? ? URI.parse("#{base_uri}#{path}") : path
|
113
|
-
existing_query = uri.query ? "#{uri.query}&" : ''
|
114
|
-
uri.query = if options[:query].blank?
|
115
|
-
existing_query + default_params.to_query
|
116
|
-
else
|
117
|
-
existing_query + (options[:query].is_a?(Hash) ? default_params.merge(options[:query]).to_query : options[:query])
|
118
|
-
end
|
119
|
-
|
120
|
-
klass = Net::HTTP.const_get method.to_s.downcase.capitalize
|
121
|
-
request = klass.new(uri.request_uri)
|
122
|
-
request.body = options[:body].is_a?(Hash) ? options[:body].to_query : options[:body] unless options[:body].blank?
|
123
|
-
basic_auth = options.delete(:basic_auth) || @auth
|
124
|
-
request.initialize_http_header headers.merge(options[:headers] || {})
|
125
|
-
request.basic_auth(basic_auth[:username], basic_auth[:password]) if basic_auth
|
126
|
-
response = http(uri).request(request)
|
127
|
-
@format ||= format_from_mimetype(response['content-type'])
|
128
|
-
|
129
|
-
case response
|
130
|
-
when Net::HTTPSuccess
|
131
|
-
parse_response(response.body)
|
132
|
-
when Net::HTTPRedirection
|
133
|
-
options[:limit] -= 1
|
134
|
-
send_request(method, response['location'], options)
|
135
|
-
else
|
136
|
-
response.instance_eval { class << self; attr_accessor :body_parsed; end }
|
137
|
-
begin; response.body_parsed = parse_response(response.body); rescue; end
|
138
|
-
response.error! # raises exception corresponding to http error Net::XXX
|
139
|
-
end
|
140
81
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
return nil if body.nil? or body.empty?
|
145
|
-
case @format
|
146
|
-
when :xml
|
147
|
-
Hash.from_xml(body)
|
148
|
-
when :json
|
149
|
-
ActiveSupport::JSON.decode(body)
|
150
|
-
else
|
151
|
-
body
|
152
|
-
end
|
82
|
+
private
|
83
|
+
def perform_request(http_method, path, options) #:nodoc:
|
84
|
+
Request.new(http_method, path, default_options.merge(options)).perform
|
153
85
|
end
|
154
86
|
|
155
|
-
# Makes it so uri is sure to parse stuff like google.com
|
87
|
+
# Makes it so uri is sure to parse stuff like google.com without the http
|
156
88
|
def normalize_base_uri(url) #:nodoc:
|
157
89
|
use_ssl = (url =~ /^https/) || url.include?(':443')
|
158
90
|
url.chop! if url.ends_with?('/')
|
159
91
|
url.gsub!(/^https?:\/\//i, '')
|
160
92
|
"http#{'s' if use_ssl}://#{url}"
|
161
93
|
end
|
162
|
-
|
163
|
-
# Uses the HTTP Content-Type header to determine the format of the response
|
164
|
-
# It compares the MIME type returned to the types stored in the AllowedFormats hash
|
165
|
-
def format_from_mimetype(mimetype) #:nodoc:
|
166
|
-
AllowedFormats.each { |k, v| return k if mimetype.include?(v) }
|
167
|
-
end
|
168
94
|
end
|
169
|
-
end
|
95
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module HTTParty
|
2
|
+
class Request
|
3
|
+
SupportedHTTPMethods = [Net::HTTP::Get, Net::HTTP::Post, Net::HTTP::Put, Net::HTTP::Delete]
|
4
|
+
|
5
|
+
attr_accessor :http_method, :path, :options
|
6
|
+
|
7
|
+
def initialize(http_method, path, options={})
|
8
|
+
self.http_method = http_method
|
9
|
+
self.path = path
|
10
|
+
self.options = {
|
11
|
+
:limit => options.delete(:no_follow) ? 0 : 5,
|
12
|
+
:default_params => {},
|
13
|
+
}.merge(options.dup)
|
14
|
+
end
|
15
|
+
|
16
|
+
def path=(uri)
|
17
|
+
@path = URI.parse(uri)
|
18
|
+
end
|
19
|
+
|
20
|
+
def uri
|
21
|
+
uri = path.relative? ? URI.parse("#{options[:base_uri]}#{path}") : path
|
22
|
+
uri.query = query_string(uri)
|
23
|
+
uri
|
24
|
+
end
|
25
|
+
|
26
|
+
def perform
|
27
|
+
validate!
|
28
|
+
handle_response!(get_response(uri))
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def http(uri) #:nodoc:
|
33
|
+
http = Net::HTTP.new(uri.host, uri.port, options[:http_proxyaddr], options[:http_proxyport])
|
34
|
+
http.use_ssl = (uri.port == 443)
|
35
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
36
|
+
http
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_response(uri) #:nodoc:
|
40
|
+
request = http_method.new(uri.request_uri)
|
41
|
+
request.body = options[:body].is_a?(Hash) ? options[:body].to_query : options[:body] unless options[:body].blank?
|
42
|
+
request.initialize_http_header options[:headers]
|
43
|
+
request.basic_auth(options[:basic_auth][:username], options[:basic_auth][:password]) if options[:basic_auth]
|
44
|
+
response = http(uri).request(request)
|
45
|
+
options[:format] ||= format_from_mimetype(response['content-type'])
|
46
|
+
response
|
47
|
+
end
|
48
|
+
|
49
|
+
def query_string(uri) #:nodoc:
|
50
|
+
query_string_parts = []
|
51
|
+
query_string_parts << uri.query unless uri.query.blank?
|
52
|
+
|
53
|
+
if options[:query].is_a?(Hash)
|
54
|
+
query_string_parts << options[:default_params].merge(options[:query]).to_query
|
55
|
+
else
|
56
|
+
query_string_parts << options[:default_params].to_query unless options[:default_params].blank?
|
57
|
+
query_string_parts << options[:query] unless options[:query].blank?
|
58
|
+
end
|
59
|
+
|
60
|
+
query_string_parts.size > 0 ? query_string_parts.join('&') : nil
|
61
|
+
end
|
62
|
+
|
63
|
+
# Raises exception Net::XXX (http error code) if an http error occured
|
64
|
+
def handle_response!(response) #:nodoc:
|
65
|
+
case response
|
66
|
+
when Net::HTTPSuccess
|
67
|
+
parse_response(response.body)
|
68
|
+
when Net::HTTPRedirection
|
69
|
+
options[:limit] -= 1
|
70
|
+
self.path = response['location']
|
71
|
+
perform
|
72
|
+
else
|
73
|
+
response.instance_eval { class << self; attr_accessor :body_parsed; end }
|
74
|
+
begin; response.body_parsed = parse_response(response.body); rescue; end
|
75
|
+
response.error! # raises exception corresponding to http error Net::XXX
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def parse_response(body) #:nodoc:
|
80
|
+
return nil if body.nil? or body.empty?
|
81
|
+
case options[:format]
|
82
|
+
when :xml
|
83
|
+
Hash.from_xml(body)
|
84
|
+
when :json
|
85
|
+
ActiveSupport::JSON.decode(body)
|
86
|
+
else
|
87
|
+
body
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Uses the HTTP Content-Type header to determine the format of the response
|
92
|
+
# It compares the MIME type returned to the types stored in the AllowedFormats hash
|
93
|
+
def format_from_mimetype(mimetype) #:nodoc:
|
94
|
+
AllowedFormats.each { |k, v| return k if mimetype.include?(v) }
|
95
|
+
end
|
96
|
+
|
97
|
+
def validate! #:nodoc:
|
98
|
+
raise HTTParty::RedirectionTooDeep, 'HTTP redirects too deep' if options[:limit].to_i <= 0
|
99
|
+
raise ArgumentError, 'only get, post, put and delete methods are supported' unless SupportedHTTPMethods.include?(http_method)
|
100
|
+
raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].is_a?(Hash)
|
101
|
+
raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].is_a?(Hash)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
data/lib/httparty/version.rb
CHANGED
@@ -0,0 +1,107 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe HTTParty::Request do
|
4
|
+
before do
|
5
|
+
@request = HTTParty::Request.new(Net::HTTP::Get, 'http://api.foo.com/v1', :format => :xml)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'http' do
|
9
|
+
it "should use ssl for port 443" do
|
10
|
+
@request.send(:http, URI.parse('https://api.foo.com/v1:443')).use_ssl?.should == true
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should not use ssl for port 80' do
|
14
|
+
@request.send(:http, URI.parse('http://foobar.com')).use_ssl?.should == false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'parsing responses' do
|
19
|
+
it 'should handle xml automatically' do
|
20
|
+
xml = %q[<books><book><id>1234</id><name>Foo Bar!</name></book></books>]
|
21
|
+
@request.options[:format] = :xml
|
22
|
+
@request.send(:parse_response, xml).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should handle json automatically' do
|
26
|
+
json = %q[{"books": {"book": {"name": "Foo Bar!", "id": "1234"}}}]
|
27
|
+
@request.options[:format] = :json
|
28
|
+
@request.send(:parse_response, json).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should not attempt to parse empty responses" do
|
33
|
+
http = Net::HTTP.new('localhost', 80)
|
34
|
+
@request.stub!(:http).and_return(http)
|
35
|
+
response = Net::HTTPNoContent.new("1.1", 204, "No content for you")
|
36
|
+
response.stub!(:body).and_return(nil)
|
37
|
+
http.stub!(:request).and_return(response)
|
38
|
+
|
39
|
+
@request.options[:format] = :xml
|
40
|
+
@request.perform.should be_nil
|
41
|
+
|
42
|
+
response.stub!(:body).and_return("")
|
43
|
+
@request.perform.should be_nil
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "that respond with redirects" do
|
47
|
+
def setup_redirect
|
48
|
+
@http = Net::HTTP.new('localhost', 80)
|
49
|
+
@request.stub!(:http).and_return(@http)
|
50
|
+
@request.stub!(:uri).and_return(URI.parse("http://foo.com/foobar"))
|
51
|
+
@redirect = Net::HTTPFound.new("1.1", 302, "")
|
52
|
+
@redirect['location'] = '/foo'
|
53
|
+
end
|
54
|
+
|
55
|
+
def setup_ok_response
|
56
|
+
@ok = Net::HTTPOK.new("1.1", 200, "Content for you")
|
57
|
+
@ok.stub!(:body).and_return({"foo" => "bar"}.to_xml)
|
58
|
+
@http.should_receive(:request).and_return(@redirect, @ok)
|
59
|
+
@request.options[:format] = :xml
|
60
|
+
end
|
61
|
+
|
62
|
+
def setup_redirect_response
|
63
|
+
@http.stub!(:request).and_return(@redirect)
|
64
|
+
end
|
65
|
+
|
66
|
+
def setup_successful_redirect
|
67
|
+
setup_redirect
|
68
|
+
setup_ok_response
|
69
|
+
end
|
70
|
+
|
71
|
+
def setup_infinite_redirect
|
72
|
+
setup_redirect
|
73
|
+
setup_redirect_response
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should handle redirects for GET transparently" do
|
77
|
+
setup_successful_redirect
|
78
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should handle redirects for POST transparently" do
|
82
|
+
setup_successful_redirect
|
83
|
+
@request.http_method = Net::HTTP::Post
|
84
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should handle redirects for DELETE transparently" do
|
88
|
+
setup_successful_redirect
|
89
|
+
@request.http_method = Net::HTTP::Delete
|
90
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should handle redirects for PUT transparently" do
|
94
|
+
setup_successful_redirect
|
95
|
+
@request.http_method = Net::HTTP::Put
|
96
|
+
@request.perform.should == {"hash" => {"foo" => "bar"}}
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should prevent infinite loops" do
|
100
|
+
setup_infinite_redirect
|
101
|
+
|
102
|
+
lambda do
|
103
|
+
@request.perform
|
104
|
+
end.should raise_error(HTTParty::RedirectionTooDeep)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
data/spec/httparty_spec.rb
CHANGED
@@ -13,6 +13,10 @@ end
|
|
13
13
|
describe HTTParty do
|
14
14
|
|
15
15
|
describe "base uri" do
|
16
|
+
before do
|
17
|
+
Foo.base_uri('api.foo.com/v1')
|
18
|
+
end
|
19
|
+
|
16
20
|
it "should have reader" do
|
17
21
|
Foo.base_uri.should == 'http://api.foo.com/v1'
|
18
22
|
end
|
@@ -65,19 +69,19 @@ describe HTTParty do
|
|
65
69
|
describe "basic http authentication" do
|
66
70
|
it "should work" do
|
67
71
|
Foo.basic_auth 'foobar', 'secret'
|
68
|
-
Foo.
|
72
|
+
Foo.default_options[:basic_auth].should == {:username => 'foobar', :password => 'secret'}
|
69
73
|
end
|
70
74
|
end
|
71
75
|
|
72
76
|
describe "format" do
|
73
77
|
it "should allow xml" do
|
74
78
|
Foo.format :xml
|
75
|
-
Foo.
|
79
|
+
Foo.default_options[:format].should == :xml
|
76
80
|
end
|
77
81
|
|
78
82
|
it "should allow json" do
|
79
83
|
Foo.format :json
|
80
|
-
Foo.
|
84
|
+
Foo.default_options[:format].should == :json
|
81
85
|
end
|
82
86
|
|
83
87
|
it 'should not allow funky format' do
|
@@ -86,136 +90,31 @@ describe HTTParty do
|
|
86
90
|
end.should raise_error(HTTParty::UnsupportedFormat)
|
87
91
|
end
|
88
92
|
end
|
89
|
-
|
90
|
-
describe
|
91
|
-
|
92
|
-
|
93
|
-
end
|
94
|
-
|
95
|
-
it 'should not use ssl for port 80' do
|
96
|
-
Foo.send(:http, URI.parse('http://foobar.com')).use_ssl?.should == false
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
describe 'parsing responses' do
|
101
|
-
it 'should handle xml automatically' do
|
102
|
-
xml = %q[<books><book><id>1234</id><name>Foo Bar!</name></book></books>]
|
103
|
-
Foo.format :xml
|
104
|
-
Foo.send(:parse_response, xml).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'should handle json automatically' do
|
108
|
-
json = %q[{"books": {"book": {"name": "Foo Bar!", "id": "1234"}}}]
|
109
|
-
Foo.format :json
|
110
|
-
Foo.send(:parse_response, json).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
describe "sending requests" do
|
115
|
-
it "should not work with request method other than get, post, put, delete" do
|
116
|
-
lambda do
|
117
|
-
Foo.send(:send_request, 'foo', '/foo')
|
118
|
-
end.should raise_error(ArgumentError)
|
119
|
-
end
|
120
|
-
|
121
|
-
it 'should require that :headers is a hash if present' do
|
93
|
+
|
94
|
+
describe "with explicit override of automatic redirect handling" do
|
95
|
+
|
96
|
+
it "should fail with redirected GET" do
|
122
97
|
lambda do
|
123
|
-
Foo.
|
124
|
-
end.should raise_error(
|
98
|
+
Foo.get('/foo', :no_follow => true)
|
99
|
+
end.should raise_error(HTTParty::RedirectionTooDeep)
|
125
100
|
end
|
126
|
-
|
127
|
-
it
|
101
|
+
|
102
|
+
it "should fail with redirected POST" do
|
128
103
|
lambda do
|
129
|
-
Foo.
|
130
|
-
end.should raise_error(
|
104
|
+
Foo.post('/foo', :no_follow => true)
|
105
|
+
end.should raise_error(HTTParty::RedirectionTooDeep)
|
131
106
|
end
|
132
107
|
|
133
|
-
it "should
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
response.stub!(:body).and_return(nil)
|
138
|
-
http.stub!(:request).and_return(response)
|
139
|
-
|
140
|
-
Foo.headers.clear # clear out bogus settings from other specs
|
141
|
-
Foo.format :xml
|
142
|
-
Foo.send(:send_request, 'get', '/bar').should be_nil
|
143
|
-
|
144
|
-
response.stub!(:body).and_return("")
|
145
|
-
Foo.send(:send_request, 'get', 'bar').should be_nil
|
108
|
+
it "should fail with redirected DELETE" do
|
109
|
+
lambda do
|
110
|
+
Foo.delete('/foo', :no_follow => true)
|
111
|
+
end.should raise_error(HTTParty::RedirectionTooDeep)
|
146
112
|
end
|
147
113
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
@redirect = Net::HTTPFound.new("1.1", 302, "")
|
153
|
-
@redirect.stub!(:[]).with('location').and_return('/foo')
|
154
|
-
@ok = Net::HTTPOK.new("1.1", 200, "Content for you")
|
155
|
-
@ok.stub!(:body).and_return({"foo" => "bar"}.to_xml)
|
156
|
-
@http.should_receive(:request).and_return(@redirect, @ok)
|
157
|
-
Foo.headers.clear
|
158
|
-
Foo.format :xml
|
159
|
-
end
|
160
|
-
|
161
|
-
it "should handle redirects for GET transparently" do
|
162
|
-
setup_http
|
163
|
-
Foo.get('/foo/').should == {"hash" => {"foo" => "bar"}}
|
164
|
-
end
|
165
|
-
|
166
|
-
it "should handle redirects for POST transparently" do
|
167
|
-
setup_http
|
168
|
-
Foo.post('/foo/', {:foo => :bar}).should == {"hash" => {"foo" => "bar"}}
|
169
|
-
end
|
170
|
-
|
171
|
-
it "should handle redirects for DELETE transparently" do
|
172
|
-
setup_http
|
173
|
-
Foo.delete('/foo/').should == {"hash" => {"foo" => "bar"}}
|
174
|
-
end
|
175
|
-
|
176
|
-
it "should handle redirects for PUT transparently" do
|
177
|
-
setup_http
|
178
|
-
Foo.put('/foo/').should == {"hash" => {"foo" => "bar"}}
|
179
|
-
end
|
180
|
-
|
181
|
-
it "should prevent infinite loops" do
|
182
|
-
http = Net::HTTP.new('localhost', 80)
|
183
|
-
Foo.stub!(:http).and_return(http)
|
184
|
-
redirect = Net::HTTPFound.new("1.1", "302", "Look, over there!")
|
185
|
-
redirect.stub!(:[]).with('location').and_return('/foo')
|
186
|
-
http.stub!(:request).and_return(redirect)
|
187
|
-
|
188
|
-
lambda do
|
189
|
-
Foo.send(:send_request, 'get', '/foo')
|
190
|
-
end.should raise_error(HTTParty::RedirectionTooDeep)
|
191
|
-
end
|
192
|
-
|
193
|
-
describe "with explicit override of automatic redirect handling" do
|
194
|
-
|
195
|
-
it "should fail with redirected GET" do
|
196
|
-
lambda do
|
197
|
-
Foo.get('/foo', :no_follow => true)
|
198
|
-
end.should raise_error(HTTParty::RedirectionTooDeep)
|
199
|
-
end
|
200
|
-
|
201
|
-
it "should fail with redirected POST" do
|
202
|
-
lambda do
|
203
|
-
Foo.post('/foo', :no_follow => true)
|
204
|
-
end.should raise_error(HTTParty::RedirectionTooDeep)
|
205
|
-
end
|
206
|
-
|
207
|
-
it "should fail with redirected DELETE" do
|
208
|
-
lambda do
|
209
|
-
Foo.delete('/foo', :no_follow => true)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
it "should fail with redirected PUT" do
|
214
|
-
lambda do
|
215
|
-
Foo.put('/foo', :no_follow => true)
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
114
|
+
it "should fail with redirected PUT" do
|
115
|
+
lambda do
|
116
|
+
Foo.put('/foo', :no_follow => true)
|
117
|
+
end.should raise_error(HTTParty::RedirectionTooDeep)
|
219
118
|
end
|
220
119
|
end
|
221
|
-
end
|
120
|
+
end
|
data/spec/spec.opts
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jnunemaker-httparty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Nunemaker
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-11-
|
12
|
+
date: 2008-11-14 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -59,13 +59,14 @@ files:
|
|
59
59
|
- examples/whoismyrep.rb
|
60
60
|
- httparty.gemspec
|
61
61
|
- lib/httparty.rb
|
62
|
+
- lib/httparty/request.rb
|
62
63
|
- lib/httparty/version.rb
|
63
64
|
- script/console
|
64
65
|
- script/destroy
|
65
66
|
- script/generate
|
66
67
|
- script/txt2html
|
67
68
|
- setup.rb
|
68
|
-
- spec/
|
69
|
+
- spec/httparty/request_spec.rb
|
69
70
|
- spec/httparty_spec.rb
|
70
71
|
- spec/spec.opts
|
71
72
|
- spec/spec_helper.rb
|