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 CHANGED
@@ -1,6 +1,26 @@
1
1
  = rest-graph changes history
2
2
 
3
- == rest-graph 1.4.0 -- ?
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
@@ -0,0 +1,12 @@
1
+
2
+ source 'http://rubygems.org'
3
+
4
+ gem 'rest-client'
5
+
6
+ group :test do
7
+ gem 'yajl-ruby'
8
+ gem 'rack'
9
+ gem 'rr'
10
+ gem 'webmock'
11
+ gem 'bacon'
12
+ end
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.3.0
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.3.0
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(:data, :auto_decode,
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{ |duration, url| }
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(graph_server, path, query, :get, nil, opts[:suppress_decode])
95
+ request(:get , url(path, query, graph_server), opts)
85
96
  end
86
97
 
87
98
  def delete path, query={}, opts={}
88
- request(graph_server, path, query, :delete, nil, opts[:suppress_decode])
99
+ request(:delete, url(path, query, graph_server), opts)
89
100
  end
90
101
 
91
102
  def post path, payload, query={}, opts={}
92
- request(graph_server, path, query, :post, payload, opts[:suppress_decode])
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(graph_server, path, query, :put, payload, opts[:suppress_decode])
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
- request(graph_server, 'oauth/access_token', query, :get, nil, true))
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(old_server, "method/#{path}",
139
- {:format => 'json'}.merge(query), :get, nil, opts[:suppress_decode])
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(graph_server, 'oauth/exchange_sessions', query, :post)
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 server, path, opts, method, payload=nil, suppress_decode=nil
191
+ def request meth, uri, opts={}, payload=nil
166
192
  start_time = Time.now
167
- res = RestClient::Resource.new(server)[path + build_query_string(opts)]
168
- post_request(
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, res.url)
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) && hash['error']
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
- module RestGraph::DefaultAttributes
5
- def default_canvas
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
- rest_graph_options .merge!(rest_graph_extract_options(options, :reject))
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 3 ways to check the user identity!
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 => rest_graph_options[:auto_authorize_scope]}.
68
- merge( rest_graph_options[:auto_authorize_options]))
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
- # ==================== checking utility ====================
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
- return if rest_graph.authorized? || !params[:session]
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
- @fb_sig_in_canvas = true
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 !rest_graph.authorized? || !rest_graph_options[:write_session]
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 duration, url
173
- logger.debug("DEBUG: RestGraph: spent #{duration} requesting #{url}")
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
- "#{rest_graph_canvas}#{request.request_uri}"
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
- !rest_graph_options[:canvas].empty?
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
- !rest_graph_options[:auto_authorize_scope ].empty? ||
200
- !rest_graph_options[:auto_authorize_options].empty? ||
201
- rest_graph_options[:auto_authorize]
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
@@ -1,4 +1,4 @@
1
1
 
2
2
  require 'rest-graph'
3
3
 
4
- RestGraph::VERSION = '1.4.0'
4
+ RestGraph::VERSION = '1.4.1'
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.0"
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-15}
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.1"])
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.1"])
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.1"])
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
@@ -4,3 +4,4 @@ test:
4
4
  secret: <%= 'r41829'.reverse %>
5
5
  auto_decode: false
6
6
  lang: zh-tw
7
+ auto_authorize_scope: 'publish_stream'
data/test/test_handler.rb CHANGED
@@ -8,49 +8,81 @@ end
8
8
  require 'json'
9
9
 
10
10
  describe RestGraph do
11
- before do
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
- stub_request(:get, 'https://graph.facebook.com/me').
18
- to_return(:body => @error)
13
+ RR.verify
19
14
  end
20
15
 
21
- it 'would call error_handler if error occurred' do
22
- RestGraph.new(:error_handler => @id).get('me').should == @error_hash
23
- end
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
- it 'would raise ::RestGraph::Error in default error_handler' do
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 RestGraph do
35
- before do
36
- reset_webmock
37
- end
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
- after do
40
- RR.verify
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
- it 'would log whenever doing network request' do
44
- stub_request(:get, 'https://graph.facebook.com/me').
45
- to_return(:body => '{}')
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
- mock(Time).now{ 666 }
48
- mock(Time).now{ 999 }
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
- logger = []
51
- rg = RestGraph.new(:log_handler => lambda{ |d, u| logger << [d, u] })
52
- rg.get('me')
72
+ stub_request(:get, bad_fql_request).to_return(:body => @fql_error)
73
+ end
53
74
 
54
- logger.last.should == [333, 'https://graph.facebook.com/me']
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
@@ -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
 
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
@@ -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: 7
4
+ hash: 5
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 4
9
- - 0
10
- version: 1.4.0
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-07-15 00:00:00 +08:00
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: 25
94
+ hash: 31
95
95
  segments:
96
96
  - 1
97
97
  - 3
98
- - 1
99
- version: 1.3.1
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)