koala 1.1.0rc2 → 1.1.0rc3

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.
@@ -391,7 +391,7 @@ describe "Koala::Facebook::OAuth" do
391
391
  # the signed request code is ported directly from Facebook
392
392
  # so we only need to test at a high level that it works
393
393
  it "should throw an error if the algorithm is unsupported" do
394
- JSON.stub!(:parse).and_return("algorithm" => "my fun algorithm")
394
+ MultiJson.stub(:decode).and_return("algorithm" => "my fun algorithm")
395
395
  lambda { @oauth.parse_signed_request(@signed_request) }.should raise_error
396
396
  end
397
397
 
@@ -43,19 +43,19 @@ describe "Koala::Facebook::RealtimeUpdates" do
43
43
  it "should not allow write access to app_id" do
44
44
  updates = Koala::Facebook::RealtimeUpdates.new(:app_id => @app_id, :app_access_token => @app_access_token)
45
45
  # this should not throw errors
46
- lambda { updates.app_id = 2 }.should raise_error(NoMethodError)
46
+ updates.methods.map(&:to_sym).should_not include(:app_id=)
47
47
  end
48
48
 
49
49
  it "should not allow write access to app_access_token" do
50
50
  updates = Koala::Facebook::RealtimeUpdates.new(:app_id => @app_id, :app_access_token => @app_access_token)
51
51
  # this should not throw errors
52
- lambda { updates.app_access_token = 2 }.should raise_error(NoMethodError)
52
+ updates.methods.map(&:to_sym).should_not include(:app_access_token=)
53
53
  end
54
54
 
55
55
  it "should not allow write access to secret" do
56
56
  updates = Koala::Facebook::RealtimeUpdates.new(:app_id => @app_id, :app_access_token => @app_access_token)
57
57
  # this should not throw errors
58
- lambda { updates.secret = 2 }.should raise_error(NoMethodError)
58
+ updates.methods.map(&:to_sym).should_not include(:secret=)
59
59
  end
60
60
 
61
61
  # init with secret / fetching the token
Binary file
@@ -25,11 +25,11 @@ rest_api:
25
25
  no_token: '{"error_code":104,"error_msg":"Requires valid signature","request_args":[{"key":"method","value":"fql.query"},{"key":"format","value":"json"},{"key":"query","value":"select read_stream from permissions where uid = 216743"}]}'
26
26
 
27
27
  /method/fql.multiquery:
28
- 'queries={"query1":"select post_id from stream where source_id = me()","query2":"select fromid from comment where post_id in (select post_id from #query1)","query3":"select uid, name from user where uid in (select fromid from #query2)"}':
28
+ 'queries=<%= MultiJson.encode({"query1" => "select post_id from stream where source_id = me()", "query2" => "select fromid from comment where post_id in (select post_id from #query1)", "query3" => "select uid, name from user where uid in (select fromid from #query2)"}) %>':
29
29
  get:
30
30
  with_token: '[{"name":"query1", "fql_result_set":[]},{"name":"query2", "fql_result_set":[]},{"name":"query3", "fql_result_set":[]}]'
31
31
  no_token: '{"error_code":104,"error_msg":"Requires valid signature","request_args":[{"key":"method","value":"fql.query"},{"key":"format","value":"json"},{"key":"query","value":"select read_stream from permissions where uid = 216743"}]}'
32
- 'queries={"query1":"select first_name from user where uid = 216743","query2":"select first_name from user where uid = 2905623"}':
32
+ 'queries=<%= MultiJson.encode({"query1" => "select first_name from user where uid = 216743", "query2" => "select first_name from user where uid = 2905623"}) %>':
33
33
  get:
34
34
  with_token: '[{"name":"query1", "fql_result_set":[{"first_name":"Chris"}]},{"name":"query2", "fql_result_set":[{"first_name":"Alex"}]}]'
