httparty 0.2.10 → 0.3.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.

@@ -1,7 +1,7 @@
1
1
  require 'uri'
2
2
 
3
3
  module HTTParty
4
- class Request
4
+ class Request #:nodoc:
5
5
  SupportedHTTPMethods = [Net::HTTP::Get, Net::HTTP::Post, Net::HTTP::Put, Net::HTTP::Delete]
6
6
 
7
7
  attr_accessor :http_method, :path, :options
@@ -21,7 +21,12 @@ module HTTParty
21
21
 
22
22
  def uri
23
23
  new_uri = path.relative? ? URI.parse("#{options[:base_uri]}#{path}") : path
24
- new_uri.query = query_string(new_uri)
24
+
25
+ # avoid double query string on redirects [#12]
26
+ unless @redirect
27
+ new_uri.query = query_string(new_uri)
28
+ end
29
+
25
30
  new_uri
26
31
  end
27
32
 
@@ -30,13 +35,13 @@ module HTTParty
30
35
  end
31
36
 
32
37
  def perform
33
- validate!
38
+ validate
34
39
  setup_raw_request
35
- handle_response!(get_response)
40
+ handle_response(get_response)
36
41
  end
37
42
 
38
43
  private
39
- def http #:nodoc:
44
+ def http
40
45
  http = Net::HTTP.new(uri.host, uri.port, options[:http_proxyaddr], options[:http_proxyport])
41
46
  http.use_ssl = (uri.port == 443)
42
47
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
@@ -64,13 +69,13 @@ module HTTParty
64
69
  http.request(@raw_request)
65
70
  end
66
71
 
67
- def get_response #:nodoc:
72
+ def get_response
68
73
  response = perform_actual_request
69
74
  options[:format] ||= format_from_mimetype(response['content-type'])
70
75
  response
71
76
  end
72
77
 
73
- def query_string(uri) #:nodoc:
78
+ def query_string(uri)
74
79
  query_string_parts = []
75
80
  query_string_parts << uri.query unless uri.query.blank?
76
81
 
@@ -85,11 +90,12 @@ module HTTParty
85
90
  end
86
91
 
87
92
  # Raises exception Net::XXX (http error code) if an http error occured
88
- def handle_response!(response) #:nodoc:
93
+ def handle_response(response)
89
94
  case response
90
95
  when Net::HTTPRedirection
91
96
  options[:limit] -= 1
92
97
  self.path = response['location']
98
+ @redirect = true
93
99
  perform
94
100
  else
95
101
  parsed_response = parse_response(response.body)
@@ -97,13 +103,13 @@ module HTTParty
97
103
  end
98
104
  end
99
105
 
100
- def parse_response(body) #:nodoc:
106
+ def parse_response(body)
101
107
  return nil if body.nil? or body.empty?
102
108
  case format
103
109
  when :xml
104
- ToHashParser.from_xml(body)
110
+ HTTParty::Parsers::XML.parse(body)
105
111
  when :json
106
- JSON.parse(body)
112
+ HTTParty::Parsers::JSON.decode(body)
107
113
  else
108
114
  body
109
115
  end
@@ -111,12 +117,12 @@ module HTTParty
111
117
 
112
118
  # Uses the HTTP Content-Type header to determine the format of the response
113
119
  # It compares the MIME type returned to the types stored in the AllowedFormats hash
114
- def format_from_mimetype(mimetype) #:nodoc:
120
+ def format_from_mimetype(mimetype)
115
121
  return nil if mimetype.nil?
116
122
  AllowedFormats.each { |k, v| return v if mimetype.include?(k) }
117
123
  end
118
124
 
119
- def validate! #:nodoc:
125
+ def validate
120
126
  raise HTTParty::RedirectionTooDeep, 'HTTP redirects too deep' if options[:limit].to_i <= 0
121
127
  raise ArgumentError, 'only get, post, put and delete methods are supported' unless SupportedHTTPMethods.include?(http_method)
122
128
  raise ArgumentError, ':headers must be a hash' if options[:headers] && !options[:headers].is_a?(Hash)
