lib/koala/graph_api.rb in koala-1.0.0 vs lib/koala/graph_api.rb in koala-1.1.0rc
- old
+ new
@@ -26,23 +26,36 @@
# JavaScript SDK. See the Koala and Facebook documentation for more information.
#
# If you are using the JavaScript SDK, you can use the
# Koala::Facebook::OAuth.get_user_from_cookie() method below to get the OAuth access token
# for the active user from the cookie saved by the SDK.
-
+
+ def self.included(base)
+ base.class_eval do
+ def self.check_response(response)
+ # check for Graph API-specific errors
+ # this returns an error, which is immediately raised (non-batch)
+ # or added to the list of batch results (batch)
+ if response.is_a?(Hash) && error_details = response["error"]
+ APIError.new(error_details)
+ end
+ end
+ end
+ end
+
# Objects
def get_object(id, args = {}, options = {})
# Fetchs the given object from the graph.
graph_call(id, args, "get", options)
end
def get_objects(ids, args = {}, options = {})
- # Fetchs all of the given object from the graph.
- # We return a map from ID to object. If any of the IDs are invalid,
- # we raise an exception.
- graph_call("", args.merge("ids" => ids.join(",")), "get", options)
+ # Fetchs all of the given objects from the graph.
+ # If any of the IDs are invalid, they'll raise an exception.
+ return [] if ids.empty?
+ graph_call("", args.merge("ids" => ids.respond_to?(:join) ? ids.join(",") : ids), "get", options)
end
def put_object(parent_object, connection_name, args = {}, options = {})
# Writes the given object to the graph, connected to the given parent.
# See http://developers.facebook.com/docs/api#publishing for all of
@@ -69,14 +82,23 @@
# Connections
def get_connections(id, connection_name, args = {}, options = {})
# Fetchs the connections for given object.
- result = graph_call("#{id}/#{connection_name}", args, "get", options)
- result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
+ graph_call("#{id}/#{connection_name}", args, "get", options) do |result|
+ result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
+ end
end
+ def get_comments_for_urls(urls = [], args = {}, options = {})
+ # Fetchs the comments for given URLs (array or comma-separated string)
+ # see https://developers.facebook.com/blog/post/490
+ return [] if urls.empty?
+ args.merge!(:ids => urls.respond_to?(:join) ? urls.join(",") : urls)
+ get_object("comments", args, options)
+ end
+
def put_connections(id, connection_name, args = {}, options = {})
# Posts a certain connection
raise APIError.new({"type" => "KoalaMissingAccessToken", "message" => "Write operations require an access token"}) unless @access_token
graph_call("#{id}/#{connection_name}", args, "post", options)
end
@@ -91,12 +113,13 @@
# to delete pictures, use delete_object(photo_id)
# note: you'll need the user_photos permission to actually access photos after uploading them
def get_picture(object, args = {}, options = {})
# Gets a picture object, returning the URL (which Facebook sends as a header)
- result = graph_call("#{object}/picture", args, "get", options.merge(:http_component => :headers))
- result["Location"]
+ graph_call("#{object}/picture", args, "get", options.merge(:http_component => :headers)) do |result|
+ result["Location"]
+ end
end
def put_picture(*picture_args)
# Can be called in multiple ways:
#
@@ -121,11 +144,13 @@
args = picture_args[1 + args_offset] || {}
target_id = picture_args[2 + args_offset] || "me"
options = picture_args[3 + args_offset] || {}
args["source"] = Koala::UploadableIO.new(*picture_args.slice(0, 1 + args_offset))
-
+
+ options[:http_service] = Koala.base_http_service if args["source"].requires_base_http_service
+
self.put_object(target_id, "photos", args, options)
end
# Wall posts
# To get wall posts, use get_connections(user, "feed")
@@ -170,50 +195,65 @@
# Search
def search(search_terms, args = {}, options = {})
args.merge!({:q => search_terms}) unless search_terms.nil?
- result = graph_call("search", args, "get", options)
- result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
+ graph_call("search", args, "get", options) do |result|
+ result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
+ end
end
# API access
-
- def graph_call(*args)
+
+ # Make a call which may or may not be batched
+ def graph_call(path, args = {}, verb = "get", options = {}, &post_processing)
# Direct access to the Facebook API
# see any of the above methods for example invocations
- response = api(*args) do |response|
- # check for Graph API-specific errors
- if response.is_a?(Hash) && error_details = response["error"]
- raise APIError.new(error_details)
+ unless GraphAPI.batch_mode?
+ result = api(path, args, verb, options) do |response|
+ if error = GraphAPI.check_response(response)
+ raise error
+ end
end
+
+ # now process as appropriate (get picture header, make GraphCollection, etc.)
+ post_processing ? post_processing.call(result) : result
+ else
+ # for batch APIs, we queue up the call details (incl. post-processing)
+ GraphAPI.batch_calls << BatchOperation.new(
+ :url => path,
+ :args => args,
+ :method => verb,
+ :access_token => @access_token,
+ :http_options => options,
+ :post_processing => post_processing
+ )
+ nil # batch operations return nothing immediately
end
+ end
- response
- end
-
# GraphCollection support
-
def get_page(params)
# Pages through a set of results stored in a GraphCollection
# Used for connections and search results
- result = graph_call(*params)
- result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
+ graph_call(*params) do |result|
+ result ? GraphCollection.new(result, self) : nil # when facebook is down nil can be returned
+ end
end
end
class GraphCollection < Array
- #This class is a light wrapper for collections returned
- #from the Graph API.
+ # This class is a light wrapper for collections returned
+ # from the Graph API.
#
- #It extends Array to allow direct access to the data colleciton
- #which should allow it to drop in seamlessly.
+ # It extends Array to allow direct access to the data colleciton
+ # which should allow it to drop in seamlessly.
#
- #It also allows access to paging information and the
- #ability to get the next/previous page in the collection
- #by calling next_page or previous_page.
+ # It also allows access to paging information and the
+ # ability to get the next/previous page in the collection
+ # by calling next_page or previous_page.
attr_reader :paging
attr_reader :api
def initialize(response, api)
super response["data"]