35
35
  no_token: '[{"name":"query1", "fql_result_set":[{"first_name":"Chris"}]},{"name":"query2", "fql_result_set":[{"first_name":"Alex"}]}]'
@@ -74,52 +74,53 @@ graph_api:
74
74
  with_token: '{"contextoptional":"{}","naitik":"{}"}'
75
75
  no_token: '{"contextoptional":"{}","naitik":"{}"}'
76
76
  # Ruby 1.8.7 and 1.9.2 generate JSON with different key ordering, hence we have to dynamically generate it here
77
- batch=<%= [{"method" => "get", "relative_url" => "me"},{"method" => "get", "relative_url" => "koppel"}].to_json %>:
77
+ batch=<%= MultiJson.encode([{"method" => "get", "relative_url" => "me"},{"method" => "get", "relative_url" => "koppel"}]) %>:
78
78
  post:
79
79
  with_token: '[{"body":"{\"id\":\"123\"}"}, {"body":"{\"id\":\"456\"}"}]'
80
- batch=<%= [{"method" => "get", "relative_url" => "me/picture"}].to_json %>:
80
+ batch=<%= MultiJson.encode([{"method" => "get", "relative_url" => "me/picture"}]) %>:
81
81
  post:
82
82
  with_token: '[{"headers":[{"name":"Location","value":"http://google.com"}]}]'
83
- batch=<%= [{"method" => "get", "relative_url" => "me"},{"method" => "get", "relative_url" => "me/friends"}].to_json %>:
83
+ batch=<%= MultiJson.encode([{"method" => "get", "relative_url" => "me"},{"method" => "get", "relative_url" => "me/friends"}]) %>:
84
84
  post:
85
85
  with_token: '[{"body":"{\"id\":\"123\"}"}, {"body":"{\"data\":[]}"}]'
86
- batch=<%= [{"method"=>"get", "relative_url"=>"me"}, {"method"=>"get", "relative_url"=>"#{OAUTH_DATA["app_id"]}/insights?access_token=#{CGI.escape APP_ACCESS_TOKEN}"}].to_json %>:
86
+ batch=<%= MultiJson.encode([{"method"=>"get", "relative_url"=>"me"}, {"method"=>"get", "relative_url"=>"#{OAUTH_DATA["app_id"]}/insights?access_token=#{CGI.escape APP_ACCESS_TOKEN}"}]) %>:
87
87
  post:
88
88
  with_token: '[{"body":"{\"id\":\"123\"}"}, {"body":"{\"data\":[]}"}]'
89
- batch=<%= [{"method"=>"get", "relative_url"=>"#{OAUTH_DATA["app_id"]}/insights"}, {"method"=>"get", "relative_url"=>"koppel?access_token=#{CGI.escape APP_ACCESS_TOKEN}"}].to_json %>:
89
+ batch=<%= MultiJson.encode([{"method"=>"get", "relative_url"=>"#{OAUTH_DATA["app_id"]}/insights"}, {"method"=>"get", "relative_url"=>"koppel?access_token=#{CGI.escape APP_ACCESS_TOKEN}"}]) %>:
90
90
  post:
91
91
  with_token: '[{"body": "{\"error\":{\"type\":\"AnError\", \"message\":\"An error occurred!.\"}}"},{"body":"{\"id\":\"123\"}"}]'
92
- batch=<%= [{"method"=>"post", "relative_url"=>"FEED_ITEM_BATCH/likes"}, {"method"=>"delete", "relative_url"=> "FEED_ITEM_BATCH"}].to_json %>:
92
+ batch=<%= MultiJson.encode([{"method"=>"post", "relative_url"=>"FEED_ITEM_BATCH/likes"}, {"method"=>"delete", "relative_url"=> "FEED_ITEM_BATCH"}]) %>:
93
93
  post:
94
94
  with_token: '[{"body": "{\"id\": \"MOCK_LIKE\"}"},{"body":true}]'
