httparty 0.1.8 → 0.2.0

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