rest-graph 1.7.0 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.gitignore +6 -0
  2. data/CHANGES +44 -0
  3. data/CONTRIBUTORS +1 -0
  4. data/README +221 -191
  5. data/README.md +367 -0
  6. data/Rakefile +28 -43
  7. data/TODO +1 -0
  8. data/doc/ToC.md +10 -0
  9. data/doc/dependency.md +78 -0
  10. data/doc/design.md +206 -0
  11. data/doc/rails.md +12 -0
  12. data/doc/test.md +46 -0
  13. data/doc/tutorial.md +142 -0
  14. data/example/rails2/Gemfile +13 -0
  15. data/example/rails2/app/controllers/application_controller.rb +10 -8
  16. data/example/rails2/app/views/application/helper.html.erb +1 -0
  17. data/example/rails2/config/boot.rb +16 -0
  18. data/example/rails2/config/environment.rb +3 -30
  19. data/example/rails2/config/preinitializer.rb +23 -0
  20. data/example/rails2/test/functional/application_controller_test.rb +72 -32
  21. data/example/rails2/test/test_helper.rb +10 -6
  22. data/example/rails3/Gemfile +13 -0
  23. data/example/rails3/Rakefile +7 -0
  24. data/example/rails3/app/controllers/application_controller.rb +118 -0
  25. data/example/rails3/app/views/application/helper.html.erb +1 -0
  26. data/example/rails3/config.ru +4 -0
  27. data/example/rails3/config/application.rb +23 -0
  28. data/example/rails3/config/environment.rb +5 -0
  29. data/example/rails3/config/environments/development.rb +26 -0
  30. data/example/rails3/config/environments/production.rb +49 -0
  31. data/example/rails3/config/environments/test.rb +30 -0
  32. data/example/rails3/config/initializers/secret_token.rb +7 -0
  33. data/example/rails3/config/initializers/session_store.rb +8 -0
  34. data/example/rails3/config/rest-graph.yaml +11 -0
  35. data/example/rails3/config/routes.rb +5 -0
  36. data/example/rails3/test/functional/application_controller_test.rb +183 -0
  37. data/example/rails3/test/test_helper.rb +18 -0
  38. data/example/rails3/test/unit/rails_util_test.rb +44 -0
  39. data/init.rb +1 -1
  40. data/lib/rest-graph.rb +5 -571
  41. data/lib/rest-graph/auto_load.rb +3 -3
  42. data/lib/rest-graph/autoload.rb +3 -3
  43. data/lib/rest-graph/config_util.rb +43 -0
  44. data/lib/rest-graph/core.rb +608 -0
  45. data/lib/rest-graph/facebook_util.rb +74 -0
  46. data/lib/rest-graph/rails_util.rb +85 -37
  47. data/lib/rest-graph/test_util.rb +18 -2
  48. data/lib/rest-graph/version.rb +2 -2
  49. data/rest-graph.gemspec +42 -47
  50. data/task/gemgem.rb +155 -0
  51. data/test/test_api.rb +16 -0
  52. data/test/test_cache.rb +28 -8
  53. data/test/test_error.rb +9 -0
  54. data/test/test_facebook.rb +36 -0
  55. data/test/test_load_config.rb +16 -14
  56. data/test/test_misc.rb +4 -4
  57. data/test/test_parse.rb +10 -4
  58. metadata +146 -186
  59. data/Gemfile.lock +0 -45
  60. data/README.rdoc +0 -337
  61. data/example/rails2/script/console +0 -3
  62. data/example/rails2/script/server +0 -3
  63. data/lib/rest-graph/load_config.rb +0 -41