95
- batch=<%= [{"method" => "get", "relative_url" => "me/friends?limit=5", "name" => "get-friends"}, {"method" => "get", "relative_url" => "?ids=#{CGI.escape "{result=get-friends:$.data.*.id}"}"}].to_json %>:
95
+ batch=<%= MultiJson.encode([{"method" => "get", "relative_url" => "me/friends?limit=5", "name" => "get-friends"}, {"method" => "get", "relative_url" => "?ids=#{CGI.escape "{result=get-friends:$.data.*.id}"}"}]) %>:
96
96
  post:
97
97
  with_token: '[null,{"body":"{}"}]'
98
- batch=<%= [{"method" => "get", "relative_url" => "me/friends?limit=5", "name" => "get-friends", "omit_response_on_success" => false}, {"method" => "get", "relative_url" => "?ids=#{CGI.escape "{result=get-friends:$.data.*.id}"}"}].to_json %>:
98
+ batch=<%= MultiJson.encode([{"method" => "get", "relative_url" => "me/friends?limit=5", "name" => "get-friends", "omit_response_on_success" => false}, {"method" => "get", "relative_url" => "?ids=#{CGI.escape "{result=get-friends:$.data.*.id}"}"}]) %>:
99
99
  post:
100
100
  with_token: '[{"body":"{\"data\":[]}"},{"body":"{}"}]'
101
- batch=<%= [{"method" => "get", "relative_url" => "me/friends?limit=5"}, {"method" => "get", "relative_url" => "?ids=#{CGI.escape "{result=i-dont-exist:$.data.*.id}"}"}].to_json %>:
101
+ batch=<%= MultiJson.encode([{"method" => "get", "relative_url" => "me/friends?limit=5"}, {"method" => "get", "relative_url" => "?ids=#{CGI.escape "{result=i-dont-exist:$.data.*.id}"}"}]) %>:
102
102
  post:
103
103
  with_token: '{"error":190,"error_description":"Error validating access token."}'
104
- batch=<%= [{"method" => "post", "relative_url" => "method/fql.query", "body" => "query=select+name+from+user+where+uid%3D4"}].to_json %>:
104
+ batch=<%= MultiJson.encode([{"method" => "post", "relative_url" => "method/fql.query", "body" => "query=select+name+from+user+where+uid%3D4"}]) %>:
105
105
  post:
106
106
  with_token: '[{"body":"[{\"name\":\"Mark Zuckerberg\"}]"}]'
107
- batch=<%= [{"method"=>"get", "relative_url"=>"me", "name" => "getme"}, {"method"=>"get", "relative_url"=>"koppel", "depends_on" => "getme"}].to_json %>:
108
- post:
109
- with_token: '[null,{"body":"{\"id\":\"123\"}"}]'
110
- batch=<%= [{"method"=>"get", "relative_url"=>"#{OAUTH_DATA["app_id"]}/insights", "name" => "getdata"}, {"method"=>"get", "relative_url"=>"koppel", "depends_on" => "getdata"}].to_json %>:
111
- post:
112
- with_token: '[{"body": "{\"error\":{\"type\":\"AnError\", \"message\":\"An error occurred!.\"}}"},null]'
113
- batch=<%= [{"method"=>"get", "relative_url"=>"#{OAUTH_DATA["app_id"]}/insights", "name" => "getdata"}, {"method"=>"get", "relative_url"=>"koppel", "depends_on" => "getdata"}].to_json %>:
107
+
108
+ # dependencies
109
+ batch=<%= MultiJson.encode([{"method"=>"get", "relative_url"=>"me", "name" => "getme"}, {"method"=>"get", "relative_url"=>"koppel", "depends_on" => "getme"}]) %>:
110
+ post: &batch_dependent
111
+ with_token: '[null,{"body":"{\"id\":\"123\"}"}]'
112
+ batch=<%= MultiJson.encode([{"method"=>"get", "relative_url"=>"#{OAUTH_DATA["app_id"]}/insights", "name" => "getdata"}, {"method"=>"get", "relative_url"=>"koppel", "depends_on" => "getdata"}]) %>:
114
113
  post:
115
114
  with_token: '[{"body": "{\"error\":{\"type\":\"AnError\", \"message\":\"An error occurred!.\"}}"},null]'
116
- batch=<%= [{"method"=>"post", "relative_url"=>"me/photos", "attached_files" => "file0_0"}].to_json %>&file0_0=[FILE]:
115
+
116
+ # attached files tests
117
+ batch=<%= MultiJson.encode([{"method"=>"post", "relative_url"=>"me/photos", "attached_files" => "op1_file0"}]) %>&op1_file0=[FILE]:
117
118
  post:
118
119
  with_token: '[{"body": "{\"error\":{\"type\":\"AnError\", \"message\":\"An error occurred!.\"}}"},null]'
119
- batch=<%= [{"method"=>"post", "relative_url"=>"me/photos", "attached_files" => "file0_0"}].to_json %>&file0_0=[FILE]:
120
+ batch=<%= MultiJson.encode([{"method"=>"post", "relative_url"=>"me/photos", "attached_files" => "op1_file0"}]) %>&op1_file0=[FILE]:
120
121
  post:
121
122
  with_token: '[{"body":"{\"id\": \"MOCK_PHOTO\"}"}]'
122
- batch=<%= [{"method"=>"post", "relative_url"=>"me/photos", "attached_files" => "file0_0"}, {"method"=>"post", "relative_url"=>"koppel/photos", "attached_files" => "file1_0"}].to_json %>&file0_0=[FILE]&file1_0=[FILE]:
123
+ batch=<%= MultiJson.encode([{"method"=>"post", "relative_url"=>"me/photos", "attached_files" => "op1_file0"}, {"method"=>"post", "relative_url"=>"koppel/photos", "attached_files" => "op2_file0"}]) %>&op1_file0=[FILE]&op2_file0=[FILE]:
123
124
  post:
124
125
  with_token: '[{"body":"{\"id\": \"MOCK_PHOTO\"}"}, {"body":"{\"id\": \"MOCK_PHOTO\"}"}]'
125
126
 
@@ -161,6 +162,16 @@ graph_api:
161
162
  post:
162
163
  <<: *token_required
163
164
  with_token: '{"id": "MOCK_PHOTO"}'
165
+ /me/videos:
166
+ source=[FILE]:
167
+ post:
168
+ <<: *token_required
169
+ with_token: '{"id": "MOCK_PHOTO"}'
170
+ message=This is the test message&source=[FILE]:
171
+ post:
172
+ <<: *token_required
173
+ with_token: '{"id": "MOCK_PHOTO"}'
174
+
164
175
  /koppel:
165
176
  no_args:
166
177
  get:
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  begin
2
2
  require 'bundler/setup'
3
3
  rescue LoadError
4
- puts 'although not required, bundler is recommened for running the tests'
4
+ puts 'although not required, bundler is recommended for running the tests'
5
5
  end
6
6
 
7
7
  # load the libraries
@@ -166,44 +166,87 @@ shared_examples_for "Koala GraphAPI with an access token" do
166
166
  @temporary_object_id.should_not be_nil
167
167
  end
168
168
 
169
- it "should be able to post photos to the user's wall with an open file object" do
170
- content_type = "image/jpg"
171
- file = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg"))
172
-
173
- result = @api.put_picture(file, content_type)
174
- @temporary_object_id = result["id"]
175
- @temporary_object_id.should_not be_nil
176
- end
169
+ describe ".put_picture" do
170
+ it "should be able to post photos to the user's wall with an open file object" do
171
+ content_type = "image/jpg"
172
+ file = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg"))
177
173
 
