voxdolo-httparty 0.3.1

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.
Files changed (56) hide show
  1. data/History +108 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Manifest +55 -0
  4. data/README +35 -0
  5. data/Rakefile +47 -0
  6. data/bin/httparty +98 -0
  7. data/cucumber.yml +1 -0
  8. data/examples/aaws.rb +32 -0
  9. data/examples/basic.rb +11 -0
  10. data/examples/delicious.rb +37 -0
  11. data/examples/google.rb +16 -0
  12. data/examples/rubyurl.rb +14 -0
  13. data/examples/twitter.rb +31 -0
  14. data/examples/whoismyrep.rb +10 -0
  15. data/features/basic_authentication.feature +20 -0
  16. data/features/command_line.feature +7 -0
  17. data/features/deals_with_http_error_codes.feature +26 -0
  18. data/features/handles_multiple_formats.feature +34 -0
  19. data/features/steps/env.rb +15 -0
  20. data/features/steps/httparty_response_steps.rb +26 -0
  21. data/features/steps/httparty_steps.rb +15 -0
  22. data/features/steps/mongrel_helper.rb +55 -0
  23. data/features/steps/remote_service_steps.rb +47 -0
  24. data/features/supports_redirection.feature +22 -0
  25. data/httparty.gemspec +37 -0
  26. data/lib/core_extensions.rb +175 -0
  27. data/lib/httparty/cookie_hash.rb +9 -0
  28. data/lib/httparty/exceptions.rb +7 -0
  29. data/lib/httparty/module_inheritable_attributes.rb +25 -0
  30. data/lib/httparty/parsers/json.rb +74 -0
  31. data/lib/httparty/parsers/xml.rb +209 -0
  32. data/lib/httparty/parsers.rb +4 -0
  33. data/lib/httparty/request.rb +139 -0
  34. data/lib/httparty/response.rb +17 -0
  35. data/lib/httparty/version.rb +3 -0
  36. data/lib/httparty.rb +201 -0
  37. data/setup.rb +1585 -0
  38. data/spec/fixtures/delicious.xml +23 -0
  39. data/spec/fixtures/empty.xml +0 -0
  40. data/spec/fixtures/google.html +3 -0
  41. data/spec/fixtures/twitter.json +1 -0
  42. data/spec/fixtures/twitter.xml +403 -0
  43. data/spec/fixtures/undefined_method_add_node_for_nil.xml +2 -0
  44. data/spec/hash_spec.rb +49 -0
  45. data/spec/httparty/cookie_hash_spec.rb +38 -0
  46. data/spec/httparty/parsers/json_spec.rb +42 -0
  47. data/spec/httparty/parsers/xml_spec.rb +445 -0
  48. data/spec/httparty/request_spec.rb +205 -0
  49. data/spec/httparty/response_spec.rb +53 -0
  50. data/spec/httparty_spec.rb +259 -0
  51. data/spec/spec.opts +3 -0
  52. data/spec/spec_helper.rb +21 -0
  53. data/spec/string_spec.rb +27 -0
  54. data/website/css/common.css +47 -0
  55. data/website/index.html +74 -0
  56. metadata +133 -0
