koala 1.1.0rc → 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.
@@ -3,14 +3,14 @@ require "typhoeus" unless defined?(Typhoeus)
3
3
  module Koala
4
4
  module TyphoeusService
5
5
  # this service uses Typhoeus to send requests to the graph
6
- include Typhoeus
6
+ include Typhoeus
7
7
  include Koala::HTTPService
8
8
 
9
9
  def self.make_request(path, args, verb, options = {})
10
10
  # if the verb isn't get or post, send it as a post argument
11
11
  args.merge!({:method => verb}) && verb = "post" if verb != "get" && verb != "post"
12
12
 
13
- # switch any UploadableIOs to the files Typhoeus expects
13
+ # switch any UploadableIOs to the files Typhoeus expects
14
14
  args.each_pair {|key, value| args[key] = value.to_file if value.is_a?(UploadableIO)}
15
15
 
16
16
  # you can pass arguments directly to Typhoeus using the :typhoeus_options key
@@ -27,9 +27,9 @@ module Koala
27
27
  response = Typhoeus::Request.send(verb, "#{prefix}://#{server(options)}#{path}", typhoeus_options)
28
28
  Koala::Response.new(response.code, response.body, response.headers_hash)
29
29
  end
30
-
30
+
31
31
  protected
32
-
32
+
33
33
  def self.multipart_requires_content_type?
34
34
  false # Typhoeus handles multipart file types, we don't have to require it
35
35
  end
@@ -13,18 +13,20 @@ module Koala
13
13
  def self.included(base)
14
14
  base.class_eval do
15
15
  class << self
16
- attr_accessor :always_use_ssl, :proxy, :timeout, :ca_path, :ca_file
16
+ attr_accessor :always_use_ssl, :proxy, :timeout
17
17
  end
18
18
 
19
19
  def self.server(options = {})
20
- "#{options[:beta] ? "beta." : ""}#{options[:rest_api] ? Facebook::REST_SERVER : Facebook::GRAPH_SERVER}"
20
+ server = "#{options[:rest_api] ? Facebook::REST_SERVER : Facebook::GRAPH_SERVER}"
21
+ server.gsub!(/\.facebook/, "-video.facebook") if options[:video]
22
+ "#{options[:beta] ? "beta." : ""}#{server}"
21
23
  end
22
24
 
23
25
  def self.encode_params(param_hash)
24
26
  # unfortunately, we can't use to_query because that's Rails, not Ruby
25
27
  # if no hash (e.g. no auth token) return empty string
26
28
  ((param_hash || {}).collect do |key_and_value|
27
- key_and_value[1] = key_and_value[1].to_json unless key_and_value[1].is_a? String
29
+ key_and_value[1] = MultiJson.encode(key_and_value[1]) unless key_and_value[1].is_a? String
28
30
  "#{key_and_value[0].to_s}=#{CGI.escape key_and_value[1]}"
29
31
  end).join("&")
30
32
  end
data/lib/koala/oauth.rb CHANGED
@@ -99,7 +99,7 @@ module Koala
99
99
  def parse_signed_request(input)
100
100
  encoded_sig, encoded_envelope = input.split('.', 2)
101
101
  signature = base64_url_decode(encoded_sig).unpack("H*").first
102
- envelope = JSON.parse(base64_url_decode(encoded_envelope))
102
+ envelope = MultiJson.decode(base64_url_decode(encoded_envelope))
103
103
 
104
104
  raise "SignedRequest: Unsupported algorithm #{envelope['algorithm']}" if envelope['algorithm'] != 'HMAC-SHA256'
105
105
 
@@ -126,7 +126,7 @@ module Koala
126
126
  })
127
127
  end
128
128
 
129
- JSON.parse(response)
129
+ MultiJson.decode(response)
130
130
  end
131
131
 
132
132
  def get_tokens_from_session_keys(sessions, options = {})