data/README.md ADDED
@@ -0,0 +1,367 @@
1
+ # rest-graph
2
+ by Cardinal Blue <http://cardinalblue.com>
3
+
4
+ Tutorial on setting up a sample Facebook application with Rails 3
5
+ and RestGraph could be found on [samplergthree][]. Instead, if you're
6
+ an experienced Ruby programmer, you might also want to look at
7
+ [detailed documents][].
8
+
9
+ [samplergthree]: https://github.com/cardinalblue/samplergthree
10
+ [detailed documents]: https://github.com/cardinalblue/rest-graph/blob/master/doc/ToC.md
11
+
12
+ ## LINKS:
13
+
14
+ * [github](http://github.com/cardinalblue/rest-graph)
15
+ * [rubygems](http://rubygems.org/gems/rest-graph)
16
+ * [rdoc](http://rdoc.info/projects/cardinalblue/rest-graph)
17
+ * [mailing list](http://groups.google.com/group/rest-graph/topics)
18
+
19
+ ## DESCRIPTION:
20
+
21
+ A lightweight Facebook Graph API client
22
+
23
+ ## FEATURES:
24
+
25
+ * Simple Graph API call
26
+ * Simple FQL call
27
+ * Utility to extract access_token and check sig in cookies/signed_request
28
+
29
+ ## REQUIREMENTS:
30
+
31
+ * Tested with MRI 1.8.7 and 1.9.2 and Rubinius 1.2.2.
32
+ Because of development gems can't work well on JRuby,
33
+ let me know if rest-graph is working on JRuby, thanks!
34
+
35
+ * (must) pick one HTTP client:
36
+ - gem install rest-client
37
+ - gem install em-http-request
38
+
39
+ * (optional) pick one JSON parser/generator:
40
+ - gem install yajl-ruby
41
+ - gem install json
42
+ - gem install json_pure
43
+
44
+ * (optional) parse access_token in HTTP_COOKIE
45
+ - gem install rack
46
+
47
+ * (optional) to use rest-graph/test_util
48
+ - gem install rr
49
+
50
+ ## INSTALLATION:
51
+
52
+ gem install rest-graph
53
+
54
+ Or if you want development version, put this in Gemfile:
55
+
56
+ gem 'rest-graph', :git => 'git://github.com/cardinalblue/rest-graph.git
57
+
58
+ Or as a Rails2 plugin:
59
+
60
+ ./script/plugin install git://github.com/cardinalblue/rest-graph.git
61
+
62
+ ## QUICK START:
63
+
64
+ require 'rest-graph'
65
+ rg = RestGraph.new(:access_token => 'myaccesstokenfromfb')
66
+ rg.get('me')
67
+ rg.get('me/likes')
68
+ rg.get('search', :q => 'taiwan')
69
+
70
+ ### Obtaining an access token
71
+
72
+ If you are using Rails, we recommend that you include a module called
73
+ RestGraph::RailsUtil into your controllers. (Your code contributions
74
+ for other Ruby frameworks would be appreciated!). RestGraph::RailsUtil
75
+ adds the following two methods to your controllers:
76
+
77
+ rest_graph_setup: Attempts to find an access_token from the environment
78
+ and initializes a RestGraph object with it.
79
+ Most commonly used inside a filter.
80
+
81
+ rest_graph: Accesses the RestGraph object by rest_graph_setup.
82
+
83
+ ### Example usage:
84
+
85
+ class MyController < ActionController::Base
86
+ include RestGraph::RailsUtil
87
+ before_filter :setup
88
+
89
+ def myaction
90
+ @medata = rest_graph.get('me')
91
+ end
92
+
93
+ private
94
+ def setup
95
+ rest_graph_setup(:app_id => '123',
96
+ :canvas => 'mycanvas',
97
+ :auto_authorize_scope => 'email')
98
+ # See below for more options
99
+ end
100
+ end
101
+
102
+ ### Default setup
103
+
104
+ New RestGraph objects can read their default setup configuration from a
105
+ YAML configuration file. Which is the same as passing to rest_graph_setup.
106
+
107
+ * [Example](test/config/rest-graph.yaml)
108
+
109
+ To enable, just require anywhere:
110
+
111
+ require 'rest-graph'
112
+
113
+ Or if you're using bundler, add this line into Gemfile:
114
+
115
+ gem 'rest-graph'
116
+
117
+ ## SETUP OPTIONS:
118
+
119
+ Here are ALL the available options for new instance of RestGraph.
120
+
121
+ rg = RestGraph.new(
122
+ :access_token => TOKEN , # default nil
123
+ :graph_server => 'https://graph.facebook.com/', # this is default
124
+ :old_server => 'https://api.facebook.com/' , # this is default
125
+ :accept => 'text/javascript' , # this is default
126
+ :lang => 'en-us' , # affect search
127
+ :auto_decode => true , # decode by json
128
+ # default true
129
+ :app_id => '123' , # default nil
130
+ :secret => '1829' , # default nil
131
+
132
+ :cache => {} ,
133
+ # A cache for the same API call. Any object quacks like a hash
134
+ # should work, and Rails.cache works, too. (because of a patch in
135
+ # RailsUtil)
136
+
137
+ :error_handler => lambda{|hash| raise RestGraph::Error.new(hash)},
138
+ # This handler callback is only called if auto_decode is
139
+ # set to true, otherwise, it's ignored. And raising exception
140
+ # is the default unless you're using RailsUtil and enabled
141
+ # auto_authorize. That way, RailsUtil would do redirect
142
+ # instead of raising an exception.
143
+
144
+ :log_method => method(:puts),
145
+ # This way, any log message would be output by puts. If you want to
146
+ # change the log format, use log_handler instead. See below:
147
+
148
+ :log_handler => lambda{ |event|
149
+ Rails.logger.
150
+ debug("Spent #{event.duration} requesting #{event.url}")})
151
+ # You might not want to touch this if you're using RailsUtil.
152
+ # Otherwise, the default behavior is do nothing. (i.e. no logging)
153
+
154
+ And here are ALL the available options for rest_graph_setup. Note that all
155
+ options for RestGraph instance are also valid options for rest_graph_setup.
156
+
157
+ rest_graph_setup(#
158
+ # == All the above RestGraph options, plus
159
+ #
160
+ :canvas => 'mycanvas', # default ''
161
+ :auto_authorize => true , # default false
162
+ :auto_authorize_scope => 'email' , # default ''
163
+ :auto_authorize_options => {} , # default {}
164
+ # auto_authorize means it will do redirect to oauth
165
+ # API automatically if the access_token is invalid or
166
+ # missing. So you would like to setup scope if you're
167
+ # using it. Note that: setting scope implies setting
168
+ # auto_authorize to true, even it's false.
169
+
170
+ :ensure_authorized => false , # default false
171
+ # This means if the access_token is not there,
172
+ # then do auto_authorize.
173
+
174
+ :write_session => true , # default false
175
+ :write_cookies => false , # default false
176
+ :write_handler =>
177
+ lambda{ |fbs| @cache[uid] = fbs } , # default nil
178
+ :check_handler =>
179
+ lambda{ @cache[uid] }) # default nil
180
+ # If we're not using Facebook JavaScript SDK,
181
+ # then we'll need to find a way to store the fbs,
182
+ # which contains access_token and/or user id. In a
183
+ # standalone site or iframe canvas application, you might
184
+ # want to just use the Rails (or other framework) session
185
+
186
+ ### Alternate ways to setup RestGraph:
187
+
188
+ 1. Set upon RestGraph object creation:
189
+
190
+ rg = RestGraph.new :app_id => 1234
191
+
192
+ 2. Set via the rest_graph_setup call in a Controller:
193
+
194
+ rest_graph_setup :app_id => 1234
195
+
196
+ 3. Load from a YAML file
197
+
198
+ require 'rest-graph/config_util'
199
+ RestGraph.load_config('path/to/rest-graph.yaml', 'production')
200
+ rg = RestGraph.new
201
+
202
+ 4. Load config automatically
203
+
204
+ require 'rest-graph' # under Rails, would load config/rest-graph.yaml
205
+ rg = RestGraph.new
206
+
207
+ 5. Override directly
208
+
209
+ module MyDefaults
210
+ def default_app_id
211
+ '456'
212
+ end
213
+
214
+ def default_secret
215
+ 'category theory'
216
+ end
217
+ end
218
+ RestGraph.send(:extend, MyDefaults)
219
+ rg = RestGraph.new
220
+
221
+ ## API REFERENCE:
222
+
223
+ ### Facebook Graph API:
224
+
225
+ #### get
226
+ # GET https://graph.facebook.com/me?access_token=TOKEN
227
+ rg.get('me')
228
+
229
+ # GET https://graph.facebook.com/me?metadata=1&access_token=TOKEN
230
+ rg.get('me', :metadata => '1')
231
+
232
+ # extra options:
233
+ # auto_decode: Bool # decode with json or not in this method call
234
+ # # default: auto_decode in rest-graph instance
235
+ # secret: Bool # use secret_acccess_token or not
236
+ # # default: false
237
+ # cache: Bool # use cache or not; if it's false, update cache, too
238
+ # # default: true
239
+ # expires_in: Int # control when would the cache be expired
240
+ # # default: nothing
241
+ # async: Bool # use eventmachine for http client or not
242
+ # # default: false, but true in aget family
243
+ rg.get('me', {:metadata => '1'}, :secret => true, expires_in => 600)
244
+
245
+ #### post
246
+
247
+ rg.post('me/feed', :message => 'bread!')
248
+
249
+ #### fql
250
+
251
+ Make an arbitrary [FQL][] query
252
+
253
+ [FQL]: http://developers.facebook.com/docs/reference/fql/
254
+
255
+ rg.fql('SELECT name FROM page WHERE page_id="123"')
256
+
257
+ #### fql_multi
258
+
259
+ rg.fql_multi(:q1 => 'SELECT name FROM page WHERE page_id="123"',
260
+ :q2 => 'SELECT name FROM page WHERE page_id="456"')
261
+
262
+ #### old_rest
263
+
264
+ Call functionality from Facebook's old REST API:
265
+
266
+ rg.old_rest(
267
+ 'stream.publish',
268
+ { :message => 'Greetings',
269
+ :attachment => {:name => 'Wikipedia',
270
+ :href => 'http://wikipedia.org/',
271
+ :caption => 'Wikipedia says hi.',
272
+ :media => [{:type => 'image',
273
+ :src => 'http://wikipedia.org/logo.png',
274
+ :href => 'http://wikipedia.org/'}]
275
+ }.to_json,
276
+ :action_links => [{:text => 'Go to Wikipedia',
277
+ :href => 'http://wikipedia.org/'}
278
+ ].to_json
279
+ },
280
+ :auto_decode => false) # You'll need to set auto_decode to false for
281
+ # this API request if Facebook is not returning
282
+ # a proper formatted JSON response. Otherwise,
283
+ # this could be omitted.
284
+
285
+ # Some Old Rest API requires a special access token with app secret
286
+ # inside of it. For those methods, use secret_old_rest instead of the
287
+ # usual old_rest with common access token.
288
+ rg.secret_old_rest('admin.getAppProperties', :properties => 'app_id')
289
+
290
+ ### Utility Methods:
291
+
292
+ #### parse_???
293
+
294
+ All the methods that obtain an access_token will automatically save it.
295
+
296
+ If you have the session in the cookies,
297
+ then RestGraph can parse the cookies:
298
+
299
+ rg.parse_cookies!(cookies)
300
+
301
+ If you're writing a Rack application, you might want to parse
302
+ the session directly from Rack env:
303
+
304
+ rg.parse_rack_env!(env)
305
+
306
+ #### access_token
307
+
308
+ rg.access_token
309
+
310
+ Data associated with the access_token (which might or might not
311
+ available, depending on how the access_token was obtained).
312
+
313
+ rg.data
314
+ rg.data['uid']
315
+ rg.data['expires']
316
+
317
+ #### Default values
318
+
319
+ Read from the rest-graph.yaml file.
320
+
321
+ RestGraph.default_???
322
+
323
+ ### Other ways of getting an access token
324
+
325
+ #### authorize_url
326
+
327
+ Returns the redirect URL for authorizing
328
+
329
+ # https://graph.facebook.com/oauth/authorize?
330
+ # client_id=123&redirect_uri=http%3A%2F%2Fw3.org%2F
331
+ rg.authorize_url(:redirect_uri => 'http://w3.org/', :scope => 'email')
332
+
333
+ #### authorize!
334
+
335
+ Makes a call to Facebook to convert
336
+ the authorization "code" into an access token:
337
+
338
+ # https://graph.facebook.com/oauth/access_token?
339
+ # code=CODE&client_id=123&client_secret=1829&
340
+ # redirect_uri=http%3A%2F%2Fw3.org%2F
341
+ rg.authorize!(:redirect_uri => 'http://w3.org/', :code => 'CODE')
342
+
343
+ #### exchange_sessions
344
+
345
+ Takes a session key from the old REST API
346
+ (non-Graph API) and converts to an access token:
347
+
348
+ # https://graph.facebook.com/oauth/exchange_sessions?sessions=SESSION
349
+ rg.exchange_sessions(:sessions => params[:fb_sig_session_key])
350
+
351
+ ## LICENSE:
352
+
353
+ Apache License 2.0
354
+
355
+ Copyright (c) 2010, Cardinal Blue
356
+
357
+ Licensed under the Apache License, Version 2.0 (the "License");
358
+ you may not use this file except in compliance with the License.
359
+ You may obtain a copy of the License at
360
+
361
+ <http://www.apache.org/licenses/LICENSE-2.0>
362
+
363
+ Unless required by applicable law or agreed to in writing, software
364
+ distributed under the License is distributed on an "AS IS" BASIS,
365
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
366
+ See the License for the specific language governing permissions and
367
+ limitations under the License.
data/Rakefile CHANGED
@@ -1,57 +1,42 @@
1
1
  # encoding: utf-8
2
2
 
3
- begin
4
- require 'bones'
5
- rescue LoadError
6
- abort '### Please install the "bones" gem ###'
7
- end
8
-
9
- ensure_in_path 'lib'
10
- proj = 'rest-graph'
11
- require "#{proj}/version"
12
-
13
- Bones{
14
- ruby_opts [''] # silence warning for now
15
-
16
- version RestGraph::VERSION
17
-
18
- depend_on 'rest-client' , :development => true
19
- depend_on 'em-http-request', :development => true
3
+ require "#{dir = File.dirname(__FILE__)}/task/gemgem"
4
+ Gemgem.dir = dir
20
5
 
21
- depend_on 'rack' , :development => true
6
+ ($LOAD_PATH << File.expand_path("#{Gemgem.dir}/lib" )).uniq!
22
7
 
23
- depend_on 'yajl-ruby', :development => true
24
- depend_on 'json' , :development => true
25
- depend_on 'json_pure', :development => true
8
+ desc 'Generate gemspec'
9
+ task 'gem:spec' do
10
+ Gemgem.spec = Gemgem.create do |s|
11
+ require 'rest-graph/version'
12
+ s.name = 'rest-graph'
13
+ s.version = RestGraph::VERSION
14
+ # s.executables = [s.name]
26
15
 
27
- depend_on 'ruby-hmac', :development => true
16
+ %w[].each{ |g| s.add_runtime_dependency(g) }
17
+ %w[rest-client em-http-request rack yajl-ruby json json_pure ruby-hmac
18
+ webmock bacon rr].each{ |g| s.add_development_dependency(g) }
28
19
 
29
- depend_on 'rr' , :development => true
30
- depend_on 'webmock' , :development => true
31
- depend_on 'bacon' , :development => true
20
+ s.authors = ['Cardinal Blue', 'Lin Jen-Shin (godfat)']
21
+ s.email = ['dev (XD) cardinalblue.com']
22
+ end
32
23
 
33
- name proj
34
- url "http://github.com/cardinalblue/#{proj}"
35
- authors ['Cardinal Blue', 'Lin Jen-Shin (aka godfat 真常)']
36
- email 'dev (XD) cardinalblue.com'
37
-
38
- history_file 'CHANGES'
39
- readme_file 'README.rdoc'
40
- ignore_file '.gitignore'
41
- rdoc.include ['\w+']
42
- rdoc.exclude ['test', 'doc', 'Rakefile', 'example']
43
- }
44
-
45
- CLEAN.include Dir['**/*.rbc']
46
-
47
- task :default do
48
- Rake.application.options.show_task_pattern = /./
49
- Rake.application.display_tasks_and_comments
24
+ Gemgem.write
50
25
  end
51
26
 
52
27
  desc 'Run example tests'
53
28
  task 'test:example' => ['gem:install'] do
54
- sh "cd example/rails2; #{Gem.ruby} -S rake test"
29
+ %w[rails3 rails2].each{ |framework|
30
+ opts = Rake.application.options
31
+ args = (opts.singleton_methods - [:rakelib, 'rakelib']).map{ |arg|
32
+ if arg.to_s !~ /=$/ && opts.send(arg)
33
+ "--#{arg}"
34
+ else
35
+ ''
36
+ end
37
+ }.join(' ')
38
+ sh "cd example/#{framework}; #{Gem.ruby} -S rake test #{args}"
39
+ }
55
40
  end
56
41
 
57
42
  desc 'Run all tests'