178
- it "uses the base HTTP service if the upload is a StringIO or similar" do
179
- source = stub("UploadIO")
180
- Koala::UploadableIO.stub(:new).and_return(source)
181
- source.stub(:requires_base_http_service).and_return(true)
182
- Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(:http_service => Koala.base_http_service)).and_return(Koala::Response.new(200, "[]", {}))
183
- @api.put_picture(StringIO.new)
184
- end
174
+ result = @api.put_picture(file, content_type)
175
+ @temporary_object_id = result["id"]
176
+ @temporary_object_id.should_not be_nil
177
+ end
178
+
179
+ it "uses the base HTTP service if the upload is a StringIO or similar" do
180
+ source = stub("UploadIO")
181
+ Koala::UploadableIO.stub(:new).and_return(source)
182
+ source.stub(:requires_base_http_service).and_return(true)
183
+ Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(:http_service => Koala.base_http_service)).and_return(Koala::Response.new(200, "[]", {}))
184
+ @api.put_picture(StringIO.new)
185
+ end
186
+
187
+ it "should be able to post photos to the user's wall without an open file object" do
188
+ content_type = "image/jpg",
189
+ file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
185
190
 
186
- it "should be able to post photos to the user's wall without an open file object" do
187
- content_type = "image/jpg",
188
- file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
189
-
190
- result = @api.put_picture(file_path, content_type)
191
- @temporary_object_id = result["id"]
192
- @temporary_object_id.should_not be_nil
191
+ result = @api.put_picture(file_path, content_type)
192
+ @temporary_object_id = result["id"]
193
+ @temporary_object_id.should_not be_nil
194
+ end
195
+
196
+ it "should be able to verify a photo posted to a user's wall" do
197
+ content_type = "image/jpg",
198
+ file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
199
+
200
+ expected_message = "This is the test message"
201
+
202
+ result = @api.put_picture(file_path, content_type, :message => expected_message)
203
+ @temporary_object_id = result["id"]
204
+ @temporary_object_id.should_not be_nil
205
+
206
+ get_result = @api.get_object(@temporary_object_id)
207
+ get_result["name"].should == expected_message
208
+ end
193
209
  end
210
+
211
+ describe ".put_video" do
212
+ before :each do
213
+ @cat_movie = File.join(File.dirname(__FILE__), "..", "fixtures", "cat.m4v")
214
+ @content_type = "video/mpeg4"
215
+ end
194
216
 
195
- it "should be able to verify a photo posted to a user's wall" do
196
- content_type = "image/jpg",
197
- file_path = File.join(File.dirname(__FILE__), "..", "fixtures", "beach.jpg")
198
-
199
- expected_message = "This is the test message"
200
-
201
- result = @api.put_picture(file_path, content_type, :message => expected_message)
202
- @temporary_object_id = result["id"]
203
- @temporary_object_id.should_not be_nil
217
+ it "should set options[:video] to true" do
218
+ source = stub("UploadIO")
219
+ Koala::UploadableIO.stub(:new).and_return(source)
220
+ source.stub(:requires_base_http_service).and_return(false)
221
+ Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(:video => true)).and_return(Koala::Response.new(200, "[]", {}))
222
+ @api.put_video("foo")
223
+ end
204
224
 
205
- get_result = @api.get_object(@temporary_object_id)
206
- get_result["name"].should == expected_message
225
+ it "should be able to post videos to the user's wall with an open file object" do
226
+ file = File.open(@cat_movie)
227
+
228
+ result = @api.put_video(file, @content_type)
229
+ @temporary_object_id = result["id"]
230
+ @temporary_object_id.should_not be_nil
231
+ end
232
+
233
+ it "uses the base HTTP service if the upload is a StringIO or similar" do
234
+ source = stub("UploadIO")
235
+ Koala::UploadableIO.stub(:new).and_return(source)
236
+ source.stub(:requires_base_http_service).and_return(true)
237
+ Koala.should_receive(:make_request).with(anything, anything, anything, hash_including(:http_service => Koala.base_http_service)).and_return(Koala::Response.new(200, "[]", {}))
238
+ @api.put_video(StringIO.new)
239
+ end
240
+
241
+ it "should be able to post videos to the user's wall without an open file object" do
242
+ result = @api.put_video(@cat_movie, @content_type)
243
+ @temporary_object_id = result["id"]
244
+ @temporary_object_id.should_not be_nil
245
+ end
246
+
247
+ # note: Facebook doesn't post videos immediately to the wall, due to processing time
248
+ # during which get_object(video_id) will return false
249
+ # hence we can't do the same verify test we do for photos
207
250
  end