@@ -0,0 +1,4 @@
1
+ Dir[File.dirname(__FILE__) + "/parsers/*.rb"].sort.each do |path|
2
+ filename = File.basename(path)
3
+ require "httparty/parsers/#{filename}"
4
+ end
@@ -0,0 +1,139 @@
1
+ require 'uri'
2
+
3
+ module HTTParty
4
+ class Request #:nodoc:
5
+ SupportedHTTPMethods = [Net::HTTP::Get, Net::HTTP::Post, Net::HTTP::Put, Net::HTTP::Delete]
6
+
7
+ attr_accessor :http_method, :path, :options
8
+
9
+ def initialize(http_method, path, o={})
10
+ self.http_method = http_method
11
+ self.path = path
12
+ self.options = {
13
+ :limit => o.delete(:no_follow) ? 0 : 5,
14
+ :default_params => {},
15
+ }.merge(o)
16
+ end
17
+
18
+ def path=(uri)
19
+ @path = URI.parse(uri)
20
+ end
21
+
22
+ def uri
23
+ new_uri = path.relative? ? URI.parse("#{options[:base_uri]}#{path}") : path
24
+
25
+ # avoid double query string on redirects [#12]
26
+ unless @redirect
27
+ new_uri.query = query_string(new_uri)
28
+ end
29
+
30
+ new_uri
31
+ end
32
+
33
+ def format
34
+ options[:format]
35
+ end
36
+
37
+ def perform
38
+ validate
39
+ setup_raw_request
40
+ handle_response(get_response)
41
+ end
42
+
43
+ private
44
+ def http
45
+ http = Net::HTTP.new(uri.host, uri.port, options[:http_proxyaddr], options[:http_proxyport])
46
+ http.use_ssl = (uri.port == 443)
47
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
48
+ http
49
+ end
50
+
51
+ def configure_basic_auth
52
+ @raw_request.basic_auth(options[:basic_auth][:username], options[:basic_auth][:password])
53
+ end
54
+
55
+ def setup_raw_request
56
+ @raw_request = http_method.new(uri.request_uri)
57
+
58
+ if post? && options[:query]
59
+ @raw_request.set_form_data(options[:query])
60
+ end
61
+
62
+ @raw_request.body = options[:body].is_a?(Hash) ? options[:body].to_params : options[:body] unless options[:body].blank?
63
+ @raw_request.initialize_http_header options[:headers]
64
+
65
+ configure_basic_auth if options[:basic_auth]
66
+ end
67
+
68
+ def perform_actual_request
69
+ http.request(@raw_request)
70
+ end
71
+
72
+ def get_response
73
+ response = perform_actual_request
74
+ options[:format] ||= format_from_mimetype(response['content-type'])
75
+ response
76
+ end
77
+
78
+ def query_string(uri)
79
+ query_string_parts = []
80
+ query_string_parts << uri.query unless uri.query.blank?
81
+
82
+ if options[:query].is_a?(Hash)
83
+ query_string_parts << options[:default_params].merge(options[:query]).to_params
84
+ else
85
+ query_string_parts << options[:default_params].to_params unless options[:default_params].blank?
86
+ query_string_parts << options[:query] unless options[:query].blank?
87
+ end
88
+
89
+ query_string_parts.size > 0 ? query_string_parts.join('&') : nil
90
+ end
91
+
92
+ # Raises exception Net::XXX (http error code) if an http error occured
93
+ def handle_response(response)
94
+ case response
95
+ when Net::HTTPRedirection
96
+ options[:limit] -= 1
97
+ self.path = response['location']
98
+ @redirect = true
99
+ perform
100
+ else
101
+ parsed_response = parse_response(response.body)
102
+ Response.new(parsed_response, response.body, response.code, response.to_hash)
103
+ end
104
+ end
105
+
106
+ def parse_response(body)
107
+ return nil if body.nil? or body.empty? or body =~ /^\s+$/
108
+ case format
109
+ when :xml
110
+ HTTParty::Parsers::XML.parse(body)
111
+ when :json
112
+ HTTParty::Parsers::JSON.decode(body)
113
+ when :yaml
114
+ YAML::load(body)
115
+ else
116
+ body
117
+ end
118
+ end
119
+
120
+ # Uses the HTTP Content-Type header to determine the format of the response
121
+ # It compares the MIME type returned to the types stored in the AllowedFormats hash
122
+ def format_from_mimetype(mimetype)
123
+ return nil if mimetype.nil?
124
+ AllowedFormats.each { |k, v| return v if mimetype.include?(k) }
125
+ end
126
+
127
+ def validate
128
+ raise HTTParty::RedirectionTooDeep, 'HTTP redirects too deep' if options[:limit].to_i <= 0
129
+ raise ArgumentError, 'only get, post, put and delete methods are supported' unless SupportedHTTPMethods.include?(http_method)
130
+ raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].is_a?(Hash)
131
+ raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].is_a?(Hash)
132
+ raise ArgumentError, ':query must be hash if using HTTP Post' if post? && !options[:query].nil? && !options[:query].is_a?(Hash)
133
+ end
134
+
135
+ def post?
136
+ Net::HTTP::Post == http_method
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,17 @@
1
+ module HTTParty
2
+ class Response < BlankSlate #:nodoc:
3
+ attr_accessor :body, :code, :headers
4
+ attr_reader :delegate
5
+
6
+ def initialize(delegate, body, code, headers={})
7
+ @delegate = delegate
8
+ @body = body
9
+ @code = code
10
+ @headers = headers
11
+ end
12
+
13
+ def method_missing(name, *args, &block)
14
+ @delegate.send(name, *args, &block)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module HTTParty #:nodoc:
2
+ Version = '0.3.1'
3
+ end
data/lib/httparty.rb ADDED
@@ -0,0 +1,201 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require 'net/http'
4
+ require 'net/https'
5
+ require 'core_extensions'
6
+ require 'httparty/module_inheritable_attributes'
7
+
8
+ module HTTParty
9
+
10
+ AllowedFormats = {
11
+ 'text/xml' => :xml,
12
+ 'application/xml' => :xml,
13
+ 'application/json' => :json,
14
+ 'text/json' => :json,
15
+ 'application/javascript' => :json,
16
+ 'text/javascript' => :json,
17
+ 'text/html' => :html,
18
+ 'application/x-yaml' => :yaml,
19
+ 'text/yaml' => :yaml
20
+ } unless defined?(AllowedFormats)
21
+
22
+ def self.included(base)
23
+ base.extend ClassMethods
24
+ base.send :include, HTTParty::ModuleInheritableAttributes
25
+ base.send(:mattr_inheritable, :default_options)
26
+ base.instance_variable_set("@default_options", {})
27
+ end
28
+
29
+ module ClassMethods
30
+ # Allows setting http proxy information to be used
31
+ #
32
+ # class Foo
33
+ # include HTTParty
34
+ # http_proxy 'http://foo.com', 80
35
+ # end
36
+ def http_proxy(addr=nil, port = nil)
37
+ default_options[:http_proxyaddr] = addr
38
+ default_options[:http_proxyport] = port
39
+ end
40
+
41
+ # Allows setting a base uri to be used for each request.
42
+ # Will normalize uri to include http, etc.
43
+ #
44
+ # class Foo
45
+ # include HTTParty
46
+ # base_uri 'twitter.com'
47
+ # end
48
+ def base_uri(uri=nil)
49
+ return default_options[:base_uri] unless uri
50
+ default_options[:base_uri] = HTTParty.normalize_base_uri(uri)
51
+ end
52
+
53
+ # Allows setting basic authentication username and password.
54
+ #
55
+ # class Foo
56
+ # include HTTParty
57
+ # basic_auth 'username', 'password'
58
+ # end
59
+ def basic_auth(u, p)
60
+ default_options[:basic_auth] = {:username => u, :password => p}
61
+ end
62
+
63
+ # Allows setting default parameters to be appended to each request.
64
+ # Great for api keys and such.
65
+ #
66
+ # class Foo
67
+ # include HTTParty
68
+ # default_params :api_key => 'secret', :another => 'foo'
69
+ # end
70
+ def default_params(h={})
71
+ raise ArgumentError, 'Default params must be a hash' unless h.is_a?(Hash)
72
+ default_options[:default_params] ||= {}
73
+ default_options[:default_params].merge!(h)
74
+ end
75
+
76
+ # Allows setting a base uri to be used for each request.
77
+ #
78
+ # class Foo
79
+ # include HTTParty
80
+ # headers 'Accept' => 'text/html'
81
+ # end
82
+ def headers(h={})
83
+ raise ArgumentError, 'Headers must be a hash' unless h.is_a?(Hash)
84
+ default_options[:headers] ||= {}
85
+ default_options[:headers].merge!(h)
86
+ end
87
+
88
+ def cookies(h={})
89
+ raise ArgumentError, 'Cookies must be a hash' unless h.is_a?(Hash)
90
+ default_options[:cookies] ||= CookieHash.new
91
+ default_options[:cookies].add_cookies(h)
92
+ end
93
+
94
+ # Allows setting the format with which to parse.
95
+ # Must be one of the allowed formats ie: json, xml
96
+ #
97
+ # class Foo
98
+ # include HTTParty
99
+ # format :json
100
+ # end
101
+ def format(f)
102
+ raise UnsupportedFormat, "Must be one of: #{AllowedFormats.values.join(', ')}" unless AllowedFormats.value?(f)
103
+ default_options[:format] = f
104
+ end
105
+
106
+ # Allows making a get request to a url.
107
+ #
108
+ # class Foo
109
+ # include HTTParty
110
+ # end
111
+ #
112
+ # # Simple get with full url
113
+ # Foo.get('http://foo.com/resource.json')
114
+ #
115
+ # # Simple get with full url and query parameters
116
+ # # ie: http://foo.com/resource.json?limit=10
117
+ # Foo.get('http://foo.com/resource.json', :query => {:limit => 10})
118
+ def get(path, options={})
119
+ perform_request Net::HTTP::Get, path, options
120
+ end
121
+
122
+ # Allows making a post request to a url.
123
+ #
124
+ # class Foo
125
+ # include HTTParty
126
+ # end
127
+ #
128
+ # # Simple post with full url and setting the body
129
+ # Foo.post('http://foo.com/resources', :body => {:bar => 'baz'})
130
+ #
131
+ # # Simple post with full url using :query option,
132
+ # # which gets set as form data on the request.
133
+ # Foo.post('http://foo.com/resources', :query => {:bar => 'baz'})
134
+ def post(path, options={})
135
+ perform_request Net::HTTP::Post, path, options
136
+ end
137
+
138
+ def put(path, options={})
139
+ perform_request Net::HTTP::Put, path, options
140
+ end
141
+
142
+ def delete(path, options={})
143
+ perform_request Net::HTTP::Delete, path, options
144
+ end
145
+
146
+ def default_options #:nodoc:
147
+ @default_options
148
+ end
149
+
150
+ private
151
+ def perform_request(http_method, path, options) #:nodoc:
152
+ process_cookies(options)
153
+ Request.new(http_method, path, default_options.dup.merge(options)).perform
154
+ end
155
+
156
+ def process_cookies(options) #:nodoc:
157
+ return unless options[:cookies] || default_options[:cookies]
158
+ options[:headers] ||= {}
159
+ options[:headers]["cookie"] = cookies(options[:cookies] || {}).to_cookie_string
160
+
161
+ default_options.delete(:cookies)
162
+ options.delete(:cookies)
163
+ end
164
+ end
165
+
166
+ def self.normalize_base_uri(url) #:nodoc:
167
+ use_ssl = (url =~ /^https/) || url.include?(':443')
168
+ ends_with_slash = url =~ /\/$/
169
+
170
+ url.chop! if ends_with_slash
171
+ url.gsub!(/^https?:\/\//i, '')
172
+
173
+ "http#{'s' if use_ssl}://#{url}"
174
+ end
175
+
176
+ class Basement #:nodoc:
177
+ include HTTParty
178
+ end
179
+
180
+ def self.get(*args)
181
+ Basement.get(*args)
182
+ end
183
+
184
+ def self.post(*args)
185
+ Basement.post(*args)
186
+ end
187
+
188
+ def self.put(*args)
189
+ Basement.put(*args)
190
+ end
191
+
192
+ def self.delete(*args)
193
+ Basement.delete(*args)
194
+ end
195
+ end
196
+
197
+ require 'httparty/cookie_hash'
198
+ require 'httparty/exceptions'
199
+ require 'httparty/request'
200
+ require 'httparty/response'
201
+ require 'httparty/parsers'