koala 1.1.0 → 1.2.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.
Files changed (52) hide show
  1. data/.travis.yml +2 -1
  2. data/CHANGELOG +36 -0
  3. data/Gemfile +6 -2
  4. data/Rakefile +0 -1
  5. data/koala.gemspec +7 -8
  6. data/lib/koala/batch_operation.rb +15 -15
  7. data/lib/koala/graph_api.rb +85 -73
  8. data/lib/koala/graph_batch_api.rb +21 -11
  9. data/lib/koala/graph_collection.rb +13 -8
  10. data/lib/koala/http_service.rb +176 -0
  11. data/lib/koala/oauth.rb +34 -24
  12. data/lib/koala/realtime_updates.rb +21 -18
  13. data/lib/koala/rest_api.rb +1 -1
  14. data/lib/koala/test_users.rb +33 -17
  15. data/lib/koala/uploadable_io.rb +49 -43
  16. data/lib/koala/utils.rb +11 -0
  17. data/lib/koala/version.rb +3 -0
  18. data/lib/koala.rb +47 -45
  19. data/readme.md +58 -38
  20. data/spec/cases/{api_base_spec.rb → api_spec.rb} +27 -2
  21. data/spec/cases/error_spec.rb +32 -0
  22. data/spec/cases/graph_and_rest_api_spec.rb +12 -21
  23. data/spec/cases/graph_api_batch_spec.rb +92 -119
  24. data/spec/cases/graph_api_spec.rb +11 -14
  25. data/spec/cases/graph_collection_spec.rb +116 -0
  26. data/spec/cases/http_service_spec.rb +446 -0
  27. data/spec/cases/koala_spec.rb +36 -37
  28. data/spec/cases/oauth_spec.rb +318 -212
  29. data/spec/cases/realtime_updates_spec.rb +45 -31
  30. data/spec/cases/rest_api_spec.rb +23 -7
  31. data/spec/cases/test_users_spec.rb +123 -75
  32. data/spec/cases/uploadable_io_spec.rb +77 -36
  33. data/spec/cases/utils_spec.rb +10 -0
  34. data/spec/fixtures/facebook_data.yml +26 -24
  35. data/spec/fixtures/mock_facebook_responses.yml +131 -101
  36. data/spec/spec_helper.rb +29 -5
  37. data/spec/support/graph_api_shared_examples.rb +80 -120
  38. data/spec/support/json_testing_fix.rb +35 -11
  39. data/spec/support/koala_test.rb +187 -0
  40. data/spec/support/mock_http_service.rb +8 -5
  41. data/spec/support/ordered_hash.rb +205 -0
  42. data/spec/support/rest_api_shared_examples.rb +37 -37
  43. data/spec/support/uploadable_io_shared_examples.rb +2 -8
  44. metadata +72 -83
  45. data/lib/koala/http_services/net_http_service.rb +0 -92
  46. data/lib/koala/http_services/typhoeus_service.rb +0 -37
  47. data/lib/koala/http_services.rb +0 -46
  48. data/spec/cases/http_services/http_service_spec.rb +0 -129
  49. data/spec/cases/http_services/net_http_service_spec.rb +0 -532
  50. data/spec/cases/http_services/typhoeus_service_spec.rb +0 -152
  51. data/spec/support/live_testing_data_helper.rb +0 -40
  52. data/spec/support/setup_mocks_or_live.rb +0 -51
@@ -0,0 +1,3 @@
1
+ module Koala
2
+ VERSION = "1.2.0"
3
+ end
data/lib/koala.rb CHANGED
@@ -8,8 +8,6 @@ require 'openssl'
8
8
  require 'base64'
9
9
 
10
10
  # include koala modules
11
- require 'koala/http_services'
12
- require 'koala/http_services/net_http_service'
13
11
  require 'koala/oauth'
14
12
  require 'koala/graph_api'
