|
df29a552
»
|
jnunemaker |
2008-07-27 |
Initial commit |
1 |
require 'net/http' |
| |
2 |
require 'net/https' |
| |
3 |
require 'uri' |
|
de9b4fb6
»
|
jnunemaker |
2008-07-27 |
Put in first wave of parsin...  |
4 |
require 'ostruct' |
|
df29a552
»
|
jnunemaker |
2008-07-27 |
Initial commit |
5 |
require 'rubygems' |
| |
6 |
require 'active_support' |
| |
7 |
|
| |
8 |
$:.unshift(File.dirname(__FILE__)) unless |
| |
9 |
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__))) |
| |
10 |
|
|
1d48da03
»
|
jnunemaker |
2008-07-28 |
Renamed to HTTParty which i... |
11 |
dir = File.expand_path(File.join(File.dirname(__FILE__), 'httparty')) |
|
13620e30
»
|
jnunemaker |
2008-07-27 |
Added Hash#to_struct for ma... |
12 |
require dir + '/core_ext' |
|
de9b4fb6
»
|
jnunemaker |
2008-07-27 |
Put in first wave of parsin...  |
13 |
|
|
1d48da03
»
|
jnunemaker |
2008-07-28 |
Renamed to HTTParty which i... |
14 |
module HTTParty |
|
df29a552
»
|
jnunemaker |
2008-07-27 |
Initial commit |
15 |
def self.included(base) |
| |
16 |
base.extend ClassMethods |
| |
17 |
end |
| |
18 |
|
|
0a1737e2
»
|
jnunemaker |
2008-07-28 |
Added several specs for htt... |
19 |
class UnsupportedFormat < StandardError; end |
| |
20 |
|
| |
21 |
AllowedFormats = %w[xml json] |
| |
22 |
|
| |
23 |
module ClassMethods |
|
df29a552
»
|
jnunemaker |
2008-07-27 |
Initial commit |
24 |
def base_uri(base_uri=nil) |
|
8e143785
»
|
jnunemaker |
2008-07-27 |
get, post, put and delete n... |
25 |
return @base_uri unless base_uri |
|
a8e1e6ac
»
|
jnunemaker |
2008-07-27 |
tweaked the way base uri wo... |
26 |
# don't want this to ever end with / |
| |
27 |
base_uri = base_uri.ends_with?('/') ? base_uri.chop : base_uri |
|
0a1737e2
»
|
jnunemaker |
2008-07-28 |
Added several specs for htt... |
28 |
@base_uri = normalize_base_uri(base_uri) |
|
8e143785
»
|
jnunemaker |
2008-07-27 |
get, post, put and delete n... |
29 |
end |
| |
30 |
|
|
3a8ad1da
»
|
jnunemaker |
2008-07-30 |
Added :basic_auth as an opt... |
31 |
# Warning: This is not thread safe most likely and |
| |
32 |
# only works if you use one set of credentials. I |
| |
33 |
# leave it because it is convenient on some occasions. |
|
8e143785
»
|
jnunemaker |
2008-07-27 |
get, post, put and delete n... |
34 |
def basic_auth(u, p) |
| |
35 |
@auth = {:username => u, :password => p} |
|
df29a552
»
|
jnunemaker |
2008-07-27 |
Initial commit |
36 |
end |
| |
37 |
|
|
3a8ad1da
»
|
jnunemaker |
2008-07-30 |
Added :basic_auth as an opt... |
38 |
# Updates the default query string parameters |
| |
39 |
# that should be appended to each request. |
|
236b3ad4
»
|
jnunemaker |
2008-07-28 |
Made it so default_params a... |
40 |
def default_params(h={}) |
| |
41 |
raise ArgumentError, 'Default params must be a hash' unless h.is_a?(Hash) |
|
0c05dcda
»
|
jnunemaker |
2008-07-28 |
Added #default_params metho... |
42 |
@default_params ||= {} |
| |
43 |
return @default_params if h.blank? |
| |
44 |
@default_params.merge!(h) |
| |
45 |
end |
| |
46 |
|
| |
47 |
def headers(h={}) |
| |
48 |
raise ArgumentError, 'Headers must be a hash' unless h.is_a?(Hash) |
| |
49 |
@headers ||= {} |
| |
50 |
return @headers if h.blank? |
| |
51 |
@headers.merge!(h) |
| |
52 |
end |
| |
53 |
|
|
236b3ad4
»
|
jnunemaker |
2008-07-28 |
Made it so default_params a... |
54 |
def format(f) |
| |
55 |
f = f.to_s |
| |
56 |
raise UnsupportedFormat, "Must be one of: #{AllowedFormats.join(', ')}" unless AllowedFormats.include?(f) |
| |
57 |
@format = f |
| |
58 |
end |
| |
59 |
|
| |
60 |
# TODO: spec out this |
|
8e143785
»
|
jnunemaker |
2008-07-27 |
get, post, put and delete n... |
61 |
def get(path, options={}) |
| |
62 |
send_request 'get', path, options |
| |
63 |
end |
|
236b3ad4
»
|
jnunemaker |
2008-07-28 |
Made it so default_params a... |
64 |
|
| |
65 |
# TODO: spec out this |
|
8e143785
»
|
jnunemaker |
2008-07-27 |
get, post, put and delete n... |
66 |
def post(path, options={}) |
| |
67 |
send_request 'post', path, options |
| |
68 |
end |
|
236b3ad4
»
|
jnunemaker |
2008-07-28 |
Made it so default_params a... |
69 |
|
| |
70 |
# TODO: spec out this |
|
8e143785
»
|
jnunemaker |
2008-07-27 |
get, post, put and delete n... |
71 |
def put(path, options={}) |
| |
72 |
send_request 'put', path, options |
| |
73 |
end |
|
236b3ad4
»
|
jnunemaker |
2008-07-28 |
Made it so default_params a... |
74 |
|
| |
75 |
# TODO: spec out this |
|
8e143785
»
|
jnunemaker |
2008-07-27 |
get, post, put and delete n... |
76 |
def delete(path, options={}) |
| |
77 |
send_request 'delete', path, options |
| |
78 |
end |
| |
79 |
|
|
df29a552
»
|
jnunemaker |
2008-07-27 |
Initial commit |
80 |
private |
|
f4570a46
»
|
jnunemaker |
2008-07-28 |
base_uri is no longer requi... |
81 |
def http(uri) |
| |
82 |
if @http.blank? |
| |
83 |
@http = Net::HTTP.new(uri.host, uri.port) |
| |
84 |
@http.use_ssl = (uri.port == 443) |
| |
85 |
# so we can avoid ssl warnings |
| |
86 |
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE |
| |
87 |
end |
| |
88 |
@http |
| |
89 |
end |
| |
90 |
|
|
3a8ad1da
»
|
jnunemaker |
2008-07-30 |
Added :basic_auth as an opt... |
91 |
# FIXME: this method is doing way to much and needs to be split up |
|
8e143785
»
|
jnunemaker |
2008-07-27 |
get, post, put and delete n... |
92 |
# options can be any or all of: |
|
9b423a22
»
|
jnunemaker |
2008-07-30 |
:body and :query now both t... |
93 |
# query => hash of keys/values or a query string (foo=bar&baz=poo) |
| |
94 |
# body => hash of keys/values or a query string (foo=bar&baz=poo) |
|
3a8ad1da
»
|
jnunemaker |
2008-07-30 |
Added :basic_auth as an opt... |
95 |
# headers => hash of headers to send request with |
| |
96 |
# basic_auth => :username and :password to use as basic http authentication (overrides @auth class instance variable) |
|
8e143785
»
|
jnunemaker |
2008-07-27 |
get, post, put and delete n... |
97 |
def send_request(method, path, options={}) |
|
a8ff3e36
»
|
jnunemaker |
2008-07-28 |
Added some argument errors ... |
98 |
raise ArgumentError, 'only get, post, put and delete methods are supported' unless %w[get post put delete].include?(method.to_s) |
| |
99 |
raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].is_a?(Hash) |
|
3a8ad1da
»
|
jnunemaker |
2008-07-30 |
Added :basic_auth as an opt... |
100 |
raise ArgumentError, ':basic_auth must be a hash' if options[:basic_auth] && !options[:basic_auth].is_a?(Hash) |
|
a8e1e6ac
»
|
jnunemaker |
2008-07-27 |
tweaked the way base uri wo... |
101 |
# we always want path that begins with / |
|
9b423a22
»
|
jnunemaker |
2008-07-30 |
:body and :query now both t... |
102 |
path = path =~ /^(\/|https?:\/\/)/ ? path : "/#{path}" |
| |
103 |
@format ||= format_from_path(path) |
| |
104 |
uri = URI.parse("#{base_uri}#{path}") |
| |
105 |
existing_query = uri.query ? "#{uri.query}&" : '' |
| |
106 |
uri.query = if options[:query].blank? |
| |
107 |
existing_query |
| |
108 |
else |
| |
109 |
existing_query + (options[:query].is_a?(Hash) ? default_params.merge(options[:query]).to_query : options[:query]) |
| |
110 |
end |
| |
111 |
klass = Net::HTTP.const_get method.to_s.downcase.capitalize |
| |
112 |
request = klass.new(uri.request_uri) |
| |
113 |
request.body = options[:body].is_a?(Hash) ? options[:body].to_query : options[:body] unless options[:body].blank? |
| |
114 |
basic_auth = options.delete(:basic_auth) || @auth |
|
8e143785
»
|
jnunemaker |
2008-07-27 |
get, post, put and delete n... |
115 |
request.initialize_http_header headers.merge(options[:headers] || {}) |
|
3a8ad1da
»
|
jnunemaker |
2008-07-30 |
Added :basic_auth as an opt... |
116 |
# note to self: self, do not put basic auth above headers because it removes basic auth |
| |
117 |
request.basic_auth(basic_auth[:username], basic_auth[:password]) if basic_auth |
|
9b423a22
»
|
jnunemaker |
2008-07-30 |
:body and :query now both t... |
118 |
response = http(uri).request(request) |
|
0a1737e2
»
|
jnunemaker |
2008-07-28 |
Added several specs for htt... |
119 |
parse_response(response.body) |
|
13620e30
»
|
jnunemaker |
2008-07-27 |
Added Hash#to_struct for ma... |
120 |
end |
| |
121 |
|
|
0a1737e2
»
|
jnunemaker |
2008-07-28 |
Added several specs for htt... |
122 |
def parse_response(body) |
|
13620e30
»
|
jnunemaker |
2008-07-27 |
Added Hash#to_struct for ma... |
123 |
case @format |
| |
124 |
when 'xml' |
| |
125 |
Hash.from_xml(body) |
| |
126 |
when 'json' |
| |
127 |
ActiveSupport::JSON.decode(body) |
|
de9b4fb6
»
|
jnunemaker |
2008-07-27 |
Put in first wave of parsin...  |
128 |
else |
|
0a1737e2
»
|
jnunemaker |
2008-07-28 |
Added several specs for htt... |
129 |
# just return the response if no format |
|
13620e30
»
|
jnunemaker |
2008-07-27 |
Added Hash#to_struct for ma... |
130 |
body |
|
de9b4fb6
»
|
jnunemaker |
2008-07-27 |
Put in first wave of parsin...  |
131 |
end |
|
8e143785
»
|
jnunemaker |
2008-07-27 |
get, post, put and delete n... |
132 |
end |
| |
133 |
|
|
df29a552
»
|
jnunemaker |
2008-07-27 |
Initial commit |
134 |
# Makes it so uri is sure to parse stuff like google.com with the http |
|
0a1737e2
»
|
jnunemaker |
2008-07-28 |
Added several specs for htt... |
135 |
def normalize_base_uri(str) |
|
df29a552
»
|
jnunemaker |
2008-07-27 |
Initial commit |
136 |
str =~ /^https?:\/\// ? str : "http#{'s' if str.include?(':443')}://#{str}" |
| |
137 |
end |
|
13620e30
»
|
jnunemaker |
2008-07-27 |
Added Hash#to_struct for ma... |
138 |
|
| |
139 |
# Returns a format that we can handle from the path if possible. |
| |
140 |
# Just does simple pattern matching on file extention: |
| |
141 |
# /foobar.xml => 'xml' |
| |
142 |
# /foobar.json => 'json' |
| |
143 |
def format_from_path(path) |
|
0a1737e2
»
|
jnunemaker |
2008-07-28 |
Added several specs for htt... |
144 |
ext = File.extname(path)[1..-1] |
| |
145 |
!ext.blank? && AllowedFormats.include?(ext) ? ext : nil |
|
13620e30
»
|
jnunemaker |
2008-07-27 |
Added Hash#to_struct for ma... |
146 |
end |
|
df29a552
»
|
jnunemaker |
2008-07-27 |
Initial commit |
147 |
end |
|
de9b4fb6
»
|
jnunemaker |
2008-07-27 |
Put in first wave of parsin...  |
148 |
end |