208
251
 
209
252
  it "should be able to verify a message with an attachment posted to a feed" do
@@ -267,6 +310,7 @@ shared_examples_for "Koala GraphAPI with an access token" do
267
310
  :search => 3,
268
311
  # methods that have special arguments
269
312
  :put_picture => ["x.jpg", "image/jpg", {}, "me"],
313
+ :put_video => ["x.mp4", "video/mpeg4", {}, "me"],
270
314
  :get_objects => [["x"], {}]
271
315
  }.each_pair do |method_name, params|
272
316
  it "should pass http options through for #{method_name}" do
@@ -343,8 +387,8 @@ shared_examples_for "Koala GraphAPI with GraphCollection" do
343
387
  end
344
388
 
345
389
  it "should have a read-only paging attribute" do
346
- lambda { @result.paging }.should_not raise_error
347
- lambda { @result.paging = "paging" }.should raise_error(NoMethodError)
390
+ @result.methods.map(&:to_sym).should include(:paging)
391
+ @result.methods.map(&:to_sym).should_not include(:paging=)
348
392
  end
349
393
 
350
394
  describe "when getting a whole page" do
@@ -5,6 +5,9 @@ module Koala
5
5
  module MockHTTPService
6
6
  include Koala::HTTPService
7
7
 
8
+ # fix our specs to use ok_json, so we always get the same results from to_json
9
+ MultiJson.engine = :ok_json
10
+
8
11
  # Mocks all HTTP requests for with koala_spec_with_mocks.rb
9
12
  # Mocked values to be included in TEST_DATA used in specs
10
13
  ACCESS_TOKEN = '*'
@@ -154,13 +154,13 @@ shared_examples_for "Koala RestAPI" do
154
154
  "fql.multiquery", anything, anything
155
155
  ).and_return({})
156
156
 
157
- @api.fql_multiquery stub('query string')
157
+ @api.fql_multiquery 'query string'
158
158
  end
159
159
 
160
160
  it "should pass a queries argument" do
161
161
  queries = stub('query string')
162
162
  queries_json = "some JSON"
163
- queries.stub(:to_json).and_return(queries_json)
163
+ MultiJson.stub(:encode).with(queries).and_return(queries_json)
164
164
 