15
13
  require 'koala/graph_batch_api'
@@ -18,11 +16,17 @@ require 'koala/graph_collection'
18
16
  require 'koala/rest_api'
19
17
  require 'koala/realtime_updates'
20
18
  require 'koala/test_users'
21
- require 'koala/http_services'
19
+
20
+ # HTTP module so we can communicate with Facebook
21
+ require 'koala/http_service'
22
22
 
23
23
  # add KoalaIO class
24
24
  require 'koala/uploadable_io'
25
25
 
26
+ # miscellaneous
27
+ require 'koala/utils'
28
+ require 'koala/version'
29
+
26
30
  module Koala
27
31
 
28
32
  module Facebook
@@ -31,6 +35,7 @@ module Koala
31
35
  # Contributors: Alex Koppel, Chris Baclig, Rafi Jacoby, and the team at Context Optional
32
36
  # http://github.com/arsduo/koala
33
37
 
38
+ # APIs
34
39
  class API
35
40
  # initialize with an access token
36
41
  def initialize(access_token = nil)
@@ -38,10 +43,13 @@ module Koala
38
43
  end
39
44
  attr_reader :access_token
40
45
 
46
+ include GraphAPIMethods
47
+ include RestAPIMethods
48
+
41
49
  def api(path, args = {}, verb = "get", options = {}, &error_checking_block)
42
50
  # Fetches the given path in the Graph API.
43
51
  args["access_token"] = @access_token || @app_access_token if @access_token || @app_access_token
44
-
52
+
45
53
  # add a leading /
46
54
  path = "/#{path}" unless path =~ /^\//
47
55
 
@@ -64,35 +72,30 @@ module Koala
64
72
  end
65
73
  end
66
74
 
67
- # APIs
68
-
69
- class GraphAPI < API
70
- include GraphAPIMethods
71
- end
72
-
73
- class GraphBatchAPI < GraphAPI
74
- include GraphBatchAPIMethods
75
- end
76
-
77
- class RestAPI < API
78
- include RestAPIMethods
75
+ # special enhanced APIs
76
+ class GraphBatchAPI < API
77
+ include GraphBatchAPIMethods
79
78
  end
80
79
 
81
- class GraphAndRestAPI < API
82
- include GraphAPIMethods
83
- include RestAPIMethods
84
- end
85
-
86
- class RealtimeUpdates < API
80
+ class RealtimeUpdates
87
81
  include RealtimeUpdateMethods
88
82
  end
89
83
 
90
- class TestUsers < API
84
+ class TestUsers
91
85
  include TestUserMethods
92
- # make the Graph API accessible in case someone wants to make other calls to interact with their users
93
- attr_reader :graph_api
94
86
  end
95
87
 
88
+ # legacy support for old APIs
89
+ class OldAPI < API;
90
+ def initialize(*args)
91
+ Koala::Utils.deprecate("#{self.class.name} is deprecated and will be removed in a future version; please use the API class instead.")
92
+ super
93
+ end
94
+ end
95
+ class GraphAPI < OldAPI; end
96
+ class RestAPI < OldAPI; end
97
+ class GraphAndRestAPI < OldAPI; end
98
+
96
99
  # Errors
97
100
 
98
101
  class APIError < StandardError
@@ -106,29 +109,28 @@ module Koala
106
109
 
107
110
  class KoalaError < StandardError; end
108
111
 
109
- # Make an api request using the provided api service or one passed by the caller
110
- def self.make_request(path, args, verb, options = {})
111
- http_service = options.delete(:http_service) || Koala.http_service
112
- options = options.merge(:use_ssl => true) if @always_use_ssl
113
- http_service.make_request(path, args, verb, options)
114
- end
115
112
 
116
- # finally, set up the http service Koala methods used to make requests
117
- # you can use your own (for HTTParty, etc.) by calling Koala.http_service = YourModule
113
+ # finally, the few things defined on the Koala module itself
118
114
  class << self
