well_rested 0.6.0

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,15 @@
1
+ module WellRested
2
+ class CamelCaseFormatter
3
+ def initialize(lower = true)
4
+ raise "Upper case camelizing not supported yet" unless lower # TODO: Support upper-camel-casing
5
+ end
6
+
7
+ def encode(hash)
8
+ KeyTransformer.camelize_keys(hash)
9
+ end
10
+
11
+ def decode(hash)
12
+ KeyTransformer.underscore_keys(hash)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+
2
+ module WellRested
3
+ class JSONFormatter
4
+ def encode(obj)
5
+ obj.to_json
6
+ end
7
+
8
+ def decode(serialized_representation)
9
+ JSON.parse(serialized_representation)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,26 @@
1
+ require 'generic_utils'
2
+
3
+ module WellRested
4
+ module Utils
5
+ extend GenericUtils
6
+ extend self
7
+
8
+ # Turn any nested resources back into hashes before sending them
9
+ def objects_to_attributes(obj)
10
+ if obj.respond_to?(:attributes_for_api)
11
+ obj.attributes_for_api
12
+ elsif obj.kind_of?(Hash)
13
+ new_attributes = {}.with_indifferent_access
14
+ obj.each do |k, v|
15
+ new_attributes[k] = objects_to_attributes(v)
16
+ end
17
+ new_attributes
18
+ elsif obj.kind_of?(Array)
19
+ obj.map { |e| self.objects_to_attributes(e) }
20
+ else
21
+ obj
22
+ #raise "Attributes was not a Hash or Enumerable"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,619 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
4
+
5
+ describe API do
6
+ before(:each) do
7
+ @account_class = Class.new(Base) do
8
+ self.path = '/accounts'
9
+ end
10
+ @user_class = Class.new(Base) do
11
+ self.path = '/accounts/:account_id/users'
12
+ end
13
+ end
14
+
15
+ before do
16
+ @api = mock_api
17
+ FakeWeb.register_uri(:get, %r|/accounts$|, :body => '[{}]')
18
+ FakeWeb.register_uri(:get, %r|/accounts/1$|, :body => '{}')
19
+ FakeWeb.register_uri(:get, %r|/accounts/1/users|, :body => '[{}]', 'x_record_count' => '2')
20
+ FakeWeb.register_uri(:get, %r|/accounts/1/users/1|, :body => '{}')
21
+ end
22
+
23
+ after do
24
+ FakeWeb.clean_registry
25
+ end
26
+
27
+ describe "class methods" do
28
+ describe ".request_headers" do
29
+ subject { API.request_headers }
30
+ it { should be_a Hash }
31
+ end
32
+
33
+ describe '.fill_path' do
34
+ it "should return the path with filled parameters" do
35
+ API.fill_path('/something/:that/has/:parameters', :that => 'foo', :parameters => 'bar').should == '/something/foo/has/bar'
36
+ end
37
+
38
+ it "should raise an exception if there are unmatched parameters" do
39
+ expect { API.fill_path('/something/:that/lacks/:parameters', :that => 'foo') }.should raise_error ArgumentError
40
+ end
41
+
42
+ it "should raise an exception if there is a blank param" do
43
+ expect { API.fill_path('/something/:that/lacks/parameters', :that => '') }.should raise_error ArgumentError
44
+ end
45
+ end
46
+ end
47
+
48
+ describe '.request_headers' do
49
+ subject { @api.request_headers }
50
+ it { should be_a Hash }
51
+ end
52
+
53
+ describe ".url_for" do
54
+ it "should substitute path params" do
55
+ @api.url_for(@user_class, :account_id => 1).should match /accounts\/1\/users/
56
+ end
57
+
58
+ it "should append query params when passed a hash" do
59
+ @api.url_for(@account_class, {}, :count => 4).should match /accounts\?count=4$/
60
+ end
61
+
62
+ it "should append query params when passed a string" do
63
+ @api.url_for(@account_class, '/accounts', :count => 4).should match /accounts\?count=4$/
64
+ end
65
+
66
+ it "should attribute-encode query params" do
67
+ @account_class.attribute_formatter = CamelCaseFormatter.new
68
+ @api.url_for(@account_class, '/accounts', :my_count => 4).should match /accounts\?myCount=4$/
69
+ end
70
+
71
+ it "should use the specified extension" do
72
+ @account_class.extension = '.foobar'
73
+ @api.url_for(@account_class, '/accounts', :my_count => 4).should match /accounts.foobar\?myCount=4$/
74
+ end
75
+
76
+ context "with auth set" do
77
+ before do
78
+ @api.user = 'admin'
79
+ @api.password = 'password'
80
+ end
81
+
82
+ it "should generate a url with auth" do
83
+ @api.url_for(@account_class).should match /:\/\/admin:password@/
84
+ end
85
+ end
86
+ end
87
+
88
+ describe ".default_path_parameters" do
89
+ context "with empty initializer" do
90
+ subject { @api.default_path_parameters }
91
+
92
+ it { should be_empty }
93
+ end
94
+
95
+ context "with params in initializer" do
96
+ before { @api = API.new(:account_id => 7, :id => 2) }
97
+
98
+ it "should have the passed value" do
99
+ @api.default_path_parameters.should == { 'account_id' => 7, 'id' => 2 }
100
+ end
101
+
102
+ it "should use the default path params when generating URLs" do
103
+ @api.url_for(@user_class).should =~ /accounts\/7\/users\/2/
104
+ end
105
+ end
106
+ end
107
+
108
+ describe 'API Calls' do
109
+ describe ".request" do
110
+ it "should issue a PUT request" do
111
+ FakeWeb.register_uri(:put, "#{base_path}/request_put_test", :body => '')
112
+ @api.request(Base, :put, "/request_put_test")
113
+ FakeWeb.should have_requested(:put, "http://#{base_path}/request_put_test")
114
+ end
115
+
116
+ it "should issue a POST request" do
117
+ FakeWeb.register_uri(:post, "#{base_path}/request_post_test", :body => '{}')
118
+ @api.request(Base, :post, "/request_post_test")
119
+ FakeWeb.should have_requested(:post, "http://#{base_path}/request_post_test")
120
+ end
121
+
122
+ it "should issue a GET request" do
123
+ FakeWeb.register_uri(:get, "#{base_path}/request_get_test", :body => '{}')
124
+ @api.request(Base, :get, "/request_get_test")
125
+ FakeWeb.should have_requested(:get, "http://#{base_path}/request_get_test")
126
+ end
127
+
128
+ it "should issue a DELETE request" do
129
+ FakeWeb.register_uri(:delete, "#{base_path}/request_del_test", :body => '')
130
+ @api.request(Base, :delete, "/request_del_test")
131
+ FakeWeb.should have_requested(:delete, "http://#{base_path}/request_del_test")
132
+ end
133
+
134
+ context "when passed a fully qualified url" do
135
+ before { FakeWeb.register_uri(:get, "#{base_path}/request_get_url", :body => '{}') }
136
+
137
+ it "should use it directly" do
138
+ @api.request(Base, :get, "http://#{base_path}/request_get_url")
139
+ end
140
+ end
141
+
142
+ context "when passed a relative path (beginning with a slash)" do
143
+ before { FakeWeb.register_uri(:get, "#{base_path}/request_get_path", :body => '{}') }
144
+
145
+ it "should fill it out" do
146
+ @api.request(Base, :get, "/request_get_path")
147
+ end
148
+ end
149
+ end
150
+
151
+ describe '.find' do
152
+ context "when passed a url" do
153
+ before {
154
+ @path = "#{base_path}/my/weird/path"
155
+ FakeWeb.register_uri(:get, @path, :body => '{}')
156
+ @account = @api.find(@account_class, '/my/weird/path')
157
+ }
158
+ it "should use the URL" do
159
+ FakeWeb.should have_requested(:get, "http://#{@path}")
160
+ end
161
+
162
+ it "should return a resource of the requested type" do
163
+ @account.should be_an @account_class
164
+ end
165
+
166
+ it "should raise an exception if the server returns 404" do
167
+ expect { @api.find(@account_class, "/notfound") }.should raise_error
168
+ end
169
+ end
170
+
171
+ context "when passed path params" do
172
+ before { @account = @api.find(@account_class, :id => 1) }
173
+
174
+ it "should return a resource of the requested type" do
175
+ @account.should be_an @account_class
176
+ end
177
+
178
+ it "should handle query params" do
179
+ FakeWeb.register_uri(:get, %r|/accounts\/1\?test=true|, :body => '{}')
180
+ @api.find(@account_class, {:id => 1}, :test => 'true')
181
+ FakeWeb.should have_requested(:get, %r|/accounts\/1\?test=true|)
182
+ end
183
+
184
+ it "should create the resource using new_from_api" do
185
+ @account_class.should_receive(:new_from_api)
186
+ @api.find(@account_class, :id => 1)
187
+ end
188
+ end
189
+
190
+ context "it includes a camelized attribute name" do
191
+ before(:each) do
192
+ @api.client.should_receive(:get).and_return '{ "camelizedAttrName" : "value" }'
193
+ @user = @api.find(@account_class, :id => 1)
194
+ end
195
+
196
+ it "should not include camelize attribute names" do
197
+ @user.attributes.should_not include('camelizedAttrName')
198
+ end
199
+
200
+ it "should include decamelized attribute names" do
201
+ @user.attributes['camelized_attr_name'].should == "value"
202
+ end
203
+ end
204
+
205
+ context "when a resource is passed instead of a class and params" do
206
+ before do
207
+ FakeWeb.register_uri(:get, %r|/test/7/foo/4|, :body => '{}')
208
+ end
209
+ it "should use the path_parameters as path parameters" do
210
+ klass = Class.new(Base) do
211
+ self.path = '/test/:account_id/foo'
212
+ end
213
+ res = klass.new(:id => 4, :account_id => 7)
214
+ @api.find(res)
215
+ FakeWeb.should have_requested(:get, %r|/test/7/foo/4|)
216
+ end
217
+ end
218
+
219
+ end
220
+
221
+ describe '.find_many' do
222
+ it "should allow a URL override" do
223
+ FakeWeb.register_uri(:get, %r|\/alternate\/users\/path|, :body => '[]')
224
+ @api.find_many(@user_class, '/alternate/users/path')
225
+ FakeWeb.should have_requested(:get, %r|\/alternate\/users\/path|)
226
+ end
227
+
228
+ it "should set last_response on @api with headers" do
229
+ @api.last_response.should be_nil # sanity check
230
+ @users = @api.find_many(@user_class, :account_id => 1)
231
+ @api.last_response.headers[:'x_record_count'].should == '2'
232
+ end
233
+
234
+ context "with no parameters" do
235
+ before(:each) { @users = @api.find_many(@user_class, :account_id => 1) }
236
+
237
+ it "should return a collection of objects of the requested type" do
238
+ @users.should be_an Array
239
+ @users.size.should be > 0 # sanity check
240
+ @users.each { |a| a.should be_a @user_class }
241
+ end
242
+ end
243
+
244
+ context "with parameters" do
245
+ before { @users = @api.find_many(@user_class, {:account_id => 1}, :count => 1) }
246
+
247
+ it "should return the number of objects requested" do
248
+ @users.size.should == 1
249
+ end
250
+
251
+ it "should create the resources using new_from_api" do
252
+ @user_class.should_receive(:new_from_api).any_number_of_times
253
+ @api.find_many(@user_class, {:account_id => 1}, :count => 1)
254
+ end
255
+ end
256
+
257
+ end
258
+
259
+ describe ".create" do
260
+ before do
261
+ FakeWeb.register_uri(:post, %r||, :body => '{ "id": "test" }', :status => 200)
262
+ @klass = Class.new(Base) { self.path = '' }
263
+ @res = @klass.new
264
+ end
265
+
266
+ it "should allow a URL override" do
267
+ FakeWeb.clean_registry
268
+ FakeWeb.register_uri(:post, %r|/alternative/path|, :body => '{ "id": "test" }')
269
+ @api.create(@klass, {}, '/alternative/path')
270
+ FakeWeb.should have_requested(:post, %r|/alternative/path|)
271
+ end
272
+
273
+ it "should create the object using new" do
274
+ @klass.should_receive(:new).at_least(:once).and_return(@res)
275
+ @api.create(@klass, {})
276
+ end
277
+
278
+ it "should call attributes_for_api on the resource" do
279
+ @klass.stub!(:new).and_return(@res)
280
+ @res.should_receive(:attributes_for_api).at_least(:once).and_return({})
281
+ @api.create(@klass)
282
+ end
283
+ it "should not call attributes on the resource" do
284
+ @klass.stub!(:new_from_api).and_return(@res)
285
+ @res.should_not_receive(:attributes)
286
+ @api.create(@klass)
287
+ end
288
+
289
+ it "should camelize keys" do
290
+ attributes = { :underscored_key => 'foo' }
291
+ @api.client.should_receive(:post).with(anything, {:underscoredKey => 'foo'}.to_json, anything).and_return(double(:code => 200, :body => '{}'))
292
+ @api.create(@klass, attributes)
293
+ end
294
+
295
+ context "when the resource is valid" do
296
+ before(:each) do
297
+ @attrs = { :account_id => 1, :first_name => 'FirsTest', :last_name => 'LasTest', :email_address => 'a@b' }
298
+ @user_class.new(@attrs).should be_valid # sanity check that user is really valid
299
+ end
300
+
301
+ it "should POST to the resource path" do
302
+ user = @api.create(@user_class, @attrs)
303
+ user.should be_a @user_class
304
+ end
305
+ end
306
+
307
+ context "when an ID is set" do
308
+ before { @res = @klass.new(:id => 9) }
309
+
310
+ it "should not issue a POST" do
311
+ @api.client.stub(:put).and_return(double(:code => 200, :body => '{}'))
312
+ @api.client.should_not_receive(:post)
313
+ @api.save(@res)
314
+ end
315
+
316
+ it "should issue a PUT" do
317
+ @api.client.should_receive(:put).and_return(double(:code => 200, :body => '{}'))
318
+ @api.save(@res)
319
+ end
320
+ end
321
+
322
+ context "when the resource is invalid" do
323
+ it "should return false" do
324
+ klass = Class.new(Base) do
325
+ def valid?
326
+ false
327
+ end
328
+ end
329
+ klass.new.should_not be_valid
330
+
331
+ @api.create(klass, {}).should == false
332
+ end
333
+ end
334
+
335
+ context "when saving a new record" do
336
+ it "should mark the record persisted after save completes" do
337
+ @res.should be_new_record # sanity check
338
+ @api.save(@res)
339
+ @res.should_not be_new_record
340
+ end
341
+ end
342
+
343
+ context "when the resource is an array" do
344
+ before do
345
+ @klass = Class.new(Base) do
346
+ self.path = '/array/resource'
347
+ end
348
+ FakeWeb.clean_registry
349
+ FakeWeb.register_uri(:post, %r|/array\/resource$|, :body => '[{"name":"one"}, {"name":"two"}]')
350
+ end
351
+
352
+ it "should return an array when the resource is an array" do
353
+ res = @api.create(@klass)
354
+ res.should be_an Array
355
+ res.first.name.should == "one"
356
+ res.last.name.should == "two"
357
+ end
358
+ end
359
+
360
+ end
361
+
362
+ describe '.save' do
363
+ before do
364
+ @klass = Class.new(Base) { self.path = '' }
365
+ @res = @klass.new(:id => 4)
366
+ end
367
+
368
+ it "should set the correct content-type" do
369
+ @user = @user_class.new :first_name => 'First', :last_name => 'Last',
370
+ :account_id => 1, :email_address => 'user@foo', :password => 'foobar', :id => 77
371
+
372
+ @api.client.should_receive(:put).with(@api.url_for(@user_class, @user.attributes_for_api),
373
+ KeyTransformer.camelize_keys(@user.attributes_for_api).to_json,
374
+ @api.request_headers).and_return(double(:code => 200, :body => '{}'))
375
+ @api.save(@user)
376
+ end
377
+
378
+ it "should camelize keys" do
379
+ @res.load(:id => 4, :underscored_key => 'foo')
380
+ @api.client.should_receive(:put).with(anything, {:id => 4, :underscoredKey => 'foo'}.to_json, anything).and_return(
381
+ double(:code => 200, :body => '{}'))
382
+ @api.save(@res)
383
+ end
384
+
385
+ context "when attributes_for_api and path_params differ" do
386
+ before do
387
+ @klass = Class.new(Base) do
388
+ self.path = '/test/:special_attr/blah'
389
+ define_schema :id, :special_attr
390
+ end
391
+ @res = @klass.new
392
+ @res.id = 4
393
+ @res.stub!(:attributes).and_return({:id => 4, :special_attr => 'bad' }.with_indifferent_access)
394
+ @res.stub!(:attributes_for_api).and_return({:id => 4, :special_attr => 'bad' }.with_indifferent_access)
395
+ @res.stub!(:path_parameters).and_return({:id => 4, :special_attr => 'good'}.with_indifferent_access)
396
+ end
397
+
398
+ it "should use the path_parameters for path substitution" do
399
+ FakeWeb.register_uri(:put, %r|/test/good/blah/4$|, :body => '{}')
400
+ #FakeWeb.should have_requested(:put, %r|/test/foo/blah/4$|) # why doesn't this work?
401
+
402
+ @api.save(@res)
403
+ end
404
+
405
+ it "should use the attributes_for_api for the payload" do
406
+ @api.client.should_receive(:put).with(anything(), {:id => 4, :specialAttr => 'bad'}.to_json, anything()).and_return(
407
+ double(:body => '{}', :code => 200))
408
+ @api.save(@res)
409
+ end
410
+ end
411
+
412
+ context "when save succeeds" do
413
+ before do
414
+ FakeWeb.register_uri(:put, %r|.*|, :body => '{"newattr":"newval"}')
415
+ @api.save(@res)
416
+ end
417
+
418
+ it "should be updated in place" do
419
+ @res.newattr.should == 'newval'
420
+ end
421
+ end
422
+
423
+ context "when host returns a 422" do
424
+ before do
425
+ @res = @klass.new(:id => 4, :attr => 'val')
426
+ FakeWeb.register_uri(:put, %r||, :body => '{"errors":["first"]}', :status => 422)
427
+ end
428
+
429
+ it "should return false" do
430
+ ret = @api.save(@res)
431
+ ret.should == false
432
+ end
433
+
434
+ it "should not modify the resource, except to add errors" do
435
+ old_attrs = @res.attributes.clone
436
+ ret = @api.save(@res)
437
+ @res.attributes.should == old_attrs
438
+ @res.errors.to_hash.should == {:base => ['first']}
439
+ end
440
+ end
441
+
442
+ context "when host returns a 400" do
443
+ before do
444
+ @res = @klass.new(:id => 4, :attr => 'val')
445
+ FakeWeb.register_uri(:put, %r||, :body => '', :status => 400)
446
+ end
447
+
448
+ it "should raise an error" do
449
+ expect { @api.save(@res) }.should raise_error RestClient::BadRequest
450
+ end
451
+ end
452
+
453
+ context "when no ID is set" do
454
+ before { @res = @klass.new }
455
+ it "should issue a POST instead of a PUT" do
456
+ FakeWeb.register_uri(:post, %r||, :body => '{}')
457
+ @api.save(@res)
458
+ end
459
+ end
460
+
461
+ context "when the resource is invalid" do
462
+ it "should return false" do
463
+ klass = Class.new(Base) do
464
+ self.path = ''
465
+ end
466
+ r = klass.new :id => 1
467
+ r.should_receive('valid?').and_return(false)
468
+ @api.client.stub!(:put).and_return('{}')
469
+ @api.save(r).should == false
470
+ end
471
+ end
472
+ end
473
+
474
+ describe ".delete" do
475
+ context "when called on a class" do
476
+ it "should issue a delete to the specified ID" do
477
+ attrs = { :account_id => 1, :id => 7 }
478
+ FakeWeb.register_uri(:delete, @api.url_for(@user_class, attrs), :status => 200, :body => '')
479
+ @api.delete(@user_class, attrs)
480
+ FakeWeb.should have_requested(:delete, @api.url_for(@user_class, attrs))
481
+ end
482
+
483
+ it "should allow a URL override" do
484
+ FakeWeb.register_uri(:delete, %r|/alternate/delete/path|, :status => 200, :body => '')
485
+ @api.delete(@user_class, '/alternate/delete/path')
486
+ FakeWeb.should have_requested(:delete, %r|/alternate/delete/path|)
487
+ end
488
+ end
489
+ context "when called on a resource" do
490
+ before { @res = @user_class.new(:account_id => 1, :id => 7) }
491
+
492
+ it "should DELETE on the resource's url" do
493
+ FakeWeb.register_uri(:delete, @api.url_for(@user_class, @res.attributes), :status => 200, :body => '')
494
+ @api.delete(@res)
495
+ FakeWeb.should have_requested(:delete, @api.url_for(@user_class, @res.attributes))
496
+ end
497
+ end
498
+ end
499
+
500
+ describe ".get" do
501
+ context "when the response is an XML array" do
502
+ before do
503
+ FakeWeb.register_uri(:get, %r|/array\/resource$|, :body => '<?xml version="1.0" encoding="UTF-8"?><hash></hash>')
504
+ @response = @api.get("#{base_path}/array/resource", XMLFormatter.new)
505
+ end
506
+ it "should return an array" do
507
+ pending
508
+ @response.should be_an Array
509
+ end
510
+ end
511
+
512
+ context "when the response is a json array" do
513
+ before do
514
+ FakeWeb.register_uri(:get, %r|/array\/resource$|, :body => '[{"name":"one"}, {"name":"two"}]')
515
+ @response = @api.get("#{base_path}/array/resource")
516
+ end
517
+ it "should return an array" do
518
+ @response.should be_an Array
519
+ end
520
+ end
521
+
522
+ context "when the response is a hash" do
523
+ before do
524
+ FakeWeb.register_uri(:get, %r|/hash\/resource$|, :body => '{"name":"one"}')
525
+ @response = @api.get("#{base_path}/hash/resource")
526
+ end
527
+ it "should return a hash" do
528
+ @response.should be_a Hash
529
+ end
530
+ end
531
+
532
+ # TODO: Make this format-agnostic
533
+ context "when the response isn't valid JSON" do
534
+ before { FakeWeb.register_uri(:get, %r|/invalid/json$|, :body => 'bogus') }
535
+ context "we're expecting json" do
536
+ it "should raise an error" do
537
+ expect { @api.get("#{base_path}/invalid/json") }.should raise_error
538
+ end
539
+ end
540
+ context "we're not expecting json" do
541
+ it "should return the string" do
542
+ @api.get("#{base_path}/invalid/json", false).should == 'bogus'
543
+ end
544
+ end
545
+ end
546
+ end
547
+
548
+ describe ".post" do
549
+ # TODO: Make this format-agnostic
550
+ context "when parsing JSON" do
551
+ it "should issue a post to the given URL" do
552
+ FakeWeb.register_uri(:post, %r|/custom/post/url|, :body => '{}')
553
+ res = @api.post("#{base_path}/custom/post/url", 'asdf')
554
+ FakeWeb.should have_requested(:post, %r|/custom/post/url|)
555
+ end
556
+
557
+ it "should return a hash" do
558
+ FakeWeb.register_uri(:post, %r|/custom/post/url|, :body => '{}')
559
+ res = @api.post("#{base_path}/custom/post/url", 'asdf')
560
+ res.should == {}
561
+ end
562
+ end
563
+
564
+ # TODO: Make this format-agnostic
565
+ context "When not parsing JSON" do
566
+ it "should return a string" do
567
+ FakeWeb.register_uri(:post, %r|/custom/post/url|, :body => '{}')
568
+ res = @api.post("#{base_path}/custom/post/url", 'asdf', false)
569
+ res.should == '{}'
570
+ end
571
+ end
572
+ end
573
+
574
+ describe ".put" do
575
+ it "should issue a PUT to the given URL" do
576
+ FakeWeb.register_uri(:put, %r|/custom/put/url|, :body => '{}')
577
+ @api.put("#{base_path}/custom/put/url", [{:a => :b}, {:b => :c}])
578
+ end
579
+
580
+ it "should raise an error if we get a 400" do
581
+ FakeWeb.register_uri(:put, %r|/custom/put/url|, :status => 400, :body => '{}')
582
+ expect { @api.put("#{base_path}/custom/put/url", [{:a => :b}, {:b => :c}]) }.should raise_error RestClient::BadRequest
583
+ end
584
+
585
+ context "when the server returns a list of resources" do
586
+ before { FakeWeb.register_uri(:put, %r|/custom/put/url|, :status => 200, :body => '[{"a":"b"}]') }
587
+ it "should return an array of hashes" do
588
+ ar = @api.put("#{base_path}/custom/put/url", {})
589
+ ar.should be_an Array
590
+ end
591
+ end
592
+
593
+ context "when the server returns a single resource" do
594
+ before { FakeWeb.register_uri(:put, %r|/custom/put/url|, :status => 200, :body => '{"a":"b"}') }
595
+ it "should return an array of hashes" do
596
+ ar = @api.put("#{base_path}/custom/put/url", {})
597
+ ar.should be_a Hash
598
+ end
599
+ end
600
+
601
+ context "when the server returns an empty response" do
602
+ before { FakeWeb.register_uri(:put, %r|/custom/put/url|, :status => 200, :body => '') }
603
+ it "should return an empty string" do
604
+ ar = @api.put("#{base_path}/custom/put/url", {})
605
+ ar.should == ""
606
+ end
607
+ end
608
+
609
+ context "when passed :json => false" do
610
+ before { FakeWeb.register_uri(:put, %r|/custom/put/url|, :status => 200, :body => '{"a":"b"}') }
611
+ it "should return a string" do
612
+ ar = @api.put("#{base_path}/custom/put/url", {}, :json => false)
613
+ ar.should be_a String
614
+ end
615
+ end
616
+ end
617
+ end
618
+ end
619
+