@@ -149,7 +149,7 @@ module Koala
149
149
  result = fetch_token_string(args, post, "access_token", options)
150
150
 
151
151
  # if we have an error, parse the error JSON and raise an error
152
- raise APIError.new((JSON.parse(result)["error"] rescue nil) || {}) if result =~ /error/
152
+ raise APIError.new((MultiJson.decode(result)["error"] rescue nil) || {}) if result =~ /error/
153
153
 
154
154
  # otherwise, parse the access token
155
155
  parse_access_token(result)
@@ -8,7 +8,7 @@ module Koala
8
8
  end
9
9
 
10
10
  def fql_multiquery(queries = {}, args = {}, options = {})
11
- if results = rest_call('fql.multiquery', args.merge(:queries => queries.to_json), options)
11
+ if results = rest_call('fql.multiquery', args.merge(:queries => MultiJson.encode(queries)), options)
12
12
  # simplify the multiquery result format
13
13
  results.inject({}) {|outcome, data| outcome[data["name"]] = data["fql_result_set"]; outcome}
14
14
  end
@@ -36,108 +36,140 @@ module Koala
36
36
  end
37
37
 
38
38
  private
39
- DETECTION_STRATEGIES = [
40
- :sinatra_param?,
41
- :rails_3_param?,
42
- :file_param?
43
- ]
39
+ DETECTION_STRATEGIES = [
40
+ :sinatra_param?,
41
+ :rails_3_param?,
42
+ :file_param?
43
+ ]
44
+
45
+ PARSE_STRATEGIES = [
46
+ :parse_rails_3_param,
47
+ :parse_sinatra_param,
48
+ :parse_file_object,
49
+ :parse_string_path
50
+ ]
44
51
 
45
- PARSE_STRATEGIES = [
46
- :parse_rails_3_param,
47
- :parse_sinatra_param,
48
- :parse_file_object,
49
- :parse_string_path
50
- ]
51
-
52
- def parse_init_mixed_param(mixed)
53
- PARSE_STRATEGIES.each do |method|
54
- send(method, mixed)
55
- return if @io_or_path && @content_type
56
- end
57
- end
58
-
59
- # Expects a parameter of type ActionDispatch::Http::UploadedFile
60
- def self.rails_3_param?(uploaded_file)
61
- uploaded_file.respond_to?(:content_type) and uploaded_file.respond_to?(:tempfile) and uploaded_file.tempfile.respond_to?(:path)
62
- end
63
-
64
- def parse_rails_3_param(uploaded_file)
65
- if UploadableIO.rails_3_param?(uploaded_file)
66
- @io_or_path = uploaded_file.tempfile.path
67
- @content_type = uploaded_file.content_type
68
- end
69
- end
70
-
71
- # Expects a Sinatra hash of file info
72
- def self.sinatra_param?(file_hash)
73
- file_hash.kind_of?(Hash) and file_hash.has_key?(:type) and file_hash.has_key?(:tempfile)
52
+ def parse_init_mixed_param(mixed)
53
+ PARSE_STRATEGIES.each do |method|
54
+ send(method, mixed)
55
+ return if @io_or_path && @content_type
74
56
  end
75
-
76
- def parse_sinatra_param(file_hash)
77
- if UploadableIO.sinatra_param?(file_hash)
78
- @io_or_path = file_hash[:tempfile]
79
- @content_type = file_hash[:type] || detect_mime_type(tempfile)
80
- end
57
+ end
58
+
59
+ # Expects a parameter of type ActionDispatch::Http::UploadedFile
60
+ def self.rails_3_param?(uploaded_file)
61
+ uploaded_file.respond_to?(:content_type) and uploaded_file.respond_to?(:tempfile) and uploaded_file.tempfile.respond_to?(:path)
62
+ end
63
+
64
+ def parse_rails_3_param(uploaded_file)
65
+ if UploadableIO.rails_3_param?(uploaded_file)
66
+ @io_or_path = uploaded_file.tempfile.path
67
+ @content_type = uploaded_file.content_type
81
68
  end