119
115
  attr_accessor :http_service
120
- attr_accessor :always_use_ssl
121
- attr_accessor :base_http_service
122
116
  end
123
- Koala.base_http_service = NetHTTPService
124
-
125
- # by default, try requiring Typhoeus -- if that works, use it
126
- # if you have Typheous and don't want to use it (or want another service),
127
- # you can run Koala.http_service = NetHTTPService (or MyHTTPService)
128
- begin
129
- require 'koala/http_services/typhoeus_service'
130
- Koala.http_service = TyphoeusService
131
- rescue LoadError
132
- Koala.http_service = Koala.base_http_service
117
+
118
+ def self.http_service=(service)
119
+ if service.respond_to?(:deprecated_interface)
120
+ # if this is a deprecated module, support the old interface
121
+ # by changing the default adapter so the right library is used
122
+ # we continue to use the single HTTPService module for everything
123
+ service.deprecated_interface
124
+ else
125
+ # if it's a real http_service, use it
126
+ @http_service = service
127
+ end
133
128
  end
129
+
130
+ def self.make_request(path, args, verb, options = {})
131
+ http_service.make_request(path, args, verb, options)
132
+ end
133
+
134
+ # we use Faraday as our main service, with mock as the other main one
135
+ self.http_service = HTTPService
134
136
  end
