httparty 0.1.3 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of httparty might be problematic. Click here for more details.
- data/History.txt +10 -0
- data/Manifest.txt +3 -3
- data/README.txt +14 -0
- data/Rakefile +8 -1
- data/examples/google.rb +16 -0
- data/httparty.gemspec +10 -5
- data/lib/httparty.rb +39 -108
- 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 +36 -61
- data/spec/spec.opts +3 -1
- metadata +16 -6
- data/lib/httparty/core_ext.rb +0 -2
- data/lib/httparty/core_ext/hash.rb +0 -21
- data/spec/hash_spec.rb +0 -11
data/History.txt
CHANGED
@@ -1,3 +1,13 @@
|
|
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
|
+
|
6
|
+
== 0.1.4 2008-11-08
|
7
|
+
* 3 major enhancements:
|
8
|
+
* Removed some cruft
|
9
|
+
* Added ability to follow redirects automatically and turn that off (Alex Vollmer)
|
10
|
+
|
1
11
|
== 0.1.3 2008-08-22
|
2
12
|
|
3
13
|
* 3 major enhancements:
|
data/Manifest.txt
CHANGED
@@ -8,19 +8,19 @@ config/hoe.rb
|
|
8
8
|
config/requirements.rb
|
9
9
|
examples/aaws.rb
|
10
10
|
examples/delicious.rb
|
11
|
+
examples/google.rb
|
11
12
|
examples/twitter.rb
|
12
13
|
examples/whoismyrep.rb
|
13
14
|
httparty.gemspec
|
14
15
|
lib/httparty.rb
|
15
|
-
lib/httparty/
|
16
|
-
lib/httparty/core_ext/hash.rb
|
16
|
+
lib/httparty/request.rb
|
17
17
|
lib/httparty/version.rb
|
18
18
|
script/console
|
19
19
|
script/destroy
|
20
20
|
script/generate
|
21
21
|
script/txt2html
|
22
22
|
setup.rb
|
23
|
-
spec/
|
23
|
+
spec/httparty/request_spec.rb
|
24
24
|
spec/httparty_spec.rb
|
25
25
|
spec/spec.opts
|
26
26
|
spec/spec_helper.rb
|
data/README.txt
CHANGED
@@ -43,6 +43,20 @@ That works and all but what if you don't want to embed your username and passwor
|
|
43
43
|
|
44
44
|
Twitter.new('username', 'password').post("It's an HTTParty and everyone is invited!")
|
45
45
|
|
46
|
+
=== REQUEST OPTIONS
|
47
|
+
|
48
|
+
Each of the HTTP method (get, post, put and delete) each take a hash of options.
|
49
|
+
The following keys can be specified in the options:
|
50
|
+
|
51
|
+
headers:: A <tt>Hash</tt> of header key/value pairs
|
52
|
+
query:: A <tt>Hash</tt> of query key/value pairs
|
53
|
+
body:: The body of the request. If it's a <tt>Hash</tt>, it is
|
54
|
+
converted into query-string format, otherwise it is sent
|
55
|
+
as-is.
|
56
|
+
basic_auth:: A <tt>Hash</tt> containing keys for <tt>:username</tt> and
|
57
|
+
<tt>:password</tt>.
|
58
|
+
no_follow:: Turns off automatic redirect following
|
59
|
+
|
46
60
|
== REQUIREMENTS:
|
47
61
|
|
48
62
|
* Active Support >= 2.1
|
data/Rakefile
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
require 'config/requirements'
|
2
2
|
require 'config/hoe' # setup Hoe + all gem configuration
|
3
|
+
require "spec/rake/spectask"
|
3
4
|
|
4
|
-
Dir['tasks/**/*.rake'].each { |rake| load rake }
|
5
|
+
Dir['tasks/**/*.rake'].each { |rake| load rake }
|
6
|
+
|
7
|
+
task :default => :spec
|
8
|
+
|
9
|
+
Spec::Rake::SpecTask.new do |t|
|
10
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
11
|
+
end
|
data/examples/google.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require File.join(dir, 'httparty')
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
class Google
|
6
|
+
include HTTParty
|
7
|
+
format :html
|
8
|
+
end
|
9
|
+
|
10
|
+
# google.com redirects to www.google.com so this is live test for redirection
|
11
|
+
pp Google.get('http://google.com')
|
12
|
+
|
13
|
+
puts '', '*'*70, ''
|
14
|
+
|
15
|
+
# check that ssl is requesting right
|
16
|
+
pp Google.get('https://www.google.com')
|
data/httparty.gemspec
CHANGED
@@ -1,33 +1,38 @@
|
|
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-
|
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/
|
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"])
|
29
|
+
s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
|
27
30
|
else
|
28
31
|
s.add_dependency(%q<activesupport>, [">= 2.1"])
|
32
|
+
s.add_dependency(%q<hoe>, [">= 1.8.0"])
|
29
33
|
end
|
30
34
|
else
|
31
35
|
s.add_dependency(%q<activesupport>, [">= 2.1"])
|
36
|
+
s.add_dependency(%q<hoe>, [">= 1.8.0"])
|
32
37
|
end
|
33
38
|
end
|
data/lib/httparty.rb
CHANGED
@@ -5,160 +5,91 @@ require 'ostruct'
|
|
5
5
|
require 'rubygems'
|
6
6
|
require 'active_support'
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
directory = File.dirname(__FILE__)
|
9
|
+
$:.unshift(directory) unless $:.include?(directory) || $:.include?(File.expand_path(directory))
|
10
|
+
|
11
|
+
require 'httparty/request'
|
10
12
|
|
11
|
-
dir = File.expand_path(File.join(File.dirname(__FILE__), 'httparty'))
|
12
|
-
require dir + '/core_ext'
|
13
|
-
|
14
13
|
module HTTParty
|
15
14
|
class UnsupportedFormat < StandardError; end
|
15
|
+
class RedirectionTooDeep < StandardError; end
|
16
|
+
|
17
|
+
AllowedFormats = {:xml => 'text/xml', :json => 'application/json', :html => 'text/html'}
|
16
18
|
|
17
19
|
def self.included(base)
|
18
20
|
base.extend ClassMethods
|
19
21
|
end
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
23
|
+
module ClassMethods
|
24
|
+
def default_options
|
25
|
+
@@default_options ||= {}
|
26
|
+
end
|
27
|
+
|
24
28
|
#
|
25
29
|
# Set an http proxy
|
26
30
|
#
|
27
31
|
# class Twitter
|
28
32
|
# include HTTParty
|
29
|
-
# http_proxy http://myProxy, 1080
|
33
|
+
# http_proxy 'http://myProxy', 1080
|
30
34
|
# ....
|
31
35
|
def http_proxy(addr=nil, port = nil)
|
32
|
-
|
33
|
-
|
36
|
+
default_options[:http_proxyaddr] = addr
|
37
|
+
default_options[:http_proxyport] = port
|
34
38
|
end
|
35
39
|
|
36
|
-
def base_uri(
|
37
|
-
return
|
38
|
-
|
39
|
-
base_uri = base_uri.ends_with?('/') ? base_uri.chop : base_uri
|
40
|
-
@base_uri = normalize_base_uri(base_uri)
|
40
|
+
def base_uri(uri=nil)
|
41
|
+
return default_options[:base_uri] unless uri
|
42
|
+
default_options[:base_uri] = normalize_base_uri(uri)
|
41
43
|
end
|
42
|
-
|
43
|
-
# Warning: This is not thread safe most likely and
|
44
|
-
# only works if you use one set of credentials. I
|
45
|
-
# leave it because it is convenient on some occasions.
|
44
|
+
|
46
45
|
def basic_auth(u, p)
|
47
|
-
|
46
|
+
default_options[:basic_auth] = {:username => u, :password => p}
|
48
47
|
end
|
49
48
|
|
50
|
-
# Updates the default query string parameters
|
51
|
-
# that should be appended to each request.
|
52
49
|
def default_params(h={})
|
53
50
|
raise ArgumentError, 'Default params must be a hash' unless h.is_a?(Hash)
|
54
|
-
|
55
|
-
|
56
|
-
@default_params.merge!(h)
|
51
|
+
default_options[:default_params] ||= {}
|
52
|
+
default_options[:default_params].merge!(h)
|
57
53
|
end
|
58
54
|
|
59
55
|
def headers(h={})
|
60
56
|
raise ArgumentError, 'Headers must be a hash' unless h.is_a?(Hash)
|
61
|
-
|
62
|
-
|
63
|
-
@headers.merge!(h)
|
57
|
+
default_options[:headers] ||= {}
|
58
|
+
default_options[:headers].merge!(h)
|
64
59
|
end
|
65
60
|
|
66
61
|
def format(f)
|
67
62
|
raise UnsupportedFormat, "Must be one of: #{AllowedFormats.keys.join(', ')}" unless AllowedFormats.key?(f)
|
68
|
-
|
63
|
+
default_options[:format] = f
|
69
64
|
end
|
70
65
|
|
71
|
-
# TODO: spec out this
|
72
66
|
def get(path, options={})
|
73
|
-
|
67
|
+
perform_request Net::HTTP::Get, path, options
|
74
68
|
end
|
75
69
|
|
76
|
-
# TODO: spec out this
|
77
70
|
def post(path, options={})
|
78
|
-
|
71
|
+
perform_request Net::HTTP::Post, path, options
|
79
72
|
end
|
80
73
|
|
81
|
-
# TODO: spec out this
|
82
74
|
def put(path, options={})
|
83
|
-
|
75
|
+
perform_request Net::HTTP::Put, path, options
|
84
76
|
end
|
85
77
|
|
86
|
-
# TODO: spec out this
|
87
78
|
def delete(path, options={})
|
88
|
-
|
79
|
+
perform_request Net::HTTP::Delete, path, options
|
89
80
|
end
|
90
|
-
|
91
|
-
private
|
92
|
-
def http(uri) #:nodoc:
|
93
|
-
if @http.blank?
|
94
|
-
@http = Net::HTTP.new(uri.host, uri.port, @http_proxyaddr, @http_proxyport)
|
95
|
-
@http.use_ssl = (uri.port == 443)
|
96
|
-
# so we can avoid ssl warnings
|
97
|
-
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
98
|
-
end
|
99
|
-
@http
|
100
|
-
end
|
101
|
-
|
102
|
-
# FIXME: this method is doing way to much and needs to be split up
|
103
|
-
# options can be any or all of:
|
104
|
-
# query => hash of keys/values or a query string (foo=bar&baz=poo)
|
105
|
-
# body => hash of keys/values or a query string (foo=bar&baz=poo)
|
106
|
-
# headers => hash of headers to send request with
|
107
|
-
# basic_auth => :username and :password to use as basic http authentication (overrides @auth class instance variable)
|
108
|
-
# Raises exception Net::XXX (http error code) if an http error occured
|
109
|
-
def send_request(method, path, options={}) #:nodoc:
|
110
|
-
raise ArgumentError, 'only get, post, put and delete methods are supported' unless %w[get post put delete].include?(method.to_s)
|
111
|
-
raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].is_a?(Hash)
|
112
|
-
raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].is_a?(Hash)
|
113
|
-
uri = URI.parse("#{base_uri}#{path}")
|
114
|
-
existing_query = uri.query ? "#{uri.query}&" : ''
|
115
|
-
uri.query = if options[:query].blank?
|
116
|
-
existing_query + default_params.to_query
|
117
|
-
else
|
118
|
-
existing_query + (options[:query].is_a?(Hash) ? default_params.merge(options[:query]).to_query : options[:query])
|
119
|
-
end
|
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
|
-
# note to self: self, do not put basic auth above headers because it removes basic auth
|
126
|
-
request.basic_auth(basic_auth[:username], basic_auth[:password]) if basic_auth
|
127
|
-
response = http(uri).request(request)
|
128
|
-
@format ||= format_from_mimetype(response['content-type'])
|
129
|
-
|
130
|
-
case response
|
131
|
-
when Net::HTTPSuccess
|
132
|
-
parse_response(response.body)
|
133
|
-
else
|
134
|
-
response.instance_eval { class << self; attr_accessor :body_parsed; end }
|
135
|
-
begin; response.body_parsed = parse_response(response.body); rescue; end
|
136
|
-
response.error! # raises exception corresponding to http error Net::XXX
|
137
|
-
end
|
138
81
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
case @format
|
143
|
-
when :xml
|
144
|
-
Hash.from_xml(body)
|
145
|
-
when :json
|
146
|
-
ActiveSupport::JSON.decode(body)
|
147
|
-
else
|
148
|
-
# just return the response if no format
|
149
|
-
body
|
150
|
-
end
|
82
|
+
private
|
83
|
+
def perform_request(http_method, path, options) #:nodoc:
|
84
|
+
Request.new(http_method, path, default_options.merge(options)).perform
|
151
85
|
end
|
152
86
|
|
153
|
-
# Makes it so uri is sure to parse stuff like google.com
|
154
|
-
def normalize_base_uri(
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
# It compares the MIME type returned to the types stored in the AllowedFormats hash
|
160
|
-
def format_from_mimetype(mimetype) #:nodoc:
|
161
|
-
AllowedFormats.each { |k, v| return k if mimetype.include?(v) }
|
87
|
+
# Makes it so uri is sure to parse stuff like google.com without the http
|
88
|
+
def normalize_base_uri(url) #:nodoc:
|
89
|
+
use_ssl = (url =~ /^https/) || url.include?(':443')
|
90
|
+
url.chop! if url.ends_with?('/')
|
91
|
+
url.gsub!(/^https?:\/\//i, '')
|
92
|
+
"http#{'s' if use_ssl}://#{url}"
|
162
93
|
end
|
163
94
|
end
|
164
|
-
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,11 +13,15 @@ end
|
|
13
13
|
describe HTTParty do
|
14
14
|
|
15
15
|
describe "base uri" do
|
16
|
-
|
16
|
+
before do
|
17
|
+
Foo.base_uri('api.foo.com/v1')
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should have reader" do
|
17
21
|
Foo.base_uri.should == 'http://api.foo.com/v1'
|
18
22
|
end
|
19
23
|
|
20
|
-
it 'should
|
24
|
+
it 'should have writer' do
|
21
25
|
Foo.base_uri('http://api.foobar.com')
|
22
26
|
Foo.base_uri.should == 'http://api.foobar.com'
|
23
27
|
end
|
@@ -28,7 +32,13 @@ describe HTTParty do
|
|
28
32
|
end
|
29
33
|
|
30
34
|
it "should add https if not present for ssl requests" do
|
31
|
-
|
35
|
+
Foo.base_uri('api.foo.com/v1:443')
|
36
|
+
Foo.base_uri.should == 'https://api.foo.com/v1:443'
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should not remove https for ssl requests" do
|
40
|
+
Foo.base_uri('https://api.foo.com/v1:443')
|
41
|
+
Foo.base_uri.should == 'https://api.foo.com/v1:443'
|
32
42
|
end
|
33
43
|
end
|
34
44
|
|
@@ -59,19 +69,19 @@ describe HTTParty do
|
|
59
69
|
describe "basic http authentication" do
|
60
70
|
it "should work" do
|
61
71
|
Foo.basic_auth 'foobar', 'secret'
|
62
|
-
Foo.
|
72
|
+
Foo.default_options[:basic_auth].should == {:username => 'foobar', :password => 'secret'}
|
63
73
|
end
|
64
74
|
end
|
65
75
|
|
66
76
|
describe "format" do
|
67
77
|
it "should allow xml" do
|
68
78
|
Foo.format :xml
|
69
|
-
Foo.
|
79
|
+
Foo.default_options[:format].should == :xml
|
70
80
|
end
|
71
81
|
|
72
82
|
it "should allow json" do
|
73
83
|
Foo.format :json
|
74
|
-
Foo.
|
84
|
+
Foo.default_options[:format].should == :json
|
75
85
|
end
|
76
86
|
|
77
87
|
it 'should not allow funky format' do
|
@@ -80,66 +90,31 @@ describe HTTParty do
|
|
80
90
|
end.should raise_error(HTTParty::UnsupportedFormat)
|
81
91
|
end
|
82
92
|
end
|
83
|
-
|
84
|
-
describe
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
Foo.send(:http, URI.parse('http://foobar.com')).use_ssl?.should == false
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
describe "deriving format from path" do
|
95
|
-
it "should work if there is extension and extension is an allowed format" do
|
96
|
-
%w[xml json].each do |ext|
|
97
|
-
Foo.send(:format_from_path, "/foo/bar.#{ext}").should == ext
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
it "should NOT work if there is extension but extention is not allow format" do
|
102
|
-
Foo.send(:format_from_path, '/foo/bar.php').should == nil
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'should NOT work if there is no extension' do
|
106
|
-
['', '.'].each do |ext|
|
107
|
-
Foo.send(:format_from_path, "/foo/bar#{ext}").should == nil
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
describe 'parsing responses' do
|
113
|
-
it 'should handle xml automatically' do
|
114
|
-
xml = %q[<books><book><id>1234</id><name>Foo Bar!</name></book></books>]
|
115
|
-
Foo.format :xml
|
116
|
-
Foo.send(:parse_response, xml).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'should handle json automatically' do
|
120
|
-
json = %q[{"books": {"book": {"name": "Foo Bar!", "id": "1234"}}}]
|
121
|
-
Foo.format :json
|
122
|
-
Foo.send(:parse_response, json).should == {'books' => {'book' => {'id' => '1234', 'name' => 'Foo Bar!'}}}
|
93
|
+
|
94
|
+
describe "with explicit override of automatic redirect handling" do
|
95
|
+
|
96
|
+
it "should fail with redirected GET" do
|
97
|
+
lambda do
|
98
|
+
Foo.get('/foo', :no_follow => true)
|
99
|
+
end.should raise_error(HTTParty::RedirectionTooDeep)
|
123
100
|
end
|
124
|
-
|
125
|
-
|
126
|
-
describe "sending requests" do
|
127
|
-
it "should not work with request method other than get, post, put, delete" do
|
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
|
-
|
133
|
-
it
|
107
|
+
|
108
|
+
it "should fail with redirected DELETE" do
|
134
109
|
lambda do
|
135
|
-
Foo.
|
136
|
-
end.should raise_error(
|
110
|
+
Foo.delete('/foo', :no_follow => true)
|
111
|
+
end.should raise_error(HTTParty::RedirectionTooDeep)
|
137
112
|
end
|
138
|
-
|
139
|
-
it
|
113
|
+
|
114
|
+
it "should fail with redirected PUT" do
|
140
115
|
lambda do
|
141
|
-
Foo.
|
142
|
-
end.should raise_error(
|
116
|
+
Foo.put('/foo', :no_follow => true)
|
117
|
+
end.should raise_error(HTTParty::RedirectionTooDeep)
|
143
118
|
end
|
144
119
|
end
|
145
|
-
end
|
120
|
+
end
|
data/spec/spec.opts
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: 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-
|
12
|
+
date: 2008-11-14 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -22,6 +22,16 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: "2.1"
|
24
24
|
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hoe
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.0
|
34
|
+
version:
|
25
35
|
description: Makes http fun! Also, makes consuming restful web services dead easy.
|
26
36
|
email:
|
27
37
|
- nunemaker@gmail.com
|
@@ -46,19 +56,19 @@ files:
|
|
46
56
|
- config/requirements.rb
|
47
57
|
- examples/aaws.rb
|
48
58
|
- examples/delicious.rb
|
59
|
+
- examples/google.rb
|
49
60
|
- examples/twitter.rb
|
50
61
|
- examples/whoismyrep.rb
|
51
62
|
- httparty.gemspec
|
52
63
|
- lib/httparty.rb
|
53
|
-
- lib/httparty/
|
54
|
-
- lib/httparty/core_ext/hash.rb
|
64
|
+
- lib/httparty/request.rb
|
55
65
|
- lib/httparty/version.rb
|
56
66
|
- script/console
|
57
67
|
- script/destroy
|
58
68
|
- script/generate
|
59
69
|
- script/txt2html
|
60
70
|
- setup.rb
|
61
|
-
- spec/
|
71
|
+
- spec/httparty/request_spec.rb
|
62
72
|
- spec/httparty_spec.rb
|
63
73
|
- spec/spec.opts
|
64
74
|
- spec/spec_helper.rb
|
@@ -90,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
100
|
requirements: []
|
91
101
|
|
92
102
|
rubyforge_project: httparty
|
93
|
-
rubygems_version: 1.
|
103
|
+
rubygems_version: 1.3.1
|
94
104
|
signing_key:
|
95
105
|
specification_version: 2
|
96
106
|
summary: Makes http fun! Also, makes consuming restful web services dead easy.
|
data/lib/httparty/core_ext.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module HTTParty
|
2
|
-
module CoreExt
|
3
|
-
module HashConversions
|
4
|
-
def to_struct
|
5
|
-
o = OpenStruct.new
|
6
|
-
self.each do |k, v|
|
7
|
-
# if id, we create an accessor so we don't get warning about id deprecation
|
8
|
-
if k.to_s == 'id'
|
9
|
-
o.class.class_eval "attr_accessor :id"
|
10
|
-
o.id = v
|
11
|
-
else
|
12
|
-
o.send("#{k}=", v.is_a?(Hash) ? v.to_struct : v)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
o
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
Hash.send :include, HTTParty::CoreExt::HashConversions
|
data/spec/hash_spec.rb
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
-
|
3
|
-
describe HTTParty::CoreExt::HashConversions do
|
4
|
-
it "should convert hash to struct" do
|
5
|
-
{'foo' => 'bar'}.to_struct.should == OpenStruct.new(:foo => 'bar')
|
6
|
-
end
|
7
|
-
|
8
|
-
it 'should convert nested hash to struct' do
|
9
|
-
{'foo' => {'bar' => 'baz'}}.to_struct.should == OpenStruct.new(:foo => OpenStruct.new(:bar => 'baz'))
|
10
|
-
end
|
11
|
-
end
|