rest-graph 1.4.0 → 1.4.1
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.
- data/CHANGES +21 -1
- data/Gemfile +12 -0
- data/Gemfile.lock +49 -0
- data/README +5 -4
- data/README.rdoc +5 -4
- data/example/rails/app/controllers/application_controller.rb +15 -2
- data/example/rails/config/environments/test.rb +2 -0
- data/example/rails/test/functional/application_controller_test.rb +9 -0
- data/lib/rest-graph.rb +67 -18
- data/lib/rest-graph/rails_util.rb +74 -46
- data/lib/rest-graph/version.rb +1 -1
- data/rest-graph.gemspec +7 -7
- data/test/config/rest-graph.yaml +1 -0
- data/test/test_handler.rb +63 -31
- data/test/test_oauth.rb +4 -1
- data/test/test_old.rb +1 -4
- data/test/test_parse.rb +19 -0
- data/test/test_rest-graph.rb +21 -4
- metadata +11 -8
- data/lib/rest-graph/facebook_util.rb +0 -27
data/CHANGES
CHANGED
@@ -1,6 +1,26 @@
|
|
1
1
|
= rest-graph changes history
|
2
2
|
|
3
|
-
== rest-graph 1.4.
|
3
|
+
== rest-graph 1.4.1 -- 2010-08-04
|
4
|
+
|
5
|
+
* [RestGraph] Call error_handler when response contains error_code as well,
|
6
|
+
which came from FQL response. Thanks Florent.
|
7
|
+
|
8
|
+
* [RestGraph] Added RestGraph#parse_signed_request!
|
9
|
+
|
10
|
+
* [RestGraph] Added RestGraph#url to generate desired API request URL,
|
11
|
+
in case you'll want to use different HTTP client, such as em-http-request,
|
12
|
+
or pass the API request to different process of data fetcher.
|
13
|
+
|
14
|
+
* [RestGraph] Added an :cache option that allow you to pass a cache
|
15
|
+
object, which should respond to [] and []= for reading and writing.
|
16
|
+
The cache key would be MD5 hexdigest from the URL being called.
|
17
|
+
pass :cache => Rails.cache to rest_graph_setup when using RailsUtil.
|
18
|
+
|
19
|
+
* [RailsUtil] Pass :cache => Rails.cache to rest_graph_setup to enable caching.
|
20
|
+
* [RailsUtil] Favor signed_request over session in rest_graph_setup
|
21
|
+
* [RailsUtil] Now it's possible to setup all options in rest-graph.yaml.
|
22
|
+
|
23
|
+
== rest-graph 1.4.0 -- 2010-07-15
|
4
24
|
|
5
25
|
Changes only for RailsUtil, the core (rest-graph.rb) is pretty stable for now.
|
6
26
|
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
---
|
2
|
+
hash: 1abfe240bd774ad21e7a187351da9cabacb74d58
|
3
|
+
sources:
|
4
|
+
- Rubygems:
|
5
|
+
uri: http://rubygems.org
|
6
|
+
specs:
|
7
|
+
- addressable:
|
8
|
+
version: 2.1.2
|
9
|
+
- bacon:
|
10
|
+
version: 1.1.0
|
11
|
+
- crack:
|
12
|
+
version: 0.1.8
|
13
|
+
- mime-types:
|
14
|
+
version: "1.16"
|
15
|
+
- rack:
|
16
|
+
version: 1.2.1
|
17
|
+
- rest-client:
|
18
|
+
version: 1.6.0
|
19
|
+
- rr:
|
20
|
+
version: 0.10.11
|
21
|
+
- webmock:
|
22
|
+
version: 1.3.2
|
23
|
+
- yajl-ruby:
|
24
|
+
version: 0.7.7
|
25
|
+
dependencies:
|
26
|
+
rest-client:
|
27
|
+
version: ">= 0"
|
28
|
+
group:
|
29
|
+
- :default
|
30
|
+
yajl-ruby:
|
31
|
+
version: ">= 0"
|
32
|
+
group:
|
33
|
+
- :test
|
34
|
+
rack:
|
35
|
+
version: ">= 0"
|
36
|
+
group:
|
37
|
+
- :test
|
38
|
+
rr:
|
39
|
+
version: ">= 0"
|
40
|
+
group:
|
41
|
+
- :test
|
42
|
+
webmock:
|
43
|
+
version: ">= 0"
|
44
|
+
group:
|
45
|
+
- :test
|
46
|
+
bacon:
|
47
|
+
version: ">= 0"
|
48
|
+
group:
|
49
|
+
- :test
|
data/README
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= rest-graph 1.
|
1
|
+
= rest-graph 1.4.1
|
2
2
|
by Cardinal Blue ( http://cardinalblue.com )
|
3
3
|
|
4
4
|
== LINKS:
|
@@ -98,6 +98,7 @@ by Cardinal Blue ( http://cardinalblue.com )
|
|
98
98
|
:auto_decode => true , # decode by json
|
99
99
|
:app_id => '123' ,
|
100
100
|
:secret => '1829' ,
|
101
|
+
:cache => {} , # a cache for the same API call
|
101
102
|
|
102
103
|
# This handler callback is only called if auto_decode is set to true,
|
103
104
|
# otherwise, it's ignored.
|
@@ -215,13 +216,13 @@ by Cardinal Blue ( http://cardinalblue.com )
|
|
215
216
|
# or (3) Load config automatically
|
216
217
|
require 'rest-graph/auto_load' # under Rails, load config/rest-graph.yaml
|
217
218
|
|
218
|
-
# Please read:
|
219
|
+
# Please read: for an example of config file.
|
220
|
+
# Note that :auto_authorize_scope and friends is only for RailsUtil.
|
219
221
|
{rest-graph.yaml}[http://github.com/cardinalblue/rest-graph/blob/master/test/config/rest-graph.yaml]
|
220
|
-
# for an example of config file.
|
221
222
|
|
222
223
|
== REQUIREMENTS:
|
223
224
|
|
224
|
-
* Tested with MRI 1.8.7 and 1.9.1
|
225
|
+
* Tested with MRI 1.8.7 and 1.9.1 and Rubinius HEAD
|
225
226
|
* gem install rest-client
|
226
227
|
* gem install json (optional)
|
227
228
|
* gem install json_pure (optional)
|
data/README.rdoc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= rest-graph 1.
|
1
|
+
= rest-graph 1.4.1
|
2
2
|
by Cardinal Blue ( http://cardinalblue.com )
|
3
3
|
|
4
4
|
== LINKS:
|
@@ -98,6 +98,7 @@ by Cardinal Blue ( http://cardinalblue.com )
|
|
98
98
|
:auto_decode => true , # decode by json
|
99
99
|
:app_id => '123' ,
|
100
100
|
:secret => '1829' ,
|
101
|
+
:cache => {} , # a cache for the same API call
|
101
102
|
|
102
103
|
# This handler callback is only called if auto_decode is set to true,
|
103
104
|
# otherwise, it's ignored.
|
@@ -215,13 +216,13 @@ by Cardinal Blue ( http://cardinalblue.com )
|
|
215
216
|
# or (3) Load config automatically
|
216
217
|
require 'rest-graph/auto_load' # under Rails, load config/rest-graph.yaml
|
217
218
|
|
218
|
-
# Please read:
|
219
|
+
# Please read: for an example of config file.
|
220
|
+
# Note that :auto_authorize_scope and friends is only for RailsUtil.
|
219
221
|
{rest-graph.yaml}[http://github.com/cardinalblue/rest-graph/blob/master/test/config/rest-graph.yaml]
|
220
|
-
# for an example of config file.
|
221
222
|
|
222
223
|
== REQUIREMENTS:
|
223
224
|
|
224
|
-
* Tested with MRI 1.8.7 and 1.9.1
|
225
|
+
* Tested with MRI 1.8.7 and 1.9.1 and Rubinius HEAD
|
225
226
|
* gem install rest-client
|
226
227
|
* gem install json (optional)
|
227
228
|
* gem install json_pure (optional)
|
@@ -16,6 +16,7 @@ class ApplicationController < ActionController::Base
|
|
16
16
|
before_filter :filter_no_auto, :only => [:no_auto]
|
17
17
|
before_filter :filter_diff_app_id, :only => [:diff_app_id]
|
18
18
|
before_filter :filter_diff_canvas, :only => [:diff_canvas]
|
19
|
+
before_filter :filter_cache, :only => [:cache]
|
19
20
|
|
20
21
|
def index
|
21
22
|
render :text => rest_graph.get('me').to_json
|
@@ -34,9 +35,16 @@ class ApplicationController < ActionController::Base
|
|
34
35
|
render :text => rest_graph.app_id
|
35
36
|
end
|
36
37
|
|
38
|
+
def cache
|
39
|
+
url = rest_graph.url('cache')
|
40
|
+
rest_graph.get('cache')
|
41
|
+
rest_graph.get('cache')
|
42
|
+
render :text => Rails.cache.read(Digest::MD5.hexdigest(url))
|
43
|
+
end
|
44
|
+
|
37
45
|
private
|
38
46
|
def filter_common
|
39
|
-
rest_graph_setup(:auto_authorize => true)
|
47
|
+
rest_graph_setup(:auto_authorize => true, :canvas => '')
|
40
48
|
end
|
41
49
|
|
42
50
|
def filter_canvas
|
@@ -59,6 +67,11 @@ class ApplicationController < ActionController::Base
|
|
59
67
|
end
|
60
68
|
|
61
69
|
def filter_options
|
62
|
-
rest_graph_setup(:auto_authorize_options => {:scope => 'bogus'}
|
70
|
+
rest_graph_setup(:auto_authorize_options => {:scope => 'bogus'},
|
71
|
+
:canvas => nil)
|
72
|
+
end
|
73
|
+
|
74
|
+
def filter_cache
|
75
|
+
rest_graph_setup(:cache => Rails.cache)
|
63
76
|
end
|
64
77
|
end
|
@@ -26,3 +26,5 @@ config.action_mailer.delivery_method = :test
|
|
26
26
|
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
27
27
|
# like if you have constraints or database-specific column types
|
28
28
|
# config.active_record.schema_format = :sql
|
29
|
+
|
30
|
+
config.logger = Logger.new($stdout, :debug)
|
@@ -71,4 +71,13 @@ class ApplicationControllerTest < ActionController::TestCase
|
|
71
71
|
assert_response :success
|
72
72
|
assert_equal 'zzz', @response.body
|
73
73
|
end
|
74
|
+
|
75
|
+
def test_cache
|
76
|
+
stub_request(:get, 'https://graph.facebook.com/cache').
|
77
|
+
to_return(:body => '{"message":"ok"}')
|
78
|
+
|
79
|
+
get(:cache)
|
80
|
+
assert_response :success
|
81
|
+
assert_equal '{"message":"ok"}', @response.body
|
82
|
+
end
|
74
83
|
end
|
data/lib/rest-graph.rb
CHANGED
@@ -4,6 +4,8 @@ require 'rest_client'
|
|
4
4
|
|
5
5
|
# stdlib
|
6
6
|
require 'digest/md5'
|
7
|
+
require 'openssl'
|
8
|
+
|
7
9
|
require 'cgi'
|
8
10
|
|
9
11
|
# optional gem
|
@@ -21,15 +23,19 @@ rescue LoadError; end
|
|
21
23
|
}
|
22
24
|
|
23
25
|
# the data structure used in RestGraph
|
24
|
-
RestGraphStruct = Struct.new(:
|
26
|
+
RestGraphStruct = Struct.new(:auto_decode,
|
25
27
|
:graph_server, :old_server,
|
26
28
|
:accept, :lang,
|
27
29
|
:app_id, :secret,
|
30
|
+
:data, :cache,
|
28
31
|
:error_handler,
|
29
32
|
:log_handler) unless defined?(RestGraphStruct)
|
30
33
|
|
31
34
|
class RestGraph < RestGraphStruct
|
32
35
|
class Error < RuntimeError; end
|
36
|
+
class Event < Struct.new(:duration, :url); end
|
37
|
+
class Event::Requested < Event; end
|
38
|
+
class Event::CacheHit < Event; end
|
33
39
|
|
34
40
|
Attributes = RestGraphStruct.members.map(&:to_sym)
|
35
41
|
|
@@ -45,7 +51,6 @@ class RestGraph < RestGraphStruct
|
|
45
51
|
# setup defaults
|
46
52
|
module DefaultAttributes
|
47
53
|
extend self
|
48
|
-
def default_data ; {} ; end
|
49
54
|
def default_auto_decode ; true ; end
|
50
55
|
def default_graph_server; 'https://graph.facebook.com/'; end
|
51
56
|
def default_old_server ; 'https://api.facebook.com/' ; end
|
@@ -53,11 +58,13 @@ class RestGraph < RestGraphStruct
|
|
53
58
|
def default_lang ; 'en-us' ; end
|
54
59
|
def default_app_id ; nil ; end
|
55
60
|
def default_secret ; nil ; end
|
61
|
+
def default_data ; {} ; end
|
62
|
+
def default_cache ; nil ; end
|
56
63
|
def default_error_handler
|
57
64
|
lambda{ |error| raise ::RestGraph::Error.new(error) }
|
58
65
|
end
|
59
66
|
def default_log_handler
|
60
|
-
lambda{ |
|
67
|
+
lambda{ |event| }
|
61
68
|
end
|
62
69
|
end
|
63
70
|
extend DefaultAttributes
|
@@ -80,20 +87,24 @@ class RestGraph < RestGraphStruct
|
|
80
87
|
!!access_token
|
81
88
|
end
|
82
89
|
|
90
|
+
def url path, query={}, server=graph_server
|
91
|
+
"#{server}#{path}#{build_query_string(query)}"
|
92
|
+
end
|
93
|
+
|
83
94
|
def get path, query={}, opts={}
|
84
|
-
request(
|
95
|
+
request(:get , url(path, query, graph_server), opts)
|
85
96
|
end
|
86
97
|
|
87
98
|
def delete path, query={}, opts={}
|
88
|
-
request(
|
99
|
+
request(:delete, url(path, query, graph_server), opts)
|
89
100
|
end
|
90
101
|
|
91
102
|
def post path, payload, query={}, opts={}
|
92
|
-
request(
|
103
|
+
request(:post , url(path, query, graph_server), opts, payload)
|
93
104
|
end
|
94
105
|
|
95
106
|
def put path, payload, query={}, opts={}
|
96
|
-
request(
|
107
|
+
request(:put , url(path, query, graph_server), opts, payload)
|
97
108
|
end
|
98
109
|
|
99
110
|
# cookies, app_id, secrect related below
|
@@ -119,6 +130,18 @@ class RestGraph < RestGraphStruct
|
|
119
130
|
rescue JSON::ParserError
|
120
131
|
end
|
121
132
|
|
133
|
+
# facebook's new signed_request...
|
134
|
+
|
135
|
+
def parse_signed_request! request
|
136
|
+
sig_encoded, json_encoded = request.split('.')
|
137
|
+
sig, json = [sig_encoded, json_encoded].map{ |str|
|
138
|
+
"#{str.tr('-_', '+/')}==".unpack('m').first
|
139
|
+
}
|
140
|
+
self.data = JSON.parse(json) if
|
141
|
+
secret && OpenSSL::HMAC.digest('sha256', secret, json_encoded) == sig
|
142
|
+
rescue JSON::ParserError
|
143
|
+
end
|
144
|
+
|
122
145
|
# oauth related
|
123
146
|
|
124
147
|
def authorize_url opts={}
|
@@ -129,20 +152,23 @@ class RestGraph < RestGraphStruct
|
|
129
152
|
def authorize! opts={}
|
130
153
|
query = {:client_id => app_id, :client_secret => secret}.merge(opts)
|
131
154
|
self.data = Rack::Utils.parse_query(
|
132
|
-
|
155
|
+
request(:get, url('oauth/access_token', query),
|
156
|
+
:suppress_decode => true))
|
133
157
|
end
|
134
158
|
|
135
159
|
# old rest facebook api, i will definitely love to remove them someday
|
136
160
|
|
137
161
|
def old_rest path, query={}, opts={}
|
138
|
-
request(
|
139
|
-
|
162
|
+
request(
|
163
|
+
:get,
|
164
|
+
url("method/#{path}", {:format => 'json'}.merge(query), old_server),
|
165
|
+
opts)
|
140
166
|
end
|
141
167
|
|
142
168
|
def exchange_sessions opts={}
|
143
169
|
query = {:client_id => app_id, :client_secret => secret,
|
144
170
|
:type => 'client_cred'}.merge(opts)
|
145
|
-
request(
|
171
|
+
request(:post, url('oauth/exchange_sessions', query))
|
146
172
|
end
|
147
173
|
|
148
174
|
def fql code, query={}, opts={}
|
@@ -162,15 +188,14 @@ class RestGraph < RestGraphStruct
|
|
162
188
|
end
|
163
189
|
|
164
190
|
private
|
165
|
-
def request
|
191
|
+
def request meth, uri, opts={}, payload=nil
|
166
192
|
start_time = Time.now
|
167
|
-
|
168
|
-
|
169
|
-
res.send(method, *[payload, build_headers].compact), suppress_decode)
|
193
|
+
post_request(cache_get(uri) || fetch(meth, uri, payload),
|
194
|
+
opts[:suppress_decode])
|
170
195
|
rescue RestClient::Exception => e
|
171
|
-
post_request(e.http_body, suppress_decode)
|
196
|
+
post_request(e.http_body, opts[:suppress_decode])
|
172
197
|
ensure
|
173
|
-
log_handler.call(Time.now - start_time,
|
198
|
+
log_handler.call(Event::Requested.new(Time.now - start_time, uri))
|
174
199
|
end
|
175
200
|
|
176
201
|
def build_query_string query={}
|
@@ -200,7 +225,9 @@ class RestGraph < RestGraphStruct
|
|
200
225
|
end
|
201
226
|
|
202
227
|
def check_error hash
|
203
|
-
if error_handler && hash.kind_of?(Hash) &&
|
228
|
+
if error_handler && hash.kind_of?(Hash) &&
|
229
|
+
(hash['error'] || # from graph api
|
230
|
+
hash['error_code']) # from fql
|
204
231
|
error_handler.call(hash)
|
205
232
|
else
|
206
233
|
hash
|
@@ -213,4 +240,26 @@ class RestGraph < RestGraphStruct
|
|
213
240
|
|
214
241
|
Digest::MD5.hexdigest(args + secret)
|
215
242
|
end
|
243
|
+
|
244
|
+
def cache_key uri
|
245
|
+
Digest::MD5.hexdigest(uri)
|
246
|
+
end
|
247
|
+
|
248
|
+
def cache_get uri
|
249
|
+
return unless cache
|
250
|
+
start_time = Time.now
|
251
|
+
cache[cache_key(uri)].tap{ |result|
|
252
|
+
log_handler.call(Event::CacheHit.new(Time.now - start_time, uri)) if
|
253
|
+
result
|
254
|
+
}
|
255
|
+
end
|
256
|
+
|
257
|
+
def fetch meth, uri, payload
|
258
|
+
RestClient::Request.execute(:method => meth, :url => uri,
|
259
|
+
:headers => build_headers,
|
260
|
+
:payload => payload).
|
261
|
+
tap{ |result|
|
262
|
+
cache[cache_key(uri)] = result if cache
|
263
|
+
}
|
264
|
+
end
|
216
265
|
end
|
@@ -1,12 +1,23 @@
|
|
1
1
|
|
2
2
|
require 'rest-graph'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
''
|
4
|
+
class RestGraph
|
5
|
+
module DefaultAttributes
|
6
|
+
def default_canvas ; '' ; end
|
7
|
+
def default_auto_authorize ; false; end
|
8
|
+
def default_auto_authorize_options; {} ; end
|
9
|
+
def default_auto_authorize_scope ; '' ; end
|
10
|
+
def default_write_session ; false; end
|
11
|
+
end
|
12
|
+
|
13
|
+
module RailsCache
|
14
|
+
def [] key ; read(key) ; end
|
15
|
+
def []= key, value; write(key, value); end
|
7
16
|
end
|
8
17
|
end
|
9
18
|
|
19
|
+
::ActiveSupport::Cache::Store.send(:include, ::RestGraph::RailsCache)
|
20
|
+
|
10
21
|
module RestGraph::RailsUtil
|
11
22
|
module Helper
|
12
23
|
def rest_graph
|
@@ -21,30 +32,16 @@ module RestGraph::RailsUtil
|
|
21
32
|
controller.helper(::RestGraph::RailsUtil::Helper)
|
22
33
|
end
|
23
34
|
|
24
|
-
def rest_graph_options
|
25
|
-
@rest_graph_options ||=
|
26
|
-
{:canvas => '',
|
27
|
-
:auto_authorize => false,
|
28
|
-
:auto_authorize_options => {},
|
29
|
-
:auto_authorize_scope => '',
|
30
|
-
:write_session => false}
|
31
|
-
end
|
32
|
-
|
33
|
-
def rest_graph_options_new
|
34
|
-
@rest_graph_options_new ||=
|
35
|
-
{:error_handler => method(:rest_graph_authorize),
|
36
|
-
:log_handler => method(:rest_graph_log)}
|
37
|
-
end
|
38
|
-
|
39
35
|
def rest_graph_setup options={}
|
40
|
-
|
36
|
+
rest_graph_options_ctl.merge!(rest_graph_extract_options(options, :reject))
|
41
37
|
rest_graph_options_new.merge!(rest_graph_extract_options(options, :select))
|
42
38
|
|
43
39
|
rest_graph_check_cookie
|
40
|
+
rest_graph_check_params_signed_request
|
44
41
|
rest_graph_check_params_session
|
45
42
|
rest_graph_check_code
|
46
43
|
|
47
|
-
# there are above
|
44
|
+
# there are above 4 ways to check the user identity!
|
48
45
|
# if nor of them passed, then we can suppose the user
|
49
46
|
# didn't authorize for us, but we can check if user has authorized
|
50
47
|
# before, in that case, the fbs would be inside session,
|
@@ -64,8 +61,8 @@ module RestGraph::RailsUtil
|
|
64
61
|
if redirect || rest_graph_auto_authorize?
|
65
62
|
@rest_graph_authorize_url = rest_graph.authorize_url(
|
66
63
|
{:redirect_uri => rest_graph_normalized_request_uri,
|
67
|
-
:scope =>
|
68
|
-
merge(
|
64
|
+
:scope => rest_graph_oget(:auto_authorize_scope)}.
|
65
|
+
merge(rest_graph_oget(:auto_authorize_options)))
|
69
66
|
|
70
67
|
logger.debug("DEBUG: RestGraph: redirect to #{@rest_graph_authorize_url}")
|
71
68
|
|
@@ -79,7 +76,6 @@ module RestGraph::RailsUtil
|
|
79
76
|
def rest_graph_authorize_redirect
|
80
77
|
if !rest_graph_in_canvas?
|
81
78
|
redirect_to @rest_graph_authorize_url
|
82
|
-
|
83
79
|
else
|
84
80
|
render :inline => <<-HTML
|
85
81
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
@@ -104,7 +100,27 @@ module RestGraph::RailsUtil
|
|
104
100
|
|
105
101
|
module_function
|
106
102
|
|
107
|
-
# ====================
|
103
|
+
# ==================== options utility =======================
|
104
|
+
|
105
|
+
def rest_graph_oget key
|
106
|
+
if rest_graph_options_ctl.has_key?(key)
|
107
|
+
rest_graph_options_ctl[key]
|
108
|
+
else
|
109
|
+
RestGraph.send("default_#{key}")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def rest_graph_options_ctl
|
114
|
+
@rest_graph_options_ctl ||= {}
|
115
|
+
end
|
116
|
+
|
117
|
+
def rest_graph_options_new
|
118
|
+
@rest_graph_options_new ||=
|
119
|
+
{:error_handler => method(:rest_graph_authorize),
|
120
|
+
:log_handler => method(:rest_graph_log)}
|
121
|
+
end
|
122
|
+
|
123
|
+
# ==================== checking utility ======================
|
108
124
|
|
109
125
|
# if we're not in canvas nor code passed,
|
110
126
|
# we could check out cookies as well.
|
@@ -117,24 +133,37 @@ module RestGraph::RailsUtil
|
|
117
133
|
" #{rest_graph.data.inspect}")
|
118
134
|
end
|
119
135
|
|
136
|
+
def rest_graph_check_params_signed_request
|
137
|
+
return if rest_graph.authorized? || !params[:signed_request]
|
138
|
+
|
139
|
+
rest_graph.parse_signed_request!(params[:signed_request])
|
140
|
+
logger.debug("DEBUG: RestGraph: detected signed_request, parsed:" \
|
141
|
+
" #{rest_graph.data.inspect}")
|
142
|
+
|
143
|
+
if rest_graph.authorized?
|
144
|
+
rest_graph_write_session
|
145
|
+
else
|
146
|
+
logger.warn(
|
147
|
+
"WARN: RestGraph: bad signed_request: #{params[:signed_request]}")
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
120
151
|
# if the code is bad or not existed,
|
121
152
|
# check if there's one in session,
|
122
153
|
# meanwhile, there the sig and access_token is correct,
|
123
154
|
# that means we're in the context of canvas
|
124
155
|
def rest_graph_check_params_session
|
125
|
-
|
156
|
+
return if rest_graph.authorized? || !params[:session]
|
126
157
|
|
127
158
|
rest_graph.parse_json!(params[:session])
|
128
159
|
logger.debug("DEBUG: RestGraph: detected session, parsed:" \
|
129
160
|
" #{rest_graph.data.inspect}")
|
130
161
|
|
131
162
|
if rest_graph.authorized?
|
132
|
-
|
163
|
+
rest_graph_write_session
|
133
164
|
else
|
134
165
|
logger.warn("WARN: RestGraph: bad session: #{params[:session]}")
|
135
166
|
end
|
136
|
-
|
137
|
-
rest_graph_write_session
|
138
167
|
end
|
139
168
|
|
140
169
|
# exchange the code with access_token
|
@@ -148,7 +177,7 @@ module RestGraph::RailsUtil
|
|
148
177
|
"#{rest_graph_normalized_request_uri}, " \
|
149
178
|
"parsed: #{rest_graph.data.inspect}")
|
150
179
|
|
151
|
-
rest_graph_write_session
|
180
|
+
rest_graph_write_session if rest_graph.authorized?
|
152
181
|
end
|
153
182
|
|
154
183
|
def rest_graph_check_rails_session
|
@@ -159,24 +188,31 @@ module RestGraph::RailsUtil
|
|
159
188
|
" #{rest_graph.data.inspect}")
|
160
189
|
end
|
161
190
|
|
162
|
-
# ==================== others
|
191
|
+
# ==================== others ================================
|
163
192
|
|
164
193
|
def rest_graph_write_session
|
165
|
-
return if !
|
194
|
+
return if !rest_graph_oget(:write_session)
|
166
195
|
|
167
196
|
fbs = rest_graph.data.to_a.map{ |k_v| k_v.join('=') }.join('&')
|
168
197
|
session['fbs'] = fbs
|
169
198
|
logger.debug("DEBUG: RestGraph: wrote session: fbs => #{fbs}")
|
170
199
|
end
|
171
200
|
|
172
|
-
def rest_graph_log
|
173
|
-
|
201
|
+
def rest_graph_log event
|
202
|
+
message = "DEBUG: RestGraph: spent #{sprintf('%f', event.duration)} "
|
203
|
+
case event
|
204
|
+
when RestGraph::Event::Requested
|
205
|
+
logger.debug(message + "requesting #{event.url}")
|
206
|
+
|
207
|
+
when RestGraph::Event::CacheHit
|
208
|
+
logger.debug(message + "cache hit' #{event.url}")
|
209
|
+
end
|
174
210
|
end
|
175
211
|
|
176
212
|
def rest_graph_normalized_request_uri
|
177
213
|
if rest_graph_in_canvas?
|
178
214
|
"http://apps.facebook.com/" \
|
179
|
-
"#{
|
215
|
+
"#{rest_graph_oget(:canvas)}#{request.request_uri}"
|
180
216
|
else
|
181
217
|
request.url
|
182
218
|
end.sub(/[\&\?]session=[^\&]+/, '').
|
@@ -184,21 +220,13 @@ module RestGraph::RailsUtil
|
|
184
220
|
end
|
185
221
|
|
186
222
|
def rest_graph_in_canvas?
|
187
|
-
!
|
188
|
-
end
|
189
|
-
|
190
|
-
def rest_graph_canvas
|
191
|
-
if rest_graph_options[:canvas].empty?
|
192
|
-
RestGraph.default_canvas
|
193
|
-
else
|
194
|
-
rest_graph_options[:canvas]
|
195
|
-
end
|
223
|
+
!rest_graph_oget(:canvas).blank?
|
196
224
|
end
|
197
225
|
|
198
226
|
def rest_graph_auto_authorize?
|
199
|
-
!
|
200
|
-
!
|
201
|
-
|
227
|
+
!rest_graph_oget(:auto_authorize_scope) .blank? ||
|
228
|
+
!rest_graph_oget(:auto_authorize_options).blank? ||
|
229
|
+
rest_graph_oget(:auto_authorize)
|
202
230
|
end
|
203
231
|
|
204
232
|
def rest_graph_extract_options options, method
|
data/lib/rest-graph/version.rb
CHANGED
data/rest-graph.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{rest-graph}
|
5
|
-
s.version = "1.4.
|
5
|
+
s.version = "1.4.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Cardinal Blue", "Lin Jen-Shin (aka godfat 真常)"]
|
9
|
-
s.date = %q{2010-07-
|
9
|
+
s.date = %q{2010-07-26}
|
10
10
|
s.description = %q{ A super simple Facebook Open Graph API client}
|
11
11
|
s.email = %q{dev (XD) cardinalblue.com}
|
12
|
-
s.extra_rdoc_files = ["CHANGES", "LICENSE", "README", "TODO", "example/rails/README", "example/rails/config/rest-graph.yaml", "example/rails/log", "example/rails/script/console", "example/rails/script/server", "rest-graph.gemspec"]
|
13
|
-
s.files = ["CHANGES", "LICENSE", "README", "README.rdoc", "Rakefile", "TODO", "example/rails/README", "example/rails/Rakefile", "example/rails/app/controllers/application_controller.rb", "example/rails/config/boot.rb", "example/rails/config/environment.rb", "example/rails/config/environments/development.rb", "example/rails/config/environments/production.rb", "example/rails/config/environments/test.rb", "example/rails/config/initializers/cookie_verification_secret.rb", "example/rails/config/initializers/new_rails_defaults.rb", "example/rails/config/initializers/session_store.rb", "example/rails/config/rest-graph.yaml", "example/rails/config/routes.rb", "example/rails/log", "example/rails/script/console", "example/rails/script/server", "example/rails/test/functional/application_controller_test.rb", "example/rails/test/test_helper.rb", "init.rb", "lib/rest-graph.rb", "lib/rest-graph/auto_load.rb", "lib/rest-graph/facebook_util.rb", "lib/rest-graph/load_config.rb", "lib/rest-graph/rails_util.rb", "lib/rest-graph/version.rb", "rest-graph.gemspec", "test/common.rb", "test/config/rest-graph.yaml", "test/test_default.rb", "test/test_handler.rb", "test/test_load_config.rb", "test/test_oauth.rb", "test/test_old.rb", "test/test_parse.rb", "test/test_rest-graph.rb"]
|
12
|
+
s.extra_rdoc_files = ["CHANGES", "Gemfile", "Gemfile.lock", "LICENSE", "README", "TODO", "example/rails/README", "example/rails/config/rest-graph.yaml", "example/rails/log", "example/rails/script/console", "example/rails/script/server", "rest-graph.gemspec"]
|
13
|
+
s.files = ["CHANGES", "Gemfile", "Gemfile.lock", "LICENSE", "README", "README.rdoc", "Rakefile", "TODO", "example/rails/README", "example/rails/Rakefile", "example/rails/app/controllers/application_controller.rb", "example/rails/config/boot.rb", "example/rails/config/environment.rb", "example/rails/config/environments/development.rb", "example/rails/config/environments/production.rb", "example/rails/config/environments/test.rb", "example/rails/config/initializers/cookie_verification_secret.rb", "example/rails/config/initializers/new_rails_defaults.rb", "example/rails/config/initializers/session_store.rb", "example/rails/config/rest-graph.yaml", "example/rails/config/routes.rb", "example/rails/log", "example/rails/script/console", "example/rails/script/server", "example/rails/test/functional/application_controller_test.rb", "example/rails/test/test_helper.rb", "init.rb", "lib/rest-graph.rb", "lib/rest-graph/auto_load.rb", "lib/rest-graph/facebook_util.rb", "lib/rest-graph/load_config.rb", "lib/rest-graph/rails_util.rb", "lib/rest-graph/version.rb", "rest-graph.gemspec", "test/common.rb", "test/config/rest-graph.yaml", "test/test_default.rb", "test/test_handler.rb", "test/test_load_config.rb", "test/test_oauth.rb", "test/test_old.rb", "test/test_parse.rb", "test/test_rest-graph.rb"]
|
14
14
|
s.homepage = %q{http://github.com/cardinalblue/rest-graph}
|
15
15
|
s.rdoc_options = ["--main", "README.rdoc"]
|
16
16
|
s.require_paths = ["lib"]
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.add_development_dependency(%q<json>, [">= 1.4.3"])
|
29
29
|
s.add_development_dependency(%q<rack>, [">= 1.2.1"])
|
30
30
|
s.add_development_dependency(%q<rr>, [">= 0.10.11"])
|
31
|
-
s.add_development_dependency(%q<webmock>, [">= 1.3.
|
31
|
+
s.add_development_dependency(%q<webmock>, [">= 1.3.2"])
|
32
32
|
s.add_development_dependency(%q<bacon>, [">= 1.1.0"])
|
33
33
|
s.add_development_dependency(%q<bones>, [">= 3.4.7"])
|
34
34
|
else
|
@@ -36,7 +36,7 @@ Gem::Specification.new do |s|
|
|
36
36
|
s.add_dependency(%q<json>, [">= 1.4.3"])
|
37
37
|
s.add_dependency(%q<rack>, [">= 1.2.1"])
|
38
38
|
s.add_dependency(%q<rr>, [">= 0.10.11"])
|
39
|
-
s.add_dependency(%q<webmock>, [">= 1.3.
|
39
|
+
s.add_dependency(%q<webmock>, [">= 1.3.2"])
|
40
40
|
s.add_dependency(%q<bacon>, [">= 1.1.0"])
|
41
41
|
s.add_dependency(%q<bones>, [">= 3.4.7"])
|
42
42
|
end
|
@@ -45,7 +45,7 @@ Gem::Specification.new do |s|
|
|
45
45
|
s.add_dependency(%q<json>, [">= 1.4.3"])
|
46
46
|
s.add_dependency(%q<rack>, [">= 1.2.1"])
|
47
47
|
s.add_dependency(%q<rr>, [">= 0.10.11"])
|
48
|
-
s.add_dependency(%q<webmock>, [">= 1.3.
|
48
|
+
s.add_dependency(%q<webmock>, [">= 1.3.2"])
|
49
49
|
s.add_dependency(%q<bacon>, [">= 1.1.0"])
|
50
50
|
s.add_dependency(%q<bones>, [">= 3.4.7"])
|
51
51
|
end
|
data/test/config/rest-graph.yaml
CHANGED
data/test/test_handler.rb
CHANGED
@@ -8,49 +8,81 @@ end
|
|
8
8
|
require 'json'
|
9
9
|
|
10
10
|
describe RestGraph do
|
11
|
-
|
12
|
-
@id = lambda{ |obj| obj }
|
13
|
-
@error = '{"error":{"type":"Exception","message":"(#2500)"}}'
|
14
|
-
@error_hash = JSON.parse(@error)
|
15
|
-
|
11
|
+
after do
|
16
12
|
reset_webmock
|
17
|
-
|
18
|
-
to_return(:body => @error)
|
13
|
+
RR.verify
|
19
14
|
end
|
20
15
|
|
21
|
-
|
22
|
-
|
23
|
-
|
16
|
+
describe 'log handler' do
|
17
|
+
it 'would log whenever doing network request' do
|
18
|
+
stub_request(:get, 'https://graph.facebook.com/me').
|
19
|
+
to_return(:body => '{}')
|
20
|
+
|
21
|
+
mock(Time).now{ 666 }
|
22
|
+
mock(Time).now{ 999 }
|
23
|
+
|
24
|
+
logger = []
|
25
|
+
rg = RestGraph.new(:log_handler => lambda{ |e|
|
26
|
+
logger << [e.duration, e.url] })
|
27
|
+
rg.get('me')
|
24
28
|
|
25
|
-
|
26
|
-
begin
|
27
|
-
RestGraph.new.get('me')
|
28
|
-
rescue ::RestGraph::Error => e
|
29
|
-
e.message.should == @error_hash
|
29
|
+
logger.last.should == [333, 'https://graph.facebook.com/me']
|
30
30
|
end
|
31
31
|
end
|
32
|
-
end
|
33
32
|
|
34
|
-
describe
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
describe 'with Graph API' do
|
34
|
+
before do
|
35
|
+
@id = lambda{ |obj| obj }
|
36
|
+
@error = '{"error":{"type":"Exception","message":"(#2500)"}}'
|
37
|
+
@error_hash = JSON.parse(@error)
|
38
38
|
|
39
|
-
|
40
|
-
|
39
|
+
stub_request(:get, 'https://graph.facebook.com/me').
|
40
|
+
to_return(:body => @error)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'would call error_handler if error occurred' do
|
44
|
+
RestGraph.new(:error_handler => @id).get('me').should == @error_hash
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'would raise ::RestGraph::Error in default error_handler' do
|
48
|
+
begin
|
49
|
+
RestGraph.new.get('me')
|
50
|
+
rescue ::RestGraph::Error => e
|
51
|
+
e.message.should == @error_hash
|
52
|
+
end
|
53
|
+
end
|
41
54
|
end
|
42
55
|
|
43
|
-
|
44
|
-
|
45
|
-
|
56
|
+
describe 'with FQL API' do
|
57
|
+
# Example of an actual response (without newline)
|
58
|
+
# {"error_code":603,"error_msg":"Unknown table: bad_table",
|
59
|
+
# "request_args":[{"key":"method","value":"fql.query"},
|
60
|
+
# {"key":"format","value":"json"},
|
61
|
+
# {"key":"query","value":
|
62
|
+
# "SELECT name FROM bad_table WHERE uid=12345"}]}
|
63
|
+
before do
|
64
|
+
@id = lambda{ |obj| obj }
|
65
|
+
@fql_error = '{"error_code":603,"error_msg":"Unknown table: bad"}'
|
66
|
+
@fql_error_hash = JSON.parse(@fql_error)
|
46
67
|
|
47
|
-
|
48
|
-
|
68
|
+
@bad_fql_query = 'SELECT name FROM bad_table WHERE uid="12345"'
|
69
|
+
bad_fql_request = "https://api.facebook.com/method/fql.query?" \
|
70
|
+
"format=json&query=#{CGI.escape(@bad_fql_query)}"
|
49
71
|
|
50
|
-
|
51
|
-
|
52
|
-
rg.get('me')
|
72
|
+
stub_request(:get, bad_fql_request).to_return(:body => @fql_error)
|
73
|
+
end
|
53
74
|
|
54
|
-
|
75
|
+
it 'would call error_handler if error occurred' do
|
76
|
+
RestGraph.new(:error_handler => @id).fql(@bad_fql_query).
|
77
|
+
should == @fql_error_hash
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'would raise ::RestGraph::Error in default error_handler' do
|
81
|
+
begin
|
82
|
+
RestGraph.new.fql(@bad_fql_query)
|
83
|
+
rescue ::RestGraph::Error => e
|
84
|
+
e.message.should == @fql_error_hash
|
85
|
+
end
|
86
|
+
end
|
55
87
|
end
|
56
88
|
end
|
data/test/test_oauth.rb
CHANGED
@@ -7,11 +7,14 @@ end
|
|
7
7
|
|
8
8
|
describe RestGraph do
|
9
9
|
before do
|
10
|
-
reset_webmock
|
11
10
|
@rg = RestGraph.new(:app_id => '29', :secret => '18')
|
12
11
|
@uri = 'http://zzz.tw'
|
13
12
|
end
|
14
13
|
|
14
|
+
after do
|
15
|
+
reset_webmock
|
16
|
+
end
|
17
|
+
|
15
18
|
it 'would return correct oauth url' do
|
16
19
|
TestHelper.normalize_url(@rg.authorize_url(:redirect_uri => @uri)).
|
17
20
|
should == 'https://graph.facebook.com/oauth/authorize?' \
|
data/test/test_old.rb
CHANGED
data/test/test_parse.rb
CHANGED
@@ -68,4 +68,23 @@ describe RestGraph do
|
|
68
68
|
should == {'feed' => 'me', 'sig' => "20393e7823730308938a86ecf1c88b14"}
|
69
69
|
end
|
70
70
|
|
71
|
+
it 'would parse signed_request' do
|
72
|
+
secret = 'aloha'
|
73
|
+
json = {'ooh' => 'dir', 'moo' => 'bar'}.to_json
|
74
|
+
encode = lambda{ |str|
|
75
|
+
[str].pack('m').tr("\n=", '').tr('+/', '-_')
|
76
|
+
}
|
77
|
+
json_encoded = encode[json]
|
78
|
+
sig = OpenSSL::HMAC.digest('sha256', secret, json_encoded)
|
79
|
+
signed_request = "#{encode[sig]}.#{json_encoded}"
|
80
|
+
|
81
|
+
rg = RestGraph.new(:secret => secret)
|
82
|
+
rg.parse_signed_request!(signed_request)
|
83
|
+
rg.data['ooh'].should == 'dir'
|
84
|
+
rg.data['moo'].should == 'bar'
|
85
|
+
|
86
|
+
signed_request = "#{encode[sig[0..-4]+'bad']}.#{json_encoded}"
|
87
|
+
rg.parse_signed_request!(signed_request).should == nil
|
88
|
+
end
|
89
|
+
|
71
90
|
end
|
data/test/test_rest-graph.rb
CHANGED
@@ -6,11 +6,8 @@ else
|
|
6
6
|
end
|
7
7
|
|
8
8
|
describe RestGraph do
|
9
|
-
before do
|
10
|
-
reset_webmock
|
11
|
-
end
|
12
|
-
|
13
9
|
after do
|
10
|
+
reset_webmock
|
14
11
|
RR.verify
|
15
12
|
end
|
16
13
|
|
@@ -42,6 +39,13 @@ describe RestGraph do
|
|
42
39
|
should == '?message=hi%21%21&subject=%28%26oh%26%29'
|
43
40
|
end
|
44
41
|
|
42
|
+
it 'would generate correct url' do
|
43
|
+
TestHelper.normalize_url(
|
44
|
+
RestGraph.new(:access_token => 'awesome').url('path', :query => 'string')).
|
45
|
+
should ==
|
46
|
+
'https://graph.facebook.com/path?access_token=awesome&query=string'
|
47
|
+
end
|
48
|
+
|
45
49
|
it 'would request to correct server' do
|
46
50
|
stub_request(:get, 'http://nothing.godfat.org/me').with(
|
47
51
|
:headers => {'Accept' => 'text/plain',
|
@@ -113,4 +117,17 @@ describe RestGraph do
|
|
113
117
|
to_return(:body => 'ok')
|
114
118
|
RestGraph.new(:auto_decode => false).get('search', :q => o).should == 'ok'
|
115
119
|
end
|
120
|
+
|
121
|
+
it 'would enable cache if passing cache' do
|
122
|
+
url, body = "https://graph.facebook.com/cache", '{"message":"ok"}'
|
123
|
+
stub_request(:get, url).to_return(:body => body)
|
124
|
+
|
125
|
+
cache = {}
|
126
|
+
rg = RestGraph.new(:cache => cache, :auto_decode => false)
|
127
|
+
3.times{
|
128
|
+
rg.get('cache').should == body
|
129
|
+
reset_webmock
|
130
|
+
}
|
131
|
+
cache.should == {rg.send(:cache_key, url) => body}
|
132
|
+
end
|
116
133
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest-graph
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 5
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 1.4.
|
9
|
+
- 1
|
10
|
+
version: 1.4.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Cardinal Blue
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-
|
19
|
+
date: 2010-08-04 00:00:00 +08:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -91,12 +91,12 @@ dependencies:
|
|
91
91
|
requirements:
|
92
92
|
- - ">="
|
93
93
|
- !ruby/object:Gem::Version
|
94
|
-
hash:
|
94
|
+
hash: 31
|
95
95
|
segments:
|
96
96
|
- 1
|
97
97
|
- 3
|
98
|
-
-
|
99
|
-
version: 1.3.
|
98
|
+
- 2
|
99
|
+
version: 1.3.2
|
100
100
|
type: :development
|
101
101
|
version_requirements: *id005
|
102
102
|
- !ruby/object:Gem::Dependency
|
@@ -139,6 +139,8 @@ extensions: []
|
|
139
139
|
|
140
140
|
extra_rdoc_files:
|
141
141
|
- CHANGES
|
142
|
+
- Gemfile
|
143
|
+
- Gemfile.lock
|
142
144
|
- LICENSE
|
143
145
|
- README
|
144
146
|
- TODO
|
@@ -150,6 +152,8 @@ extra_rdoc_files:
|
|
150
152
|
- rest-graph.gemspec
|
151
153
|
files:
|
152
154
|
- CHANGES
|
155
|
+
- Gemfile
|
156
|
+
- Gemfile.lock
|
153
157
|
- LICENSE
|
154
158
|
- README
|
155
159
|
- README.rdoc
|
@@ -176,7 +180,6 @@ files:
|
|
176
180
|
- init.rb
|
177
181
|
- lib/rest-graph.rb
|
178
182
|
- lib/rest-graph/auto_load.rb
|
179
|
-
- lib/rest-graph/facebook_util.rb
|
180
183
|
- lib/rest-graph/load_config.rb
|
181
184
|
- lib/rest-graph/rails_util.rb
|
182
185
|
- lib/rest-graph/version.rb
|
@@ -1,27 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'rest-graph'
|
3
|
-
|
4
|
-
module RestGraph::FacebookUtil
|
5
|
-
module_function
|
6
|
-
def ext_perm
|
7
|
-
%w[publish_stream create_event rsvp_event sms offline_access manage_pages
|
8
|
-
email read_insights read_stream read_mailbox ads_management xmpp_login
|
9
|
-
user_about_me user_activities user_birthday user_education_history
|
10
|
-
user_events user_groups user_hometown user_interests user_likes
|
11
|
-
user_location user_notes user_online_presence user_photo_video_tags
|
12
|
-
user_photos user_relationships user_religion_politics user_status
|
13
|
-
user_videos user_videos user_work_history read_friendlists read_requests
|
14
|
-
friends_about_me friends_activities friends_birthday
|
15
|
-
friends_education_history friends_events friends_groups friends_hometown
|
16
|
-
friends_interests friends_likes friends_location friends_notes
|
17
|
-
friends_online_presence friends_photo_video_tags friends_photos
|
18
|
-
friends_relationships friends_religion_politics friends_status
|
19
|
-
friends_videos friends_website friends_work_history]
|
20
|
-
end
|
21
|
-
|
22
|
-
def method_name
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
RestGraph.send(:include, RestGraph::FacebookUtil)
|