data/readme.md CHANGED
@@ -1,77 +1,95 @@
1
+ [![Build Status](https://secure.travis-ci.org/arsduo/koala.png)](http://travis-ci.org/arsduo/koala)
2
+
1
3
  Koala
2
4
  ====
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:
5
+ [Koala](http://github.com/arsduo/koala) is a 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:
6
+
7
+ * Lightweight: Koala should be as light and simple as Facebook’s own libraries, providing API accessors and returning simple JSON.
8
+ * Fast: Koala should, out of the box, be quick. Out of the box, we use Facebook's faster read-only servers when possible and if available, the Typhoeus gem to make snappy Facebook requests. Of course, that brings us to our next topic:
9
+ * Flexible: Koala should be useful to everyone, regardless of their current configuration. (We support JRuby, Rubinius, and REE as well as vanilla Ruby, and use the Faraday library to provide complete flexibility over how HTTP requests are made.)
10
+ * Tested: Koala should have complete test coverage, so you can rely on it. (Our test coverage is complete and can be run against either mocked responses or the live Facebook servers.)
11
+
12
+ Facebook Changes on October 1, 2011
13
+ ---
4
14
 
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
- * Flexible: Koala should be useful to everyone, regardless of their current configuration. (In addition to vanilla Ruby, we support JRuby, Rubinius, and REE, and provide built-in mechanism for using whichever HTTP library you prefer.)
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.)
15
+ **Koala 1.2 supports all of Facebook's new authentication schemes**, which will be introduced on October 1, 2011; the old Javascript library and older authentication schemes will be deprecated at the same time.
16
+
17
+ To test your application, upgrade to the latest version of Koala (see below) and configure your application according to Facebook's [OAuth 2.0 and HTTPS Migration](https://developers.facebook.com/docs/oauth2-https-migration/) guide. If you have the appropriate calls to get_user_info_from_cookies (apps using the Javascript SDK) and/or parse_signed_params (for Canvas and tab apps), your application should work without a hitch.
18
+
19
+ _Note_: in their new secure cookie format, Facebook provides an OAuth code, which Koala automatically exchanges for an access token. Because this involves a call to Facebook's servers, you should consider storing the user's access token in their session and only calling get_user_info_from_cookies when necessary (access_token not present, you discover it's expired, etc.). Otherwise, you'll be calling out to Facebook each time the user loads a page, slowing down your site. (As we figure out best practices for this, we'll update the wiki.)
9
20
 
10
21
  Installation
11
22
  ---
12
23
 
13
24
  Easy:
14
-
25
+
15
26
  [sudo|rvm] gem install koala
16
-
27
+
17
28
  Or in Bundler:
18
-
29
+
19
30
  gem "koala"
20
-
31
+
21
32
  Graph API
22
33
  ----
23
34
  The Graph API is the simple, slick new interface to Facebook's data. Using it with Koala is quite straightforward:
24
-
25
- @graph = Koala::Facebook::GraphAPI.new(oauth_access_token)
35
+
36
+ @graph = Koala::Facebook::API.new(oauth_access_token)
37
+ # in 1.1 or earlier, use GraphAPI instead of API
38
+
26
39
  profile = @graph.get_object("me")
27
40
  friends = @graph.get_connections("me", "friends")
28
41
  @graph.put_object("me", "feed", :message => "I am writing on my wall!")
29
42
 
43
+ # you can even use the new Timeline API
44
+ # see https://developers.facebook.com/docs/beta/opengraph/tutorial/
45
+ @graph.put_connections("me", "namespace:action", :object => object_url)
46
+
30
47
  The response of most requests is the JSON data returned from the Facebook servers as a Hash.
31
48
 
32
- When retrieving data that returns an array of results (for example, when calling GraphAPI#get_connections or GraphAPI#search) a GraphCollection object (a sub-class of Array) will be returned, which contains added methods for getting the next and previous page of results:
49
+ When retrieving data that returns an array of results (for example, when calling API#get_connections or API#search) a GraphCollection object will be returned, which makes it easy to page through the results:
33
50
 
34
51
  # Returns the feed items for the currently logged-in user as a GraphCollection
35
52
  feed = @graph.get_connections("me", "feed")
36
-
37
- # GraphCollection is a sub-class of Array, so you can use it as a usual Array
38
- first_entry = feed[0]
39
- last_entry = feed.last
40
-
41
- # Returns the next page of results (also as a GraphCollection)
53
+ feed.each {|f| do_something_with_item(f) } # it's a subclass of Array
42
54
  next_feed = feed.next_page
43
55
 
44
- # Returns an array describing the URL for the next page: [path, arguments]
45
- # This is useful for paging across multiple requests
46
- next_path, next_args = feed.next_page_params
56
+ # You can also get an array describing the URL for the next page: [path, arguments]
57
+ # This is useful for storing page state across multiple browser requests
58
+ next_page_params = feed.next_page_params
59
+ page = @graph.get_page(next_page_params)
47
60
 
48
- # You can use those params to easily get the next (or previous) page
49
- page = @graph.get_page(feed.next_page_params)
50
-
51
- You can make multiple calls at once using Facebook's batch API:
61
+ You can also make multiple calls at once using Facebook's batch API:
52
62
 
53
63
  # Returns an array of results as if they were called non-batch
54
64
  @graph.batch do |batch_api|
55
65
  batch_api.get_object('me')
56
- batch_api.get_object('koppel')
66
+ batch_api.put_wall_post('Making a post in a batch.')
57
67
  end
58
68
 
59
- Check out the wiki for more examples.
69
+ Check out the wiki for more details and examples.
60
70
 
61
71
  The REST API
62
72
  -----
63
73
  Where the Graph API and the old REST API overlap, you should choose the Graph API. Unfortunately, that overlap is far from complete, and there are many important API calls that can't yet be done via the Graph.
64
74
 
65
- Koala now supports the old-school REST API using OAuth access tokens; to use this, instantiate your class using the RestAPI class:
75
+ Fortunately, Koala supports the REST API using the very same interface; to use this, instantiate an API:
66
76
 
67
- @rest = Koala::Facebook::RestAPI.new(oauth_access_token)
77
+ @rest = Koala::Facebook::API.new(oauth_access_token)
78
+ # in 1.1 or earlier, use RestAPI instead of API
79
+
68
80
  @rest.fql_query(my_fql_query) # convenience method
69
81
  @rest.fql_multiquery(fql_query_hash) # convenience method
70
82
  @rest.rest_call("stream.publish", arguments_hash) # generic version
71
83
 
72
- We reserve the right to expand the built-in REST API coverage to additional convenience methods in the future, depending on how fast Facebook moves to fill in the gaps.
84
+ Of course, you can use the Graph API methods on the same object -- the power of two APIs right in the palm of your hand.
73
85
 
74
- (If you want the power of both APIs in the palm of your hand, try out the GraphAndRestAPI class.)
86
+ @api = Koala::Facebook::API.new(oauth_access_token)
87
+ # in 1.1 or earlier, use GraphAndRestAPI instead of API
88
+
89
+ @api = Koala::Facebook::API.new(oauth_access_token)
90
+ fql = @api.fql_query(my_fql_query)
91
+ @api.put_wall_post(process_result(fql))
92
+
75
93
 
76
94
  OAuth
77
95
  -----
@@ -92,7 +110,7 @@ You can also get your application's own access token, which can be used without
92
110
  @oauth.get_app_access_token
93
111
 
94
112
  For those building apps on Facebook, parsing signed requests is simple:
95
- @oauth.parse_signed_request(request)
113
+ @oauth.parse_signed_request(signed_request_string)
96
114
 
97
115
  Or, if for some horrible reason, you're still using session keys, despair not! It's easy to turn them into shiny, modern OAuth tokens:
98
116
  @oauth.get_token_from_session_key(session_key)
@@ -130,10 +148,10 @@ Test Users
130
148
  -----
131
149
 
132
150
  We also support the test users API, allowing you to conjure up fake users and command them to do your bidding using the Graph or REST API:
133
-
151
+
134
152
  @test_users = Koala::Facebook::TestUsers.new(:app_id => id, :secret => secret)
135
153
  user = @test_users.create(is_app_installed, desired_permissions)
136
- user_graph_api = Koala::Facebook::GraphAPI.new(user["access_token"])
154
+ user_graph_api = Koala::Facebook::API.new(user["access_token"])
137
155
  # or, if you want to make a whole community:
138
156
  @test_users.create_network(network_size, is_app_installed, common_permissions)
139
157
 
@@ -149,14 +167,16 @@ Testing
149
167
  -----
150
168
 
151
169
  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:
152
-
170
+
153
171
  # From anywhere in the project directory:
154
172
  bundle exec rake spec
155
-
173
+
156
174
 
157
175
  You can also run live tests against Facebook's servers:
158
-
176
+
159
177
  # Again from anywhere in the project directory:
160
178
  LIVE=true bundle exec rake spec
179
+ # you can also test against Facebook's beta tier
180
+ LIVE=true BETA=true bundle exec rake spec
161
181
 
162
- 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.)
182
+ By default, the live tests are run against test users, so you can run them as frequently as you want. If you want to run them against a real user, however, you can fill in the OAuth token, code, and access\_token values in spec/fixtures/facebook_data.yml. See the wiki for more details.
@@ -44,7 +44,7 @@ describe "Koala::Facebook::API" do
44
44
 
45
45
  Koala.stub(:make_request).and_return(response)
46
46
 
47
- @service.api('anything', 'get', {}, :http_component => http_component)
47
+ @service.api('anything', {}, 'get', :http_component => http_component)
48
48
  end
49
49
 
50
50
  it "should return the body of the request as JSON if no http_component is given" do
@@ -98,4 +98,29 @@ describe "Koala::Facebook::API" do
98
98
  end
99
99
  end
100
100
 
101
- end
101
+ describe "with an access token" do
102
+ before(:each) do
103
+ @api = Koala::Facebook::API.new(@token)
104
+ end
105
+
106
+ it_should_behave_like "Koala RestAPI"
107
+ it_should_behave_like "Koala RestAPI with an access token"
108
+
109
+ it_should_behave_like "Koala GraphAPI"
110
+ it_should_behave_like "Koala GraphAPI with an access token"
111
+ it_should_behave_like "Koala GraphAPI with GraphCollection"
112
+ end
113
+
114
+ describe "without an access token" do
115
+ before(:each) do
116
+ @api = Koala::Facebook::API.new
117
+ end
118
+
119
+ it_should_behave_like "Koala RestAPI"
120
+ it_should_behave_like "Koala RestAPI without an access token"
121
+
122
+ it_should_behave_like "Koala GraphAPI"
123
+ it_should_behave_like "Koala GraphAPI without an access token"
124
+ it_should_behave_like "Koala GraphAPI with GraphCollection"
125
+ end
126
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Koala::Facebook::APIError do
4
+ it "is a StandardError" do
5
+ Koala::Facebook::APIError.new.should be_a(StandardError)
6
+ end
7
+
8
+ it "has an accessor for fb_error_type" do
9
+ Koala::Facebook::APIError.instance_methods.map(&:to_sym).should include(:fb_error_type)
10
+ Koala::Facebook::APIError.instance_methods.map(&:to_sym).should include(:fb_error_type=)
11
+ end
12
+
13
+ it "sets fb_error_type to details['type']" do
14
+ type = "foo"
15
+ Koala::Facebook::APIError.new("type" => type).fb_error_type.should == type
16
+ end
17
+
18
+ it "sets the error message details['type']: details['message']" do
19
+ type = "foo"
20
+ message = "bar"
21
+ error = Koala::Facebook::APIError.new("type" => type, "message" => message)
22
+ error.message.should =~ /#{type}/
23
+ error.message.should =~ /#{message}/
24
+ end
25
+ end
26
+
27
+ describe Koala::KoalaError do
28
+ it "is a StandardError" do
29
+ Koala::KoalaError.new.should be_a(StandardError)
30
+ end
31
+ end
32
+
@@ -1,31 +1,22 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "Koala::Facebook::GraphAndRestAPI" do
4
- include LiveTestingDataHelper
5
-
6
- describe "with an access token" do
7
- before(:each) do
8
- @api = Koala::Facebook::GraphAndRestAPI.new(@token)
4
+ describe "class consolidation" do
5
+ before :each do
6
+ Koala::Utils.stub(:deprecate) # avoid actual messages to stderr
9
7
  end
10
8
 
11
- it_should_behave_like "Koala RestAPI"
12
- it_should_behave_like "Koala RestAPI with an access token"
13
-
14
- it_should_behave_like "Koala GraphAPI"
15
- it_should_behave_like "Koala GraphAPI with an access token"
16
- it_should_behave_like "Koala GraphAPI with GraphCollection"
17
- end
18
-
19
- describe "without an access token" do
20
- before(:each) do
21
- @api = Koala::Facebook::GraphAndRestAPI.new
9
+ it "still allows you to instantiate a GraphAndRestAPI object" do
10
+ api = Koala::Facebook::GraphAndRestAPI.new("token").should be_a(Koala::Facebook::GraphAndRestAPI)
22
11
  end
23
12
 
24
- it_should_behave_like "Koala RestAPI"
25
- it_should_behave_like "Koala RestAPI without an access token"
13
+ it "ultimately creates an API object" do
14
+ api = Koala::Facebook::GraphAndRestAPI.new("token").should be_a(Koala::Facebook::API)
15
+ end
26
16
 
27
- it_should_behave_like "Koala GraphAPI"
28
- it_should_behave_like "Koala GraphAPI without an access token"
29
- it_should_behave_like "Koala GraphAPI with GraphCollection"
17
+ it "fires a depreciation warning" do
18
+ Koala::Utils.should_receive(:deprecate)
19
+ api = Koala::Facebook::GraphAndRestAPI.new("token")
20
+ end
30
21
  end
31
22
  end