juliocesar-httparty 0.2.6

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.
@@ -0,0 +1,10 @@
1
+ dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require File.join(dir, 'httparty')
3
+ require 'pp'
4
+
5
+ class Rep
6
+ include HTTParty
7
+ end
8
+
9
+ pp Rep.get('http://whoismyrepresentative.com/whoismyrep.php?zip=46544')
10
+ pp Rep.get('http://whoismyrepresentative.com/whoismyrep.php', :query => {:zip => 46544})
data/httparty.gemspec ADDED
@@ -0,0 +1,40 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{httparty}
5
+ s.version = "0.2.6"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["John Nunemaker"]
9
+ s.date = %q{2009-01-05}
10
+ s.default_executable = %q{httparty}
11
+ s.description = %q{Makes http fun! Also, makes consuming restful web services dead easy.}
12
+ s.email = %q{nunemaker@gmail.com}
13
+ s.executables = ["httparty"]
14
+ s.extra_rdoc_files = ["bin/httparty", "lib/core_extensions.rb", "lib/httparty/exceptions.rb", "lib/httparty/request.rb", "lib/httparty/version.rb", "lib/httparty.rb", "lib/module_level_inheritable_attributes.rb", "README"]
15
+ s.files = ["bin/httparty", "examples/aaws.rb", "examples/basic.rb", "examples/delicious.rb", "examples/google.rb", "examples/rubyurl.rb", "examples/twitter.rb", "examples/whoismyrep.rb", "History", "httparty.gemspec", "lib/core_extensions.rb", "lib/httparty/exceptions.rb", "lib/httparty/request.rb", "lib/httparty/version.rb", "lib/httparty.rb", "lib/module_level_inheritable_attributes.rb", "Manifest", "MIT-LICENSE", "Rakefile", "README", "setup.rb", "spec/as_buggery_spec.rb", "spec/fixtures/delicious.xml", "spec/fixtures/google.html", "spec/fixtures/twitter.json", "spec/fixtures/twitter.xml", "spec/httparty/request_spec.rb", "spec/httparty_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "website/css/common.css", "website/index.html"]
16
+ s.has_rdoc = true
17
+ s.homepage = %q{http://httparty.rubyforge.org}
18
+ s.post_install_message = %q{When you HTTParty, you must party hard!}
19
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Httparty", "--main", "README"]
20
+ s.require_paths = ["lib"]
21
+ s.rubyforge_project = %q{httparty}
22
+ s.rubygems_version = %q{1.3.1}
23
+ s.summary = %q{Makes http fun! Also, makes consuming restful web services dead easy.}
24
+
25
+ if s.respond_to? :specification_version then
26
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
27
+ s.specification_version = 2
28
+
29
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
30
+ s.add_runtime_dependency(%q<json>, ["~> 1.1"])
31
+ s.add_development_dependency(%q<echoe>, [">= 0"])
32
+ else
33
+ s.add_dependency(%q<json>, ["~> 1.1"])
34
+ s.add_dependency(%q<echoe>, [">= 0"])
35
+ end
36
+ else
37
+ s.add_dependency(%q<json>, ["~> 1.1"])
38
+ s.add_dependency(%q<echoe>, [">= 0"])
39
+ end
40
+ end
@@ -0,0 +1,349 @@
1
+ require 'time'
2
+
3
+ # Copyright (c) 2008 Sam Smoot.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ class Object
25
+ # @return <TrueClass, FalseClass>
26
+ #
27
+ # @example [].blank? #=> true
28
+ # @example [1].blank? #=> false
29
+ # @example [nil].blank? #=> false
30
+ #
31
+ # Returns true if the object is nil or empty (if applicable)
32
+ def blank?
33
+ nil? || (respond_to?(:empty?) && empty?)
34
+ end
35
+ end # class Object
36
+
37
+ class Numeric
38
+ # @return <TrueClass, FalseClass>
39
+ #
40
+ # Numerics can't be blank
41
+ def blank?
42
+ false
43
+ end
44
+ end # class Numeric
45
+
46
+ class NilClass
47
+ # @return <TrueClass, FalseClass>
48
+ #
49
+ # Nils are always blank
50
+ def blank?
51
+ true
52
+ end
53
+ end # class NilClass
54
+
55
+ class TrueClass
56
+ # @return <TrueClass, FalseClass>
57
+ #
58
+ # True is not blank.
59
+ def blank?
60
+ false
61
+ end
62
+ end # class TrueClass
63
+
64
+ class FalseClass
65
+ # False is always blank.
66
+ def blank?
67
+ true
68
+ end
69
+ end # class FalseClass
70
+
71
+ class String
72
+ # @example "".blank? #=> true
73
+ # @example " ".blank? #=> true
74
+ # @example " hey ho ".blank? #=> false
75
+ #
76
+ # @return <TrueClass, FalseClass>
77
+ #
78
+ # Strips out whitespace then tests if the string is empty.
79
+ def blank?
80
+ strip.empty?
81
+ end
82
+ end # class String
83
+
84
+ require 'rexml/parsers/streamparser'
85
+ require 'rexml/parsers/baseparser'
86
+ require 'rexml/light/node'
87
+
88
+ # This is a slighly modified version of the XMLUtilityNode from
89
+ # http://merb.devjavu.com/projects/merb/ticket/95 (has.sox@gmail.com)
90
+ # It's mainly just adding vowels, as I ht cd wth n vwls :)
91
+ # This represents the hard part of the work, all I did was change the
92
+ # underlying parser.
93
+ class REXMLUtilityNode
94
+ attr_accessor :name, :attributes, :children, :type
95
+
96
+ def self.typecasts
97
+ @@typecasts
98
+ end
99
+
100
+ def self.typecasts=(obj)
101
+ @@typecasts = obj
102
+ end
103
+
104
+ def self.available_typecasts
105
+ @@available_typecasts
106
+ end
107
+
108
+ def self.available_typecasts=(obj)
109
+ @@available_typecasts = obj
110
+ end
111
+
112
+ self.typecasts = {}
113
+ self.typecasts["integer"] = lambda{|v| v.nil? ? nil : v.to_i}
114
+ self.typecasts["boolean"] = lambda{|v| v.nil? ? nil : (v.strip != "false")}
115
+ self.typecasts["datetime"] = lambda{|v| v.nil? ? nil : Time.parse(v).utc}
116
+ self.typecasts["date"] = lambda{|v| v.nil? ? nil : Date.parse(v)}
117
+ self.typecasts["dateTime"] = lambda{|v| v.nil? ? nil : Time.parse(v).utc}
118
+ self.typecasts["decimal"] = lambda{|v| BigDecimal(v)}
119
+ self.typecasts["double"] = lambda{|v| v.nil? ? nil : v.to_f}
120
+ self.typecasts["float"] = lambda{|v| v.nil? ? nil : v.to_f}
121
+ self.typecasts["symbol"] = lambda{|v| v.to_sym}
122
+ self.typecasts["string"] = lambda{|v| v.to_s}
123
+ self.typecasts["yaml"] = lambda{|v| v.nil? ? nil : YAML.load(v)}
124
+ self.typecasts["base64Binary"] = lambda{|v| v.unpack('m').first }
125
+
126
+ self.available_typecasts = self.typecasts.keys
127
+
128
+ def initialize(name, attributes = {})
129
+ @name = name.tr("-", "_")
130
+ # leave the type alone if we don't know what it is
131
+ @type = self.class.available_typecasts.include?(attributes["type"]) ? attributes.delete("type") : attributes["type"]
132
+
133
+ @nil_element = attributes.delete("nil") == "true"
134
+ @attributes = undasherize_keys(attributes)
135
+ @children = []
136
+ @text = false
137
+ end
138
+
139
+ def add_node(node)
140
+ @text = true if node.is_a? String
141
+ @children << node
142
+ end
143
+
144
+ def to_hash
145
+ if @type == "file"
146
+ f = StringIO.new((@children.first || '').unpack('m').first)
147
+ class << f
148
+ attr_accessor :original_filename, :content_type
149
+ end
150
+ f.original_filename = attributes['name'] || 'untitled'
151
+ f.content_type = attributes['content_type'] || 'application/octet-stream'
152
+ return {name => f}
153
+ end
154
+
155
+ if @text
156
+ return { name => typecast_value( translate_xml_entities( inner_html ) ) }
157
+ else
158
+ #change repeating groups into an array
159
+ groups = @children.inject({}) { |s,e| (s[e.name] ||= []) << e; s }
160
+
161
+ out = nil
162
+ if @type == "array"
163
+ out = []
164
+ groups.each do |k, v|
165
+ if v.size == 1
166
+ out << v.first.to_hash.entries.first.last
167
+ else
168
+ out << v.map{|e| e.to_hash[k]}
169
+ end
170
+ end
171
+ out = out.flatten
172
+
173
+ else # If Hash
174
+ out = {}
175
+ groups.each do |k,v|
176
+ if v.size == 1
177
+ out.merge!(v.first)
178
+ else
179
+ out.merge!( k => v.map{|e| e.to_hash[k]})
180
+ end
181
+ end
182
+ out.merge! attributes unless attributes.empty?
183
+ out = out.empty? ? nil : out
184
+ end
185
+
186
+ if @type && out.nil?
187
+ { name => typecast_value(out) }
188
+ else
189
+ { name => out }
190
+ end
191
+ end
192
+ end
193
+
194
+ # Typecasts a value based upon its type. For instance, if
195
+ # +node+ has #type == "integer",
196
+ # {{[node.typecast_value("12") #=> 12]}}
197
+ #
198
+ # @param value<String> The value that is being typecast.
199
+ #
200
+ # @details [:type options]
201
+ # "integer"::
202
+ # converts +value+ to an integer with #to_i
203
+ # "boolean"::
204
+ # checks whether +value+, after removing spaces, is the literal
205
+ # "true"
206
+ # "datetime"::
207
+ # Parses +value+ using Time.parse, and returns a UTC Time
208
+ # "date"::
209
+ # Parses +value+ using Date.parse
210
+ #
211
+ # @return <Integer, TrueClass, FalseClass, Time, Date, Object>
212
+ # The result of typecasting +value+.
213
+ #
214
+ # @note
215
+ # If +self+ does not have a "type" key, or if it's not one of the
216
+ # options specified above, the raw +value+ will be returned.
217
+ def typecast_value(value)
218
+ return value unless @type
219
+ proc = self.class.typecasts[@type]
220
+ proc.nil? ? value : proc.call(value)
221
+ end
222
+
223
+ # Convert basic XML entities into their literal values.
224
+ #
225
+ # @param value<#gsub> An XML fragment.
226
+ #
227
+ # @return <#gsub> The XML fragment after converting entities.
228
+ def translate_xml_entities(value)
229
+ value.gsub(/&lt;/, "<").
230
+ gsub(/&gt;/, ">").
231
+ gsub(/&quot;/, '"').
232
+ gsub(/&apos;/, "'").
233
+ gsub(/&amp;/, "&")
234
+ end
235
+
236
+ # Take keys of the form foo-bar and convert them to foo_bar
237
+ def undasherize_keys(params)
238
+ params.keys.each do |key, value|
239
+ params[key.tr("-", "_")] = params.delete(key)
240
+ end
241
+ params
242
+ end
243
+
244
+ # Get the inner_html of the REXML node.
245
+ def inner_html
246
+ @children.join
247
+ end
248
+
249
+ # Converts the node into a readable HTML node.
250
+ #
251
+ # @return <String> The HTML node in text form.
252
+ def to_html
253
+ attributes.merge!(:type => @type ) if @type
254
+ "<#{name}#{attributes.to_xml_attributes}>#{@nil_element ? '' : inner_html}</#{name}>"
255
+ end
256
+
257
+ # @alias #to_html #to_s
258
+ def to_s
259
+ to_html
260
+ end
261
+ end
262
+
263
+ class ToHashParser
264
+ def self.from_xml(xml)
265
+ stack = []
266
+ parser = REXML::Parsers::BaseParser.new(xml)
267
+
268
+ while true
269
+ event = parser.pull
270
+ case event[0]
271
+ when :end_document
272
+ break
273
+ when :end_doctype, :start_doctype
274
+ # do nothing
275
+ when :start_element
276
+ stack.push REXMLUtilityNode.new(event[1], event[2])
277
+ when :end_element
278
+ if stack.size > 1
279
+ temp = stack.pop
280
+ stack.last.add_node(temp)
281
+ end
282
+ when :text, :cdata
283
+ stack.last.add_node(event[1]) unless event[1].strip.length == 0 or stack.empty?
284
+ end
285
+ end
286
+ stack.pop.to_hash
287
+ end
288
+ end
289
+
290
+ class Hash
291
+ # @return <String> This hash as a query string
292
+ #
293
+ # @example
294
+ # { :name => "Bob",
295
+ # :address => {
296
+ # :street => '111 Ruby Ave.',
297
+ # :city => 'Ruby Central',
298
+ # :phones => ['111-111-1111', '222-222-2222']
299
+ # }
300
+ # }.to_params
301
+ # #=> "name=Bob&address[city]=Ruby Central&address[phones][]=111-111-1111&address[phones][]=222-222-2222&address[street]=111 Ruby Ave."
302
+ def to_params
303
+ params = self.map { |k,v| normalize_param(k,v) }.join
304
+ params.chop! # trailing &
305
+ params
306
+ end
307
+
308
+ # @param key<Object> The key for the param.
309
+ # @param value<Object> The value for the param.
310
+ #
311
+ # @return <String> This key value pair as a param
312
+ #
313
+ # @example normalize_param(:name, "Bob") #=> "name=Bob&"
314
+ def normalize_param(key, value)
315
+ param = ''
316
+ stack = []
317
+
318
+ if value.is_a?(Array)
319
+ param << value.map { |element| normalize_param("#{key}[]", element) }.join
320
+ elsif value.is_a?(Hash)
321
+ stack << [key,value]
322
+ else
323
+ param << "#{key}=#{URI.encode(value.to_s)}&"
324
+ end
325
+
326
+ stack.each do |parent, hash|
327
+ hash.each do |key, value|
328
+ if value.is_a?(Hash)
329
+ stack << ["#{parent}[#{key}]", value]
330
+ else
331
+ param << normalize_param("#{parent}[#{key}]", value)
332
+ end
333
+ end
334
+ end
335
+
336
+ param
337
+ end
338
+
339
+ # @return <String> The hash as attributes for an XML tag.
340
+ #
341
+ # @example
342
+ # { :one => 1, "two"=>"TWO" }.to_xml_attributes
343
+ # #=> 'one="1" two="TWO"'
344
+ def to_xml_attributes
345
+ map do |k,v|
346
+ %{#{k.to_s.snake_case.sub(/^(.{1,1})/) { |m| m.downcase }}="#{v}"}
347
+ end.join(' ')
348
+ end
349
+ end
data/lib/httparty.rb ADDED
@@ -0,0 +1,120 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require 'net/http'
4
+ require 'net/https'
5
+ require 'rubygems'
6
+ gem 'json', '>= 1.1.3'
7
+ require 'json'
8
+
9
+ require 'module_level_inheritable_attributes'
10
+ require 'core_extensions'
11
+
12
+ module HTTParty
13
+ AllowedFormats = {
14
+ 'text/xml' => :xml,
15
+ 'application/xml' => :xml,
16
+ 'application/json' => :json,
17
+ 'text/json' => :json,
18
+ 'application/javascript' => :json,
19
+ 'text/javascript' => :json,
20
+ 'text/html' => :html
21
+ }
22
+
23
+ def self.included(base)
24
+ base.extend ClassMethods
25
+ base.send :include, ModuleLevelInheritableAttributes
26
+ base.send(:mattr_inheritable, :default_options)
27
+ base.instance_variable_set("@default_options", {})
28
+ end
29
+
30
+ module ClassMethods
31
+ def default_options
32
+ @default_options
33
+ end
34
+
35
+ def http_proxy(addr=nil, port = nil)
36
+ default_options[:http_proxyaddr] = addr
37
+ default_options[:http_proxyport] = port
38
+ end
39
+
40
+ def base_uri(uri=nil)
41
+ return default_options[:base_uri] unless uri
42
+ default_options[:base_uri] = HTTParty.normalize_base_uri(uri)
43
+ end
44
+
45
+ def basic_auth(u, p)
46
+ default_options[:basic_auth] = {:username => u, :password => p}
47
+ end
48
+
49
+ def default_params(h={})
50
+ raise ArgumentError, 'Default params must be a hash' unless h.is_a?(Hash)
51
+ default_options[:default_params] ||= {}
52
+ default_options[:default_params].merge!(h)
53
+ end
54
+
55
+ def headers(h={})
56
+ raise ArgumentError, 'Headers must be a hash' unless h.is_a?(Hash)
57
+ default_options[:headers] ||= {}
58
+ default_options[:headers].merge!(h)
59
+ end
60
+
61
+ def format(f)
62
+ raise UnsupportedFormat, "Must be one of: #{AllowedFormats.values.join(', ')}" unless AllowedFormats.value?(f)
63
+ default_options[:format] = f
64
+ end
65
+
66
+ def get(path, options={})
67
+ perform_request Net::HTTP::Get, path, options
68
+ end
69
+
70
+ def post(path, options={})
71
+ perform_request Net::HTTP::Post, path, options
72
+ end
73
+
74
+ def put(path, options={})
75
+ perform_request Net::HTTP::Put, path, options
76
+ end
77
+
78
+ def delete(path, options={})
79
+ perform_request Net::HTTP::Delete, path, options
80
+ end
81
+
82
+ private
83
+ def perform_request(http_method, path, options) #:nodoc:
84
+ Request.new(http_method, path, default_options.dup.merge(options)).perform
85
+ end
86
+ end
87
+
88
+ def self.normalize_base_uri(url) #:nodoc:
89
+ use_ssl = (url =~ /^https/) || url.include?(':443')
90
+ ends_with_slash = url =~ /\/$/
91
+
92
+ url.chop! if ends_with_slash
93
+ url.gsub!(/^https?:\/\//i, '')
94
+
95
+ "http#{'s' if use_ssl}://#{url}"
96
+ end
97
+
98
+ class Basement
99
+ include HTTParty
100
+ end
101
+
102
+ def self.get(*args)
103
+ Basement.get(*args)
104
+ end
105
+
106
+ def self.post(*args)
107
+ Basement.post(*args)
108
+ end
109
+
110
+ def self.put(*args)
111
+ Basement.put(*args)
112
+ end
113
+
114
+ def self.delete(*args)
115
+ Basement.delete(*args)
116
+ end
117
+ end
118
+
119
+ require 'httparty/exceptions'
120
+ require 'httparty/request'