82
-
83
- # takes a file object
84
- def self.file_param?(file)
85
- file.kind_of?(File)
69
+ end
70
+
71
+ # Expects a Sinatra hash of file info
72
+ def self.sinatra_param?(file_hash)
73
+ file_hash.kind_of?(Hash) and file_hash.has_key?(:type) and file_hash.has_key?(:tempfile)
74
+ end
75
+
76
+ def parse_sinatra_param(file_hash)
77
+ if UploadableIO.sinatra_param?(file_hash)
78
+ @io_or_path = file_hash[:tempfile]
79
+ @content_type = file_hash[:type] || detect_mime_type(tempfile)
86
80
  end
87
-
88
- def parse_file_object(file)
89
- if UploadableIO.file_param?(file)
90
- @io_or_path = file
91
- @content_type = detect_mime_type(file.path)
92
- end
81
+ end
82
+
83
+ # takes a file object
84
+ def self.file_param?(file)
85
+ file.kind_of?(File)
86
+ end
87
+
88
+ def parse_file_object(file)
89
+ if UploadableIO.file_param?(file)
90
+ @io_or_path = file
91
+ @content_type = detect_mime_type(file.path)
93
92
  end
94
-
95
- def parse_string_path(path)
96
- if path.kind_of?(String)
97
- @io_or_path = path
98
- @content_type = detect_mime_type(path)
99
- end
93
+ end
94
+
95
+ def parse_string_path(path)
96
+ if path.kind_of?(String)
97
+ @io_or_path = path
98
+ @content_type = detect_mime_type(path)
100
99
  end
101
-
102
- MIME_TYPE_STRATEGIES = [
103
- :use_mime_module,
104
- :use_simple_detection
105
- ]
106
-
107
- def detect_mime_type(filename)
108
- if filename
109
- MIME_TYPE_STRATEGIES.each do |method|
110
- result = send(method, filename)
111
- return result if result
112
- end
100
+ end
101
+
102
+ MIME_TYPE_STRATEGIES = [
103
+ :use_mime_module,
104
+ :use_simple_detection
105
+ ]
106
+
107
+ def detect_mime_type(filename)
108
+ if filename
109
+ MIME_TYPE_STRATEGIES.each do |method|
110
+ result = send(method, filename)
111
+ return result if result
113
112
  end
114
- nil # if we can't find anything
115
113
  end
116
-
117
- def use_mime_module(filename)
118
- # if the user has installed mime/types, we can use that
119
- # if not, rescue and return nil
120
- begin
121
- type = MIME::Types.type_for(filename).first
122
- type ? type.to_s : nil
123
- rescue
124
- nil
125
- end
114
+ nil # if we can't find anything
115
+ end
116
+
117
+ def use_mime_module(filename)
118
+ # if the user has installed mime/types, we can use that
119
+ # if not, rescue and return nil
120
+ begin
121
+ type = MIME::Types.type_for(filename).first
122
+ type ? type.to_s : nil
123
+ rescue
124
+ nil
126
125
  end
127
-
128
- def use_simple_detection(filename)
129
- # very rudimentary extension analysis for images
130
- # first, get the downcased extension, or an empty string if it doesn't exist
131
- extension = ((filename.match(/\.([a-zA-Z0-9]+)$/) || [])[1] || "").downcase
132
- if extension == ""
126
+ end
127
+
128
+ def use_simple_detection(filename)
129
+ # very rudimentary extension analysis for images
130
+ # first, get the downcased extension, or an empty string if it doesn't exist
131
+ extension = ((filename.match(/\.([a-zA-Z0-9]+)$/) || [])[1] || "").downcase
132
+ case extension
133
+ when ""
133
134
  nil