@@ -1,8 +1,9 @@
1
1
  module HTTParty
2
- class Response < BlankSlate
2
+ class Response < BlankSlate #:nodoc:
3
3
  attr_accessor :body, :code, :headers
4
+ attr_reader :delegate
4
5
 
5
- def initialize(delegate, body, code, headers)
6
+ def initialize(delegate, body, code, headers={})
6
7
  @delegate = delegate
7
8
  @body = body
8
9
  @code = code
@@ -1,3 +1,3 @@
1
- module HTTParty
2
- Version = '0.2.10'
1
+ module HTTParty #:nodoc:
2
+ Version = '0.3.0'
3
3
  end
@@ -0,0 +1,44 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Hash, "to_xml_attributes" do
4
+ before do
5
+ @hash = { :one => "ONE", "two" => "TWO" }
6
+ end
7
+
8
+ it "should turn the hash into xml attributes" do
9
+ attrs = @hash.to_xml_attributes
10
+ attrs.should match(/one="ONE"/m)
11
+ attrs.should match(/two="TWO"/m)
12
+ end
13
+
14
+ it 'should preserve _ in hash keys' do
15
+ attrs = {
16
+ :some_long_attribute => "with short value",
17
+ :crash => :burn,
18
+ :merb => "uses extlib"
19
+ }.to_xml_attributes
20
+
21
+ attrs.should =~ /some_long_attribute="with short value"/
22
+ attrs.should =~ /merb="uses extlib"/
23
+ attrs.should =~ /crash="burn"/
24
+ end
25
+ end
26
+
27
+
28
+ describe Hash, 'to_params' do
29
+ {
30
+ { "foo" => "bar", "baz" => "bat" } => "foo=bar&baz=bat",
31
+ { "foo" => [ "bar", "baz" ] } => "foo[]=bar&foo[]=baz",
32
+ { "foo" => [ {"bar" => "1"}, {"bar" => 2} ] } => "foo[][bar]=1&foo[][bar]=2",
33
+ { "foo" => { "bar" => [ {"baz" => 1}, {"baz" => "2"} ] } } => "foo[bar][][baz]=1&foo[bar][][baz]=2",
34
+ { "foo" => {"1" => "bar", "2" => "baz"} } => "foo[1]=bar&foo[2]=baz"
35
+ }.each do |hash, params|
36
+ it "should covert hash: #{hash.inspect} to params: #{params.inspect}" do
37
+ hash.to_params.split('&').sort.should == params.split('&').sort
38
+ end
39
+ end
40
+
41
+ it 'should not leave a trailing &' do
42
+ { :name => 'Bob', :address => { :street => '111 Ruby Ave.', :city => 'Ruby Central', :phones => ['111-111-1111', '222-222-2222'] } }.to_params.should_not match(/&$/)
43
+ end
44
+ end
@@ -0,0 +1,41 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
2
+
3
+ describe HTTParty::Parsers::JSON do
4
+ TESTS = {
5
+ %q({"returnTo":{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}},
6
+ %q({returnTo:{"\/categories":"\/"}}) => {"returnTo" => {"/categories" => "/"}},
7
+ %q({"return\\"To\\":":{"\/categories":"\/"}}) => {"return\"To\":" => {"/categories" => "/"}},
8
+ %q({"returnTo":{"\/categories":1}}) => {"returnTo" => {"/categories" => 1}},
9
+ %({"returnTo":[1,"a"]}) => {"returnTo" => [1, "a"]},
10
+ %({"returnTo":[1,"\\"a\\",", "b"]}) => {"returnTo" => [1, "\"a\",", "b"]},
11
+ %({a: "'", "b": "5,000"}) => {"a" => "'", "b" => "5,000"},
12
+ %({a: "a's, b's and c's", "b": "5,000"}) => {"a" => "a's, b's and c's", "b" => "5,000"},
13
+ %({a: "2007-01-01"}) => {'a' => Date.new(2007, 1, 1)},
14
+ %({a: "2007-01-01 01:12:34 Z"}) => {'a' => Time.utc(2007, 1, 1, 1, 12, 34)},
15
+ # no time zone
16
+ %({a: "2007-01-01 01:12:34"}) => {'a' => "2007-01-01 01:12:34"},
17
+ %([]) => [],
18
+ %({}) => {},
19
+ %(1) => 1,
20
+ %("") => "",
21
+ %("\\"") => "\"",
22
+ %(null) => nil,
23
+ %(true) => true,
24
+ %(false) => false,
25
+ %q("http:\/\/test.host\/posts\/1") => "http://test.host/posts/1"
26
+ }
27
+
28
+ TESTS.each do |json, expected|
29
+ it "should decode json (#{json})" do
30
+ lambda {
31
+ HTTParty::Parsers::JSON.decode(json).should == expected
32
+ }.should_not raise_error
33
+ end
34
+ end
35
+
36
+ it "should raise error for failed decoding" do
37
+ lambda {
38
+ HTTParty::Parsers::JSON.decode(%({: 1}))
39
+ }.should raise_error(HTTParty::Parsers::JSON::ParseError)
40
+ end
41
+ end
@@ -0,0 +1,445 @@
1
+ require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
2
+
3
+ require "date"
4
+ require 'bigdecimal'
5
+
6
+ describe HTTParty::Parsers::XML, "#parse" do
7
+ it "should transform a simple tag with content" do
8
+ xml = "<tag>This is the contents</tag>"
9
+ HTTParty::Parsers::XML.parse(xml).should == { 'tag' => 'This is the contents' }
10
+ end
11
+
12
+ it "should work with cdata tags" do
13
+ xml = <<-END
14
+ <tag>
15
+ <![CDATA[
16
+ text inside cdata
17
+ ]]>
18
+ </tag>
19
+ END
20
+ HTTParty::Parsers::XML.parse(xml)["tag"].strip.should == "text inside cdata"
21
+ end
22
+
23
+ it "should transform a simple tag with attributes" do
24
+ xml = "<tag attr1='1' attr2='2'></tag>"
25
+ hash = { 'tag' => { 'attr1' => '1', 'attr2' => '2' } }
26
+ HTTParty::Parsers::XML.parse(xml).should == hash
27
+ end
28
+
29
+ it "should transform repeating siblings into an array" do
30
+ xml =<<-XML
31
+ <opt>
32
+ <user login="grep" fullname="Gary R Epstein" />
33
+ <user login="stty" fullname="Simon T Tyson" />
34
+ </opt>
35
+ XML
36
+
37
+ HTTParty::Parsers::XML.parse(xml)['opt']['user'].should be_an_instance_of(Array)
38
+
39
+ hash = {
40
+ 'opt' => {
41
+ 'user' => [{
42
+ 'login' => 'grep',
43
+ 'fullname' => 'Gary R Epstein'
44
+ },{
45
+ 'login' => 'stty',
46
+ 'fullname' => 'Simon T Tyson'
47
+ }]
48
+ }
49
+ }
50
+
51
+ HTTParty::Parsers::XML.parse(xml).should == hash
52
+ end
53
+
54
+ it "should not transform non-repeating siblings into an array" do
55
+ xml =<<-XML
56
+ <opt>
57
+ <user login="grep" fullname="Gary R Epstein" />
58
+ </opt>
59
+ XML
60
+
61
+ HTTParty::Parsers::XML.parse(xml)['opt']['user'].should be_an_instance_of(Hash)
62
+
63
+ hash = {
64
+ 'opt' => {
65
+ 'user' => {
66
+ 'login' => 'grep',
67
+ 'fullname' => 'Gary R Epstein'
68
+ }
69
+ }
70
+ }
71
+
72
+ HTTParty::Parsers::XML.parse(xml).should == hash
73
+ end
74
+
75
+ it "should typecast an integer" do
76
+ xml = "<tag type='integer'>10</tag>"
77
+ HTTParty::Parsers::XML.parse(xml)['tag'].should == 10
78
+ end
79
+
80
+ it "should typecast a true boolean" do
81
+ xml = "<tag type='boolean'>true</tag>"
82
+ HTTParty::Parsers::XML.parse(xml)['tag'].should be_true
83
+ end
84
+
85
+ it "should typecast a false boolean" do
86
+ ["false"].each do |w|
87
+ HTTParty::Parsers::XML.parse("<tag type='boolean'>#{w}</tag>")['tag'].should be_false
88
+ end
89
+ end
90
+
91
+ it "should typecast a datetime" do
92
+ xml = "<tag type='datetime'>2007-12-31 10:32</tag>"
93
+ HTTParty::Parsers::XML.parse(xml)['tag'].should == Time.parse( '2007-12-31 10:32' ).utc
94
+ end
95
+
96
+ it "should typecast a date" do
97
+ xml = "<tag type='date'>2007-12-31</tag>"
98
+ HTTParty::Parsers::XML.parse(xml)['tag'].should == Date.parse('2007-12-31')
99
+ end
100
+
101
+ it "should unescape html entities" do
102
+ values = {
103
+ "<" => "&lt;",
104
+ ">" => "&gt;",
105
+ '"' => "&quot;",
106
+ "'" => "&apos;",
107
+ "&" => "&amp;"
108
+ }
109
+ values.each do |k,v|
110
+ xml = "<tag>Some content #{v}</tag>"
111
+ HTTParty::Parsers::XML.parse(xml)['tag'].should match(Regexp.new(k))
112
+ end
113
+ end
114
+
115
+ it "should undasherize keys as tags" do
116
+ xml = "<tag-1>Stuff</tag-1>"
117
+ HTTParty::Parsers::XML.parse(xml).keys.should include( 'tag_1' )
118
+ end
119
+
120
+ it "should undasherize keys as attributes" do
121
+ xml = "<tag1 attr-1='1'></tag1>"
122
+ HTTParty::Parsers::XML.parse(xml)['tag1'].keys.should include( 'attr_1')
123
+ end
124
+
125
+ it "should undasherize keys as tags and attributes" do
126
+ xml = "<tag-1 attr-1='1'></tag-1>"
127
+ HTTParty::Parsers::XML.parse(xml).keys.should include( 'tag_1' )
128
+ HTTParty::Parsers::XML.parse(xml)['tag_1'].keys.should include( 'attr_1')
129
+ end
130
+
131
+ it "should render nested content correctly" do
132
+ xml = "<root><tag1>Tag1 Content <em><strong>This is strong</strong></em></tag1></root>"
133
+ HTTParty::Parsers::XML.parse(xml)['root']['tag1'].should == "Tag1 Content <em><strong>This is strong</strong></em>"
134
+ end
135
+
136
+ it "should render nested content with split text nodes correctly" do
137
+ xml = "<root>Tag1 Content<em>Stuff</em> Hi There</root>"
138
+ HTTParty::Parsers::XML.parse(xml)['root'].should == "Tag1 Content<em>Stuff</em> Hi There"
139
+ end
140
+
141
+ it "should ignore attributes when a child is a text node" do
142
+ xml = "<root attr1='1'>Stuff</root>"
143
+ HTTParty::Parsers::XML.parse(xml).should == { "root" => "Stuff" }
144
+ end
145
+
146
+ it "should ignore attributes when any child is a text node" do
147
+ xml = "<root attr1='1'>Stuff <em>in italics</em></root>"
148
+ HTTParty::Parsers::XML.parse(xml).should == { "root" => "Stuff <em>in italics</em>" }
149
+ end
150
+
151
+ it "should correctly transform multiple children" do
152
+ xml = <<-XML
153
+ <user gender='m'>
154
+ <age type='integer'>35</age>
155
+ <name>Home Simpson</name>
156
+ <dob type='date'>1988-01-01</dob>
157
+ <joined-at type='datetime'>2000-04-28 23:01</joined-at>
158
+ <is-cool type='boolean'>true</is-cool>
159
+ </user>
160
+ XML
161
+
162
+ hash = {
163
+ "user" => {
164
+ "gender" => "m",
165
+ "age" => 35,
166
+ "name" => "Home Simpson",
167
+ "dob" => Date.parse('1988-01-01'),
168
+ "joined_at" => Time.parse("2000-04-28 23:01"),
169
+ "is_cool" => true
170
+ }
171
+ }
172
+
173
+ HTTParty::Parsers::XML.parse(xml).should == hash
174
+ end
175
+
176
+ it "should properly handle nil values (ActiveSupport Compatible)" do
177
+ topic_xml = <<-EOT
178
+ <topic>
179
+ <title></title>
180
+ <id type="integer"></id>
181
+ <approved type="boolean"></approved>
182
+ <written-on type="date"></written-on>
183
+ <viewed-at type="datetime"></viewed-at>
184
+ <content type="yaml"></content>
185
+ <parent-id></parent-id>
186
+ </topic>
187
+ EOT
188
+
189
+ expected_topic_hash = {
190
+ 'title' => nil,
191
+ 'id' => nil,
192
+ 'approved' => nil,
193
+ 'written_on' => nil,
194
+ 'viewed_at' => nil,
195
+ 'content' => nil,
196
+ 'parent_id' => nil
197
+ }
198
+ HTTParty::Parsers::XML.parse(topic_xml)["topic"].should == expected_topic_hash
199
+ end
200
+
201
+ it "should handle a single record from xml (ActiveSupport Compatible)" do
202
+ topic_xml = <<-EOT
203
+ <topic>
204
+ <title>The First Topic</title>
205
+ <author-name>David</author-name>
206
+ <id type="integer">1</id>
207
+ <approved type="boolean"> true </approved>
208
+ <replies-count type="integer">0</replies-count>
209
+ <replies-close-in type="integer">2592000000</replies-close-in>
210
+ <written-on type="date">2003-07-16</written-on>
211
+ <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
212
+ <content type="yaml">--- \n1: should be an integer\n:message: Have a nice day\narray: \n- should-have-dashes: true\n should_have_underscores: true\n</content>
213
+ <author-email-address>david@loudthinking.com</author-email-address>
214
+ <parent-id></parent-id>
215
+ <ad-revenue type="decimal">1.5</ad-revenue>
216
+ <optimum-viewing-angle type="float">135</optimum-viewing-angle>
217
+ <resident type="symbol">yes</resident>
218
+ </topic>
219
+ EOT
220
+
221
+ expected_topic_hash = {
222
+ 'title' => "The First Topic",
223
+ 'author_name' => "David",
224
+ 'id' => 1,
225
+ 'approved' => true,
226
+ 'replies_count' => 0,
227
+ 'replies_close_in' => 2592000000,
228
+ 'written_on' => Date.new(2003, 7, 16),
229
+ 'viewed_at' => Time.utc(2003, 7, 16, 9, 28),
230
+ # Changed this line where the key is :message. The yaml specifies this as a symbol, and who am I to change what you specify
231
+ # The line in ActiveSupport is
232
+ # 'content' => { 'message' => "Have a nice day", 1 => "should be an integer", "array" => [{ "should-have-dashes" => true, "should_have_underscores" => true }] },
233
+ 'content' => { :message => "Have a nice day", 1 => "should be an integer", "array" => [{ "should-have-dashes" => true, "should_have_underscores" => true }] },
234
+ 'author_email_address' => "david@loudthinking.com",
235
+ 'parent_id' => nil,
236
+ 'ad_revenue' => BigDecimal("1.50"),
237
+ 'optimum_viewing_angle' => 135.0,
238
+ 'resident' => :yes
239
+ }
240
+
241
+ HTTParty::Parsers::XML.parse(topic_xml)["topic"].each do |k,v|
242
+ v.should == expected_topic_hash[k]
243
+ end
244
+ end
245
+
246
+ it "should handle multiple records (ActiveSupport Compatible)" do
247
+ topics_xml = <<-EOT
248
+ <topics type="array">
249
+ <topic>
250
+ <title>The First Topic</title>
251
+ <author-name>David</author-name>
252
+ <id type="integer">1</id>
253
+ <approved type="boolean">false</approved>
254
+ <replies-count type="integer">0</replies-count>
255
+ <replies-close-in type="integer">2592000000</replies-close-in>
256
+ <written-on type="date">2003-07-16</written-on>
257
+ <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
258
+ <content>Have a nice day</content>
259
+ <author-email-address>david@loudthinking.com</author-email-address>
260
+ <parent-id nil="true"></parent-id>
261
+ </topic>
262
+ <topic>
263
+ <title>The Second Topic</title>
264
+ <author-name>Jason</author-name>
265
+ <id type="integer">1</id>
266
+ <approved type="boolean">false</approved>
267
+ <replies-count type="integer">0</replies-count>
268
+ <replies-close-in type="integer">2592000000</replies-close-in>
269
+ <written-on type="date">2003-07-16</written-on>
270
+ <viewed-at type="datetime">2003-07-16T09:28:00+0000</viewed-at>
271
+ <content>Have a nice day</content>
272
+ <author-email-address>david@loudthinking.com</author-email-address>
273
+ <parent-id></parent-id>
274
+ </topic>
275
+ </topics>
276
+ EOT
277
+
278
+ expected_topic_hash = {
279
+ 'title' => "The First Topic",
280
+ 'author_name' => "David",
281
+ 'id' => 1,
282
+ 'approved' => false,
283
+ 'replies_count' => 0,
284
+ 'replies_close_in' => 2592000000,
285
+ 'written_on' => Date.new(2003, 7, 16),
286
+ 'viewed_at' => Time.utc(2003, 7, 16, 9, 28),
287
+ 'content' => "Have a nice day",
288
+ 'author_email_address' => "david@loudthinking.com",
289
+ 'parent_id' => nil
290
+ }
291
+ # puts HTTParty::Parsers::XML.parse(topics_xml)['topics'].first.inspect
292
+ HTTParty::Parsers::XML.parse(topics_xml)["topics"].first.each do |k,v|
293
+ v.should == expected_topic_hash[k]
294
+ end
295
+ end
296
+
297
+ it "should handle a single record from_xml with attributes other than type (ActiveSupport Compatible)" do
298
+ topic_xml = <<-EOT
299
+ <rsp stat="ok">
300
+ <photos page="1" pages="1" perpage="100" total="16">
301
+ <photo id="175756086" owner="55569174@N00" secret="0279bf37a1" server="76" title="Colored Pencil PhotoBooth Fun" ispublic="1" isfriend="0" isfamily="0"/>
302
+ </photos>
303
+ </rsp>
304
+ EOT
305
+
306
+ expected_topic_hash = {
307
+ 'id' => "175756086",
308
+ 'owner' => "55569174@N00",
309
+ 'secret' => "0279bf37a1",
310
+ 'server' => "76",
311
+ 'title' => "Colored Pencil PhotoBooth Fun",
312
+ 'ispublic' => "1",
313
+ 'isfriend' => "0",
314
+ 'isfamily' => "0",
315
+ }
316
+ HTTParty::Parsers::XML.parse(topic_xml)["rsp"]["photos"]["photo"].each do |k,v|
317
+ v.should == expected_topic_hash[k]
318
+ end
319
+ end
320
+
321
+ it "should handle an emtpy array (ActiveSupport Compatible)" do
322
+ blog_xml = <<-XML
323
+ <blog>
324
+ <posts type="array"></posts>
325
+ </blog>
326
+ XML
327
+ expected_blog_hash = {"blog" => {"posts" => []}}
328
+ HTTParty::Parsers::XML.parse(blog_xml).should == expected_blog_hash
329
+ end
330
+
331
+ it "should handle empty array with whitespace from xml (ActiveSupport Compatible)" do
332
+ blog_xml = <<-XML
333
+ <blog>
334
+ <posts type="array">
335
+ </posts>
336
+ </blog>
337
+ XML
338
+ expected_blog_hash = {"blog" => {"posts" => []}}
339
+ HTTParty::Parsers::XML.parse(blog_xml).should == expected_blog_hash
340
+ end
341
+
342
+ it "should handle array with one entry from_xml (ActiveSupport Compatible)" do
343
+ blog_xml = <<-XML
344
+ <blog>
345
+ <posts type="array">
346
+ <post>a post</post>
347
+ </posts>
348
+ </blog>
349
+ XML
350
+ expected_blog_hash = {"blog" => {"posts" => ["a post"]}}
351
+ HTTParty::Parsers::XML.parse(blog_xml).should == expected_blog_hash
352
+ end
353
+
354
+ it "should handle array with multiple entries from xml (ActiveSupport Compatible)" do
355
+ blog_xml = <<-XML
356
+ <blog>
357
+ <posts type="array">
358
+ <post>a post</post>
359
+ <post>another post</post>
360
+ </posts>
361
+ </blog>
362
+ XML
363
+ expected_blog_hash = {"blog" => {"posts" => ["a post", "another post"]}}
364
+ HTTParty::Parsers::XML.parse(blog_xml).should == expected_blog_hash
365
+ end
366
+
367
+ it "should handle file types (ActiveSupport Compatible)" do
368
+ blog_xml = <<-XML
369
+ <blog>
370
+ <logo type="file" name="logo.png" content_type="image/png">
371
+ </logo>
372
+ </blog>
373
+ XML
374
+ hash = HTTParty::Parsers::XML.parse(blog_xml)
375
+ hash.should have_key('blog')
376
+ hash['blog'].should have_key('logo')
377
+
378
+ file = hash['blog']['logo']
379
+ file.original_filename.should == 'logo.png'
380
+ file.content_type.should == 'image/png'
381
+ end
382
+
383
+ it "should handle file from xml with defaults (ActiveSupport Compatible)" do
384
+ blog_xml = <<-XML
385
+ <blog>
386
+ <logo type="file">
387
+ </logo>
388
+ </blog>
389
+ XML
390
+ file = HTTParty::Parsers::XML.parse(blog_xml)['blog']['logo']
391
+ file.original_filename.should == 'untitled'
392
+ file.content_type.should == 'application/octet-stream'
393
+ end
394
+
395
+ it "should handle xsd like types from xml (ActiveSupport Compatible)" do
396
+ bacon_xml = <<-EOT
397
+ <bacon>
398
+ <weight type="double">0.5</weight>
399
+ <price type="decimal">12.50</price>
400
+ <chunky type="boolean"> 1 </chunky>
401
+ <expires-at type="dateTime">2007-12-25T12:34:56+0000</expires-at>
402
+ <notes type="string"></notes>
403
+ <illustration type="base64Binary">YmFiZS5wbmc=</illustration>
404
+ </bacon>
405
+ EOT
406
+
407
+ expected_bacon_hash = {
408
+ 'weight' => 0.5,
409
+ 'chunky' => true,
410
+ 'price' => BigDecimal("12.50"),
411
+ 'expires_at' => Time.utc(2007,12,25,12,34,56),
412
+ 'notes' => "",
413
+ 'illustration' => "babe.png"
414
+ }
415
+
416
+ HTTParty::Parsers::XML.parse(bacon_xml)["bacon"].should == expected_bacon_hash
417
+ end
418
+
419
+ it "should let type trickle through when unknown (ActiveSupport Compatible)" do
420
+ product_xml = <<-EOT
421
+ <product>
422
+ <weight type="double">0.5</weight>
423
+ <image type="ProductImage"><filename>image.gif</filename></image>
424
+
425
+ </product>
426
+ EOT
427
+
428
+ expected_product_hash = {
429
+ 'weight' => 0.5,
430
+ 'image' => {'type' => 'ProductImage', 'filename' => 'image.gif' },
431
+ }
432
+
433
+ HTTParty::Parsers::XML.parse(product_xml)["product"].should == expected_product_hash
434
+ end
435
+
436
+ it "should handle unescaping from xml (ActiveResource Compatible)" do
437
+ xml_string = '<person><bare-string>First &amp; Last Name</bare-string><pre-escaped-string>First &amp;amp; Last Name</pre-escaped-string></person>'
438
+ expected_hash = {
439
+ 'bare_string' => 'First & Last Name',
440
+ 'pre_escaped_string' => 'First &amp; Last Name'
441
+ }
442
+
443
+ HTTParty::Parsers::XML.parse(xml_string)['person'].should == expected_hash
444
+ end
445
+ end