165
165
  @api.should_receive(:rest_call).with(
166
166
  anything,
@@ -4,8 +4,7 @@ module KoalaTest
4
4
  print "Validating permissions for live testing..."
5
5
  # make sure we have the necessary permissions
6
6
  api = Koala::Facebook::GraphAndRestAPI.new(token)
7
- uid = api.get_object("me")["id"]
8
- perms = api.fql_query("select read_stream, publish_stream, user_photos, read_insights from permissions where uid = #{uid}")[0]
7
+ perms = api.fql_query("select read_stream, publish_stream, user_photos, user_videos, read_insights from permissions where uid = me()")[0]
9
8
  perms.each_pair do |perm, value|
10
9
  if value == (perm == "read_insights" ? 1 : 0) # live testing depends on insights calls failing
11
10
  puts "failed!\n" # put a new line after the print above
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: koala
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: 5
5
- version: 1.1.0rc2
5
+ version: 1.1.0rc3
6
6
  platform: ruby
7
7
  authors:
8
8
  - Alex Koppel, Chris Baclig, Rafi Jacoby, Context Optional
@@ -10,11 +10,11 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-06-06 00:00:00 +02:00
13
+ date: 2011-06-30 00:00:00 +02:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
- name: json
17
+ name: multi_json
18
18
  requirement: &id001 !ruby/object:Gem::Requirement
19
19
  none: false
20
20
  requirements:
@@ -80,6 +80,7 @@ extra_rdoc_files:
80
80
  files:
81
81
  - .autotest
82
82
  - .gitignore
83
+ - .travis.yml
83
84
  - CHANGELOG
84
85
  - Gemfile
85
86
  - LICENSE
@@ -88,8 +89,10 @@ files:
88
89
  - autotest/discover.rb
89
90
  - koala.gemspec
90
91
  - lib/koala.rb
92
+ - lib/koala/batch_operation.rb
91
93
  - lib/koala/graph_api.rb
92
- - lib/koala/graph_api_batch.rb
94
+ - lib/koala/graph_batch_api.rb
95
+ - lib/koala/graph_collection.rb
93
96
  - lib/koala/http_services.rb
94
97
  - lib/koala/http_services/net_http_service.rb
95
98
  - lib/koala/http_services/typhoeus_service.rb
@@ -113,6 +116,7 @@ files:
113
116
  - spec/cases/test_users_spec.rb
114
117
  - spec/cases/uploadable_io_spec.rb
115
118
  - spec/fixtures/beach.jpg
119
+ - spec/fixtures/cat.m4v
116
120
  - spec/fixtures/facebook_data.yml
117
121
  - spec/fixtures/mock_facebook_responses.yml
118
122
  - spec/spec_helper.rb
@@ -139,7 +143,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
139
143
  requirements:
140
144
  - - ">="
141
145
  - !ruby/object:Gem::Version
142
- hash: -4094332028190876979
146
+ hash: 1796660115517042142
143
147
  segments:
144
148
  - 0
145
149
  version: "0"
@@ -171,6 +175,7 @@ test_files:
171
175
  - spec/cases/test_users_spec.rb
172
176
  - spec/cases/uploadable_io_spec.rb
173
177
  - spec/fixtures/beach.jpg
178
+ - spec/fixtures/cat.m4v
174
179
  - spec/fixtures/facebook_data.yml
175
180
  - spec/fixtures/mock_facebook_responses.yml
176
181
  - spec/spec_helper.rb
@@ -1,151 +0,0 @@
1
- module Koala
2
- module Facebook
3
- class BatchOperation
4
- attr_reader :access_token, :http_options, :post_processing, :files
5
-
6
- def initialize(options = {})
7
- @args = (options[:args] || {}).dup # because we modify it below
8
- @access_token = options[:access_token]
9
- @http_options = (options[:http_options] || {}).dup # dup because we modify it below
10
- @batch_args = @http_options.delete(:batch_args) || {}
11
- @url = options[:url]
12
- @method = options[:method].to_sym
13
- @post_processing = options[:post_processing]
14
-
15
- process_binary_args
16
-
17
- raise Koala::KoalaError, "Batch operations require an access token, none provided." unless @access_token
18
- end
19
-
20
- def to_batch_params(main_access_token)
21
- # set up the arguments
22
- args_string = Koala.http_service.encode_params(@access_token == main_access_token ? @args : @args.merge(:access_token => @access_token))
23
-
24
- response = {
25
- :method => @method,
26
- :relative_url => @url,
27
- }
28
-
29
- # handle batch-level arguments, such as name, depends_on, and attached_files
30
- @batch_args[:attached_files] = @files.keys.join(",") if @files
31
- response.merge!(@batch_args) if @batch_args
32
-
33
- # for get and delete, we append args to the URL string
34
- # otherwise, they go in the body
35
- if args_string.length > 0
36
- if args_in_url?
37
- response[:relative_url] += (@url =~ /\?/ ? "&" : "?") + args_string if args_string.length > 0
38
- else
39
- response[:body] = args_string if args_string.length > 0
40
- end
41
- end
42
-
43
- response
44
- end
45
-
46
- protected
47
-
48
- def process_binary_args
49
- # collect binary files
50
- @args.each_pair do |key, value|
51
- if UploadableIO.binary_content?(value)
52
- @files ||= {}
53
- # we use object_id to ensure unique file identifiers across multiple batch operations
54
- # remove it from the original hash and add it to the file store
55
- id = "file#{GraphAPI.batch_calls.length}_#{@files.keys.length}"
56
- @files[id] = @args.delete(key).is_a?(UploadableIO) ? value : UploadableIO.new(value)
57
- end
58
- end
59
- end
60
-
61
- def args_in_url?
62
- @method == :get || @method == :delete
63
- end
64
- end
65
-
66
- module GraphAPIBatchMethods
67
- def self.included(base)
68
- base.class_eval do
69
- # batch mode flags
70
- def self.batch_mode?
71
- !!@batch_mode
72
- end
73
-
74
- def self.batch_calls
75
- raise KoalaError, "GraphAPI.batch_calls accessed when not in batch block!" unless batch_mode?
76
- @batch_calls
77
- end
78
-
79
- def self.batch(http_options = {}, &block)
80
- @batch_mode = true
81
- @batch_http_options = http_options
82
- @batch_calls = []
83
- yield
84
- begin
85
- results = batch_api(@batch_calls)
86
- ensure
87
- @batch_mode = false
88
- end
89
- results
90
- end
91
-
92
- def self.batch_api(batch_calls)
93
- return [] unless batch_calls.length > 0
94
- # Facebook requires a top-level access token
95
-
96
- # Get the access token for the user and start building a hash to store params
97
- # Turn the call args collected into what facebook expects
98
- args = {}
99
- access_token = args["access_token"] = batch_calls.first.access_token
100
- args['batch'] = batch_calls.map { |batch_op|
101
- args.merge!(batch_op.files) if batch_op.files
102
- batch_op.to_batch_params(access_token)
103
- }.to_json
104
-
105
- # Make the POST request for the batch call
106
- # batch operations have to go over SSL, but since there's an access token, that secures that
107
- result = Koala.make_request('/', args, 'post', @batch_http_options)
108
- # Raise an error if we get a 500
109
- raise APIError.new("type" => "HTTP #{result.status.to_s}", "message" => "Response body: #{result.body}") if result.status >= 500
110
-
111
- response = JSON.parse(result.body.to_s)
112
- # raise an error if we get a Batch API error message
113
- raise APIError.new("type" => "Error #{response["error"]}", "message" => response["error_description"]) if response.is_a?(Hash) && response["error"]
114
-
115
- # otherwise, map the results with post-processing included
116
- index = 0 # keep compat with ruby 1.8 - no with_index for map
117
- response.map do |call_result|
118
- # Get the options hash
119
- batch_op = batch_calls[index]
120
- index += 1
121
-
122
- if call_result
123
- # (see note in regular api method about JSON parsing)
124
- body = JSON.parse("[#{call_result['body'].to_s}]")[0]
125
- unless call_result["code"].to_i >= 500 || error = GraphAPI.check_response(body)
126
- # Get the HTTP component they want
127
- data = case batch_op.http_options[:http_component]
128
- when :status
129
- call_result["code"].to_i
130
- when :headers
131
- # facebook returns the headers as an array of k/v pairs, but we want a regular hash
132
- call_result['headers'].inject({}) { |headers, h| headers[h['name']] = h['value']; headers}
133
- else
134
- body
135
- end
136
-
137
- # process it if we are given a block to process with
138
- batch_op.post_processing ? batch_op.post_processing.call(data) : data
139
- else
140
- error || APIError.new({"type" => "HTTP #{call_result["code"].to_s}", "message" => "Response body: #{body}"})
141
- end
142
- else
143
- nil
144
- end
145
- end
146
- end
147
- end
148
- end
149
- end
150
- end
151
- end