134
- elsif extension == "jpg" || extension == "jpeg"
135
+ # images
136
+ when "jpg", "jpeg"
135
137
  "image/jpeg"
136
- elsif extension == "png"
138
+ when "png"
137
139
  "image/png"
138
- elsif extension == "gif"
140
+ when "gif"
139
141
  "image/gif"
140
- end
141
- end
142
+
143
+ # video
144
+ when "3g2"
145
+ "video/3gpp2"
146
+ when "3gp", "3gpp"
147
+ "video/3gpp"
148
+ when "asf"
149
+ "video/x-ms-asf"
150
+ when "avi"
151
+ "video/x-msvideo"
152
+ when "flv"
153
+ "video/x-flv"
154
+ when "m4v"
155
+ "video/x-m4v"
156
+ when "mkv"
157
+ "video/x-matroska"
158
+ when "mod"
159
+ "video/mod"
160
+ when "mov", "qt"
161
+ "video/quicktime"
162
+ when "mp4", "mpeg4"
163
+ "video/mp4"
164
+ when "mpe", "mpeg", "mpg", "tod", "vob"
165
+ "video/mpeg"
166
+ when "nsv"
167
+ "application/x-winamp"
168
+ when "ogm", "ogv"
169
+ "video/ogg"
170
+ when "wmv"
171
+ "video/x-ms-wmv"
172
+ end
173
+ end
142
174
  end
143
175
  end
data/lib/koala.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'cgi'
2
2
  require 'digest/md5'
3
3
 
4
- require 'json'
4
+ require 'multi_json'
5
5
 
6
6
  # OpenSSL and Base64 are required to support signed_request
7
7
  require 'openssl'
@@ -12,7 +12,9 @@ require 'koala/http_services'
12
12
  require 'koala/http_services/net_http_service'
13
13
  require 'koala/oauth'
14
14
  require 'koala/graph_api'
15
- require 'koala/graph_api_batch'
15
+ require 'koala/graph_batch_api'
16
+ require 'koala/batch_operation'
17
+ require 'koala/graph_collection'
16
18
  require 'koala/rest_api'
17
19
  require 'koala/realtime_updates'
18
20
  require 'koala/test_users'
@@ -53,8 +55,8 @@ module Koala
53
55
 
54
56
  # parse the body as JSON and run it through the error checker (if provided)
55
57
  # Note: Facebook sometimes sends results like "true" and "false", which aren't strictly objects
56
- # and cause JSON.parse to fail -- so we account for that by wrapping the result in []
57
- body = JSON.parse("[#{result.body.to_s}]")[0]
58
+ # and cause MultiJson.decode to fail -- so we account for that by wrapping the result in []
59
+ body = MultiJson.decode("[#{result.body.to_s}]")[0]
58
60
  yield body if error_checking_block
59
61
 
60
62
  # if we want a component other than the body (e.g. redirect header for images), return that
@@ -66,9 +68,12 @@ module Koala
66
68
 
67
69
  class GraphAPI < API
68
70
  include GraphAPIMethods
69
- include GraphAPIBatchMethods
70
71
  end
71
72
 
73
+ class GraphBatchAPI < GraphAPI
74
+ include GraphBatchAPIMethods
75
+ end
76
+
72
77
  class RestAPI < API
73
78
  include RestAPIMethods
74
79
  end
data/readme.md CHANGED
@@ -1,9 +1,9 @@
1
1
  Koala
2
2
  ====
