koala 1.0.0.beta2.1 → 1.0.0.rc

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGELOG +6 -1
  3. data/Gemfile +3 -0
  4. data/Rakefile +13 -14
  5. data/koala.gemspec +35 -20
  6. data/lib/koala.rb +8 -17
  7. data/lib/koala/graph_api.rb +2 -2
  8. data/lib/koala/http_services.rb +32 -27
  9. data/lib/koala/test_users.rb +4 -4
  10. data/lib/koala/uploadable_io.rb +1 -1
  11. data/spec/cases/api_base_spec.rb +101 -0
  12. data/spec/cases/graph_and_rest_api_spec.rb +31 -0
  13. data/spec/cases/graph_api_spec.rb +25 -0
  14. data/spec/{koala/http_services/http_service_tests.rb → cases/http_services/http_service_spec.rb} +8 -5
  15. data/spec/cases/http_services/net_http_service_spec.rb +350 -0
  16. data/spec/cases/http_services/typhoeus_service_spec.rb +144 -0
  17. data/spec/cases/oauth_spec.rb +374 -0
  18. data/spec/cases/realtime_updates_spec.rb +184 -0
  19. data/spec/cases/rest_api_spec.rb +25 -0
  20. data/spec/{koala/test_users/test_users_tests.rb → cases/test_users_spec.rb} +34 -29
  21. data/spec/cases/uploadable_io_spec.rb +151 -0
  22. data/spec/{koala/assets → fixtures}/beach.jpg +0 -0
  23. data/spec/{facebook_data.yml → fixtures/facebook_data.yml} +5 -5
  24. data/spec/{mock_facebook_responses.yml → fixtures/mock_facebook_responses.yml} +311 -311
  25. data/spec/spec_helper.rb +18 -0
  26. data/spec/support/graph_api_shared_examples.rb +424 -0
  27. data/spec/{koala → support}/live_testing_data_helper.rb +39 -42
  28. data/spec/{mock_http_service.rb → support/mock_http_service.rb} +94 -94
  29. data/spec/{koala/rest_api/rest_api_tests.rb → support/rest_api_shared_examples.rb} +43 -0
  30. data/spec/support/setup_mocks_or_live.rb +52 -0
  31. data/spec/support/uploadable_io_shared_examples.rb +76 -0
  32. metadata +109 -53
  33. data/init.rb +0 -2
  34. data/spec/koala/api_base_tests.rb +0 -102
  35. data/spec/koala/graph_and_rest_api/graph_and_rest_api_no_token_tests.rb +0 -14
  36. data/spec/koala/graph_and_rest_api/graph_and_rest_api_with_token_tests.rb +0 -16
  37. data/spec/koala/graph_api/graph_api_no_access_token_tests.rb +0 -65
  38. data/spec/koala/graph_api/graph_api_tests.rb +0 -85
  39. data/spec/koala/graph_api/graph_api_with_access_token_tests.rb +0 -194
  40. data/spec/koala/graph_api/graph_collection_tests.rb +0 -104
  41. data/spec/koala/http_services/net_http_service_tests.rb +0 -339
  42. data/spec/koala/http_services/typhoeus_service_tests.rb +0 -162
  43. data/spec/koala/oauth/oauth_tests.rb +0 -372
  44. data/spec/koala/realtime_updates/realtime_updates_tests.rb +0 -187
  45. data/spec/koala/rest_api/rest_api_no_access_token_tests.rb +0 -25
  46. data/spec/koala/rest_api/rest_api_with_access_token_tests.rb +0 -38
  47. data/spec/koala/uploadable_io/uploadable_io_tests.rb +0 -246
  48. data/spec/koala_spec.rb +0 -18
  49. data/spec/koala_spec_helper.rb +0 -74
  50. data/spec/koala_spec_without_mocks.rb +0 -19