3
- Koala (<a href="http://github.com/arsduo/koala" target="_blank">http://github.com/arsduo/koala</a>) is a new Facebook library for Ruby, supporting the Graph API (including the batch requests and photo uploads), the REST API, realtime updates, test users, and OAuth validation. We wrote Koala with four goals:
3
+ [Koala](http://github.com/arsduo/koala) is a new Facebook library for Ruby, supporting the Graph API (including the batch requests and photo uploads), the REST API, realtime updates, test users, and OAuth validation. We wrote Koala with four goals:
4
4
 
5
- * Lightweight: Koala should be as light and simple as Facebook’s own new libraries, providing API accessors and returning simple JSON. (We clock in, with comments, just over 750 lines of code.)
6
- * Fast: Koala should, out of the box, be quick. In addition to supporting the vanilla Ruby networking libraries, it natively supports Typhoeus, our preferred gem for making fast HTTP requests. Of course, That brings us to our next topic:
5
+ * Lightweight: Koala should be as light and simple as Facebook’s own new libraries, providing API accessors and returning simple JSON. (We clock in, with comments, at just over 750 lines of code.)
6
+ * Fast: Koala should, out of the box, be quick. In addition to supporting the vanilla Ruby networking libraries, it natively supports Typhoeus, our preferred gem for making fast HTTP requests. Of course, that brings us to our next topic:
7
7
  * Flexible: Koala should be useful to everyone, regardless of their current configuration. (We have no dependencies beyond the JSON gem. Koala also has a built-in mechanism for using whichever HTTP library you prefer to make requests against the graph.)
8
8
  * Tested: Koala should have complete test coverage, so you can rely on it. (Our complete test coverage can be run against either mocked responses or the live Facebook servers.)
9
9
 
@@ -47,7 +47,7 @@ When retrieving data that returns an array of results (for example, when calling
47
47
  # This is useful for paging across multiple requests
48
48
  next_path, next_args = feed.next_page_params
49
49
 
50
- # You can use those params to easily get the next (or prevous) page
50
+ # You can use those params to easily get the next (or previous) page
51
51
  page = graph.get_page(feed.next_page_params)
52
52
 
53
53
  You can make multiple calls at once using Facebook's batch API:
@@ -144,12 +144,12 @@ Testing
144
144
  Unit tests are provided for all of Koala's methods. By default, these tests run against mock responses and hence are ready out of the box:
145
145
 
146
146
  # From anywhere in the project directory:
147
- rake spec
147
+ bundle exec rake spec
148
148
 
149
149
 
150
150
  You can also run live tests against Facebook's servers:
151
151
 
152
152
  # Again from anywhere in the project directory:
153
- LIVE=true rake spec
153
+ LIVE=true bundle exec rake spec
154
154
 
155
- Important Note: to run the live tests, you have to provide some of your own data in spec/fixtures/facebook_data.yml: a valid OAuth access token with publish\_stream, read\_stream, and user\_photos permissions and an OAuth code that can be used to generate an access token. You can get thisdata at the OAuth Playground; if you want to use your own app, remember to swap out the app ID, secret, and other values. (The file also provides valid values for other tests, which you're welcome to swap out for data specific to your own application.)
155
+ Important Note: to run the live tests, you have to provide some of your own data in spec/fixtures/facebook_data.yml: a valid OAuth access token with publish\_stream, read\_stream, and user\_photos permissions and an OAuth code that can be used to generate an access token. You can get this data at the OAuth Playground; if you want to use your own app, remember to swap out the app ID, secret, and other values. (The file also provides valid values for other tests, which you're welcome to swap out for data specific to your own application.)
@@ -52,7 +52,7 @@ describe "Koala::Facebook::API" do
52
52
  Koala.stub(:make_request).and_return(response)
53
53
 
54
54
  json_body = mock('JSON body')
55
- JSON.stub(:parse).and_return([json_body])
55
+ MultiJson.stub(:decode).and_return([json_body])
56
56
 
57
57
  @service.api('anything').should == json_body
58
58
  end
@@ -66,7 +66,7 @@ describe "Koala::Facebook::API" do
66
66
 
67
67
  @service.api('anything', {}, "get") do |arg|
68
68
  yield_test.pass
69
- arg.should == JSON.parse(body)
69
+ arg.should == MultiJson.decode(body)
70
70
  end
71
71
  end
72
72