@@ -0,0 +1,18 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'although not required, bundler is recommened for running the tests'
5
+ end
6
+
7
+ # load the libraries
8
+ require 'koala'
9
+
10
+ # load testing data libraries
11
+ require 'support/live_testing_data_helper'
12
+ require 'support/mock_http_service'
13
+ require 'support/rest_api_shared_examples'
14
+ require 'support/graph_api_shared_examples'
15
+ require 'support/uploadable_io_shared_examples'
16
+ require 'support/setup_mocks_or_live'
17
+
18
+ BEACH_BALL_PATH = File.join(File.dirname(__FILE__), "fixtures", "beach.jpg")
@@ -0,0 +1,424 @@
1
+ shared_examples_for "Koala GraphAPI" do
2
+ # all Graph API instances should pass these tests, regardless of configuration
3
+
4
+ # API
5
+ it "should never use the rest api server" do
6
+ Koala.should_receive(:make_request).with(
7
+ anything,
8
+ anything,
9
+ anything,
10
+ hash_not_including(:rest_api => true)
11
+ ).and_return(Koala::Response.new(200, "", {}))
12
+
13
+ @api.api("anything")
14
+ end
15
+
16
+ # GRAPH CALL
17
+ describe "graph_call" do
18
+ it "should pass all arguments to the api method" do
19
+ args = ["koppel", {}, "get", {:a => :b}]
20
+
21
+ @api.should_receive(:api).with(*args)
22
+
23
+ @api.graph_call(*args)
24
+ end
25
+
26
+ it "should throw an APIError if the result hash has an error key" do
27
+ Koala.stub(:make_request).and_return(Koala::Response.new(500, {"error" => "An error occurred!"}, {}))
28
+ lambda { @api.graph_call("koppel", {}) }.should raise_exception(Koala::Facebook::APIError)
29
+ end
30
+ end
31
+
32
+ # SEARCH
33
+ it "should be able to search" do
34
+ result = @api.search("facebook")
35
+ result.length.should be_an(Integer)
36
+ end
37
+
38
+ # DATA
39
+ # access public info
40
+
41
+ # get_object
42
+ it "should get public data about a user" do
43
+ result = @api.get_object("koppel")
44
+ # the results should have an ID and a name, among other things
45
+ (result["id"] && result["name"]).should_not be_nil
46
+ end
47
+
48
+ it "should get public data about a Page" do
49
+ result = @api.get_object("contextoptional")
50
+ # the results should have an ID and a name, among other things
51
+ (result["id"] && result["name"]).should
52
+ end
53
+
54
+ it "should be able to get multiple objects" do
55
+ results = @api.get_objects(["contextoptional", "naitik"])
56
+ results.length.should == 2
57
+ end
58
+
59
+ it "should be able to access a user's picture" do
60
+ @api.get_picture("chris.baclig").should =~ /http\:\/\//
61
+ end
62
+
63
+ it "should be able to access a user's picture, given a picture type" do
64
+ @api.get_picture("chris.baclig", {:type => 'large'}).should =~ /^http\:\/\//
65
+ end
66
+
67
+ it "should be able to access connections from public Pages" do
68
+ result = @api.get_connections("contextoptional", "photos")
69
+ result.should be_a(Array)
70
+ end
71
+
72
+ # SEARCH
73
+ it "should be able to search" do
74
+ result = @api.search("facebook")
75
+ result.length.should be_an(Integer)
76
+ end
77
+
78
+ # PAGING THROUGH COLLECTIONS
79
+ # see also graph_collection_tests
80
+ it "should make a request for a page when provided a specific set of page params" do
81
+ query = [1, 2]
82
+ @api.should_receive(:graph_call).with(*query)
83
+ @api.get_page(query)
84
+ end
85
+ end
86
+
87
+
88
+ shared_examples_for "Koala GraphAPI with an access token" do
89
+
90
+ it "should get private data about a user" do
91
+ result = @api.get_object("koppel")
92
+ # updated_time should be a pretty fixed test case
93
+ result["updated_time"].should_not be_nil
94
+ end
95
+
96
+ it "should get data about 'me'" do
97
+ result = @api.get_object("me")
98
+ result["updated_time"].should
99
+ end
100
+
101
+ it "should be able to get multiple objects" do
102
+ result = @api.get_objects(["contextoptional", "naitik"])
103
+ result.length.should == 2
104
+ end
105
+ it "should be able to access connections from users" do
106
+ result = @api.get_connections("lukeshepard", "likes")
107
+ result.length.should > 0
108
+ end
109
+
110
+ # PUT
111
+ it "should be able to write an object to the graph" do
112
+ result = @api.put_wall_post("Hello, world, from the test suite!")
113
+ @temporary_object_id = result["id"]
114
+ @temporary_object_id.should_not be_nil
115
+ end
116
+
117
+ # DELETE
118
+ it "should be able to delete posts" do
119
+ result = @api.put_wall_post("Hello, world, from the test suite delete method!")
120
+ object_id_to_delete = result["id"]
121
+ delete_result = @api.delete_object(object_id_to_delete)
122
+ delete_result.should == true
123
+ end
124
+
125
+ it "should be able to delete likes" do
126
+ result = @api.put_wall_post("Hello, world, from the test suite delete method!")
127
+ @temporary_object_id = result["id"]
128
+ @api.put_like(@temporary_object_id)
129
+ delete_like_result = @api.delete_like(@temporary_object_id)
130
+ delete_like_result.should == true
131
+ end
132
+
133
+ # additional put tests
134
+ it "should be able to verify messages posted to a wall" do
135
+ message = "the cats are asleep"
136
+ put_result = @api.put_wall_post(message)
137
+ @temporary_object_id = put_result["id"]
138
+ get_result = @api.get_object(@temporary_object_id)
139
+
140
+ # make sure the message we sent is the message that got posted
141
+ get_result["message"].should == message
142
+ end
143
+
144
+ it "should be able to post a message with an attachment to a feed" do
145
+ result = @api.put_wall_post("Hello, world, from the test suite again!", {:name => "OAuth Playground", :link => "http://oauth.twoalex.com/"})
146
+ @temporary_object_id = result["id"]
147
+ @temporary_object_id.should_not be_nil
148
+ end
149
+
150
+ it "should be able to post photos to the user's wall with an open file object" do
151
+ content_type = "image/jpg"
152
+ file = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg"))
153
+
154
+ result = @api.put_picture(file, content_type)
155
+ @temporary_object_id = result["id"]
156
+ @temporary_object_id.should_not be_nil
157
+ end
158
+
159
+ it "should be able to post photos to the user's wall without an open file object" do
160
+ content_type = "image/jpg",
161
+ file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
162
+
163
+ result = @api.put_picture(file_path, content_type)
164
+ @temporary_object_id = result["id"]
165
+ @temporary_object_id.should_not be_nil
166
+ end
167
+
168
+ it "should be able to verify a photo posted to a user's wall" do
169
+ content_type = "image/jpg",
170
+ file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
171
+
172
+ expected_message = "This is the test message"
173
+
174
+ result = @api.put_picture(file_path, content_type, :message => expected_message)
175
+ @temporary_object_id = result["id"]
176
+ @temporary_object_id.should_not be_nil
177
+
178
+ get_result = @api.get_object(@temporary_object_id)
179
+ get_result["name"].should == expected_message
180
+ end
181
+
182
+ it "should be able to verify a message with an attachment posted to a feed" do
183
+ attachment = {"name" => "OAuth Playground", "link" => "http://oauth.twoalex.com/"}
184
+ result = @api.put_wall_post("Hello, world, from the test suite again!", attachment)
185
+ @temporary_object_id = result["id"]
186
+ get_result = @api.get_object(@temporary_object_id)
187
+
188
+ # make sure the result we fetch includes all the parameters we sent
189
+ it_matches = attachment.inject(true) {|valid, param| valid && (get_result[param[0]] == attachment[param[0]])}
190
+ it_matches.should == true
191
+ end
192
+
193
+ it "should be able to comment on an object" do
194
+ result = @api.put_wall_post("Hello, world, from the test suite, testing comments!")
195
+ @temporary_object_id = result["id"]
196
+
197
+ # this will be deleted when the post gets deleted
198
+ comment_result = @api.put_comment(@temporary_object_id, "it's my comment!")
199
+ comment_result.should_not be_nil
200
+ end
201
+
202
+ it "should be able to verify a comment posted about an object" do
203
+ message_text = "Hello, world, from the test suite, testing comments!"
204
+ result = @api.put_wall_post(message_text)
205
+ @temporary_object_id = result["id"]
206
+
207
+ # this will be deleted when the post gets deleted
208
+ comment_text = "it's my comment!"
209
+ comment_result = @api.put_comment(@temporary_object_id, comment_text)
210
+ get_result = @api.get_object(comment_result["id"])
211
+
212
+ # make sure the text of the comment matches what we sent
213
+ get_result["message"].should == comment_text
214
+ end
215
+
216
+ it "should be able to like an object" do
217
+ result = @api.put_wall_post("Hello, world, from the test suite, testing comments!")
218
+ @temporary_object_id = result["id"]
219
+ like_result = @api.put_like(@temporary_object_id)
220
+ like_result.should be_true
221
+ end
222
+
223
+
224
+ # test all methods to make sure they pass data through to the API
225
+ # we run the tests here (rather than in the common shared example group)
226
+ # since some require access tokens
227
+ describe "HTTP options" do
228
+ # Each of the below methods should take an options hash as their last argument
229
+ # ideally we'd use introspection to determine how many arguments a method has
230
+ # but some methods require specially formatted arguments for processing
231
+ # (and anyway, Ruby 1.8's arity method fails (for this) for methods w/ 2+ optional arguments)
232
+ # (Ruby 1.9's parameters method is perfect, but only in 1.9)
233
+ # so we have to double-document
234
+ {
235
+ :get_object => 3, :put_object => 4, :delete_object => 2,
236
+ :get_connections => 4, :put_connections => 4, :delete_connections => 4,
237
+ :put_wall_post => 4,
238
+ :put_comment => 3,
239
+ :put_like => 2, :delete_like => 2,
240
+ :search => 3,
241
+ # methods that have special arguments
242
+ :put_picture => ["x.jpg", "image/jpg", {}, "me"],
243
+ :get_objects => [["x"], {}]
244
+ }.each_pair do |method_name, params|
245
+ it "should pass http options through for #{method_name}" do
246
+ options = {:a => 2}
247
+ # graph call should ultimately receive options as the fourth argument
248
+ @api.should_receive(:graph_call).with(anything, anything, anything, options)
249
+
250
+ # if we supply args, use them (since some methods process params)
251
+ # the method should receive as args n-1 anythings and then options
252
+ args = (params.is_a?(Integer) ? ([{}] * (params - 1)) : params) + [options]
253
+
254
+ @api.send(method_name, *args)
255
+ end
256
+ end
257
+
258
+ # also test get_picture, which merges a parameter into options
259
+ it "should pass http options through for get_picture" do
260
+ options = {:a => 2}
261
+ # graph call should ultimately receive options as the fourth argument
262
+ @api.should_receive(:graph_call).with(anything, anything, anything, hash_including(options)).and_return({})
263
+ @api.send(:get_picture, "x", {}, options)
264
+ end
265
+ end
266
+ end
267
+
268
+
269
+ # GraphCollection
270
+ shared_examples_for "Koala GraphAPI with GraphCollection" do
271
+
272
+ it "should create an array-like object" do
273
+ call = @api.graph_call("contextoptional/photos")
274
+ Koala::Facebook::GraphCollection.new(call, @api).should be_an(Array)
275
+ end
276
+
277
+ describe "when getting a collection" do
278
+ # GraphCollection methods
279
+ it "should get a GraphCollection when getting connections" do
280
+ @result = @api.get_connections("contextoptional", "photos")
281
+ @result.should be_a(Koala::Facebook::GraphCollection)
282
+ end
283
+
284
+ it "should return nil if the get_collections call fails with nil" do
285
+ # this happens sometimes
286
+ @api.should_receive(:graph_call).and_return(nil)
287
+ @api.get_connections("contextoptional", "photos").should be_nil
288
+ end
289
+
290
+ it "should get a GraphCollection when searching" do
291
+ result = @api.search("facebook")
292
+ result.should be_a(Koala::Facebook::GraphCollection)
293
+ end
294
+
295
+ it "should return nil if the search call fails with nil" do
296
+ # this happens sometimes
297
+ @api.should_receive(:graph_call).and_return(nil)
298
+ @api.search("facebook").should be_nil
299
+ end
300
+
301
+ it "should get a GraphCollection when paging through results" do
302
+ @results = @api.get_page(["search", {"q"=>"facebook", "limit"=>"25", "until"=>"2010-09-23T21:17:33+0000"}])
303
+ @results.should be_a(Koala::Facebook::GraphCollection)
304
+ end
305
+
306
+ it "should return nil if the page call fails with nil" do
307
+ # this happens sometimes
308
+ @api.should_receive(:graph_call).and_return(nil)
309
+ @api.get_page(["search", {"q"=>"facebook", "limit"=>"25", "until"=>"2010-09-23T21:17:33+0000"}]).should be_nil
310
+ end
311
+
312
+ # GraphCollection attributes
313
+ describe "the GraphCollection" do
314
+ before(:each) do
315
+ @result = @api.get_connections("contextoptional", "photos")
316
+ end
317
+
318
+ it "should have a read-only paging attribute" do
319
+ lambda { @result.paging }.should_not raise_error
320
+ lambda { @result.paging = "paging" }.should raise_error(NoMethodError)
321
+ end
322
+
323
+ describe "when getting a whole page" do
324
+ before(:each) do
325
+ @second_page = stub("page of Fb graph results")
326
+ @base = stub("base")
327
+ @args = stub("args")
328
+ @page_of_results = stub("page of results")
329
+ end
330
+
331
+ it "should return the previous page of results" do
332
+ @result.should_receive(:previous_page_params).and_return([@base, @args])
333
+ @api.should_receive(:graph_call).with(@base, @args).and_return(@second_page)
334
+ Koala::Facebook::GraphCollection.should_receive(:new).with(@second_page, @api).and_return(@page_of_results)
335
+
336
+ @result.previous_page.should == @page_of_results
337
+ end
338
+
339
+ it "should return the next page of results" do
340
+ @result.should_receive(:next_page_params).and_return([@base, @args])
341
+ @api.should_receive(:graph_call).with(@base, @args).and_return(@second_page)
342
+ Koala::Facebook::GraphCollection.should_receive(:new).with(@second_page, @api).and_return(@page_of_results)
343
+
344
+ @result.next_page.should == @page_of_results
345
+ end
346
+
347
+ it "should return nil it there are no other pages" do
348
+ %w{next previous}.each do |this|
349
+ @result.should_receive("#{this}_page_params".to_sym).and_return(nil)
350
+ @result.send("#{this}_page").should == nil
351
+ end
352
+ end
353
+ end
354
+
355
+ describe "when parsing page paramters" do
356
+ before(:each) do
357
+ @graph_collection = Koala::Facebook::GraphCollection.new({"data" => []}, Koala::Facebook::GraphAPI.new)
358
+ end
359
+
360
+ it "should return the base as the first array entry" do
361
+ base = "url_path"
362
+ @graph_collection.parse_page_url("anything.com/#{base}?anything").first.should == base
363
+ end
364
+
365
+ it "should return the arguments as a hash as the last array entry" do
366
+ args_hash = {"one" => "val_one", "two" => "val_two"}
367
+ @graph_collection.parse_page_url("anything.com/anything?#{args_hash.map {|k,v| "#{k}=#{v}" }.join("&")}").last.should == args_hash
368
+ end
369
+ end
370
+ end
371
+ end
372
+ end
373
+
374
+
375
+ shared_examples_for "Koala GraphAPI without an access token" do
376
+
377
+ it "should not get private data about a user" do
378
+ result = @api.get_object("koppel")
379
+ # updated_time should be a pretty fixed test case
380
+ result["updated_time"].should be_nil
381
+ end
382
+
383
+ it "should not be able to get data about 'me'" do
384
+ lambda { @api.get_object("me") }.should raise_error(Koala::Facebook::APIError)
385
+ end
386
+
387
+ it "shouldn't be able to access connections from users" do
388
+ lambda { @api.get_connections("lukeshepard", "likes") }.should raise_error(Koala::Facebook::APIError)
389
+ end
390
+
391
+ it "should not be able to put an object" do
392
+ lambda { @result = @api.put_object("lukeshepard", "feed", :message => "Hello, world") }.should raise_error(Koala::Facebook::APIError)
393
+ puts "Error! Object #{@result.inspect} somehow put onto Luke Shepard's wall!" if @result
394
+ end
395
+
396
+ # these are not strictly necessary as the other put methods resolve to put_object, but are here for completeness
397
+ it "should not be able to post to a feed" do
398
+ (lambda do
399
+ attachment = {:name => "OAuth Playground", :link => "http://oauth.twoalex.com/"}
400
+ @result = @api.put_wall_post("Hello, world", attachment, "contextoptional")
401
+ end).should raise_error(Koala::Facebook::APIError)
402
+ puts "Error! Object #{@result.inspect} somehow put onto Context Optional's wall!" if @result
403
+ end
404
+
405
+ it "should not be able to comment on an object" do
406
+ # random public post on the ContextOptional wall
407
+ lambda { @result = @api.put_comment("7204941866_119776748033392", "The hackathon was great!") }.should raise_error(Koala::Facebook::APIError)
408
+ puts "Error! Object #{@result.inspect} somehow commented on post 7204941866_119776748033392!" if @result
409
+ end
410
+
411
+ it "should not be able to like an object" do
412
+ lambda { @api.put_like("7204941866_119776748033392") }.should raise_error(Koala::Facebook::APIError)
413
+ end
414
+
415
+ # DELETE
416
+ it "should not be able to delete posts" do
417
+ # test post on the Ruby SDK Test application
418
+ lambda { @result = @api.delete_object("115349521819193_113815981982767") }.should raise_error(Koala::Facebook::APIError)
419
+ end
420
+
421
+ it "should not be able to delete a like" do
422
+ lambda { @api.delete_like("7204941866_119776748033392") }.should raise_error(Koala::Facebook::APIError)
423
+ end
424
+ end
@@ -1,43 +1,40 @@
1
- module LiveTestingDataHelper
2
- # in RSpec 2, included example groups no longer share any hooks or state with outside examples
3
- # even if in the same block
4
- # so we have to use a module to provide setup and teardown hooks for live testing
5
-
6
- def self.included(base)
7
- base.class_eval do
8
- before :each do
9
- @token = $testing_data["oauth_token"]
10
- raise Exception, "Must supply access token to run FacebookWithAccessTokenTests!" unless @token
11
- # track temporary objects created
12
- @temporary_object_ids = []
13
- end
14
-
15
- after :each do
16
- # clean up any temporary objects
17
- @temporary_object_ids << @temporary_object_id if @temporary_object_id
18
- count = @temporary_object_ids.length
19
- errors = []
20
-
21
- if count > 0
22
- print "\nCleaning up #{count} temporary #{count > 1 ? "objects" : "object (#{@temporary_object_ids.first})"}..."
23
- @temporary_object_ids.each do |id|
24
- # get our API
25
- api = @api || (@test_users ? @test_users.graph_api : nil)
26
- raise "Unable to locate API when passed temporary object to delete!" unless api
27
-
28
- # delete the object
29
- result = (api.delete_object(id) rescue false)
30
- # if we errored out or Facebook returned false, track that
31
- errors << id unless result
32
- end
33
-
34
- if errors.length == 0
35
- puts "done."
36
- else
37
- puts "cleaned up #{count - errors.length} objects, but errored out on the following:\n #{errors.join(", ")}"
38
- end
39
- end
40
- end
41
- end
42
- end
1
+ module LiveTestingDataHelper
2
+ # in RSpec 2, included example groups no longer share any hooks or state with outside examples
3
+ # even if in the same block
4
+ # so we have to use a module to provide setup and teardown hooks for live testing
5
+
6
+ def self.included(base)
7
+ base.class_eval do
8
+ before :each do
9
+ @token = $testing_data["oauth_token"]
10
+ raise Exception, "Must supply access token to run FacebookWithAccessTokenTests!" unless @token
11
+ # track temporary objects created
12
+ @temporary_object_ids = []
13
+ end
14
+
15
+ after :each do
16
+ # clean up any temporary objects
17
+ @temporary_object_ids << @temporary_object_id if @temporary_object_id
18
+ count = @temporary_object_ids.length
19
+ errors = []
20
+
21
+ if count > 0
22
+ @temporary_object_ids.each do |id|
23
+ # get our API
24
+ api = @api || (@test_users ? @test_users.graph_api : nil)
25
+ raise "Unable to locate API when passed temporary object to delete!" unless api
26
+
27
+ # delete the object
28
+ result = (api.delete_object(id) rescue false)
29
+ # if we errored out or Facebook returned false, track that
30
+ errors << id unless result
31
+ end
32
+
33
+ unless errors.length == 0
34
+ puts "cleaned up #{count - errors.length} objects, but errored out on the following:\n #{errors.join(", ")}"
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
43
40
  end