fgraph 0.1.5 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/History CHANGED
@@ -1,3 +1,8 @@
1
+ v0.2.0 - May 26, 2010
2
+ * Rails plugin support
3
+ * Add FGraph::Collection response object
4
+ * Allow Hash object as id input
5
+
1
6
  v0.1.5 - May 25, 2010
2
7
  * Fix FGraph::Client not passing default :access_token options properly
3
8
 
data/README.rdoc CHANGED
@@ -9,7 +9,26 @@ Facebook Graph Ruby API implementation with Ruby magic (http://graph.facebook.co
9
9
  == Installation
10
10
 
11
11
  sudo gem install fgraph
12
+
13
+ == Rails Plugin Installation
14
+
15
+ Gem Plugin installation:
16
+
17
+ sudo gem install fgraph
12
18
 
19
+ # Edit [RAILS_ROOT]/config/environment.rb
20
+ config.gem 'fgraph', :version => ">=0.2.0"
21
+
22
+ # Edit [RAILS_ROOT]/Rakefile
23
+ require 'tasks/fgraph'
24
+
25
+ # Create fgraph.yml config in [RAILS_ROOT]/config
26
+ rake fgraph:setup
27
+
28
+ Normal Plugin Installation:
29
+
30
+ script/plugin install http://github.com/jugend/fgraph.git
31
+
13
32
  === Facebook Graph Cheat Sheet
14
33
 
15
34
  sudo gem install cheat
@@ -29,6 +48,10 @@ Facebook Graph Ruby API implementation with Ruby magic (http://graph.facebook.co
29
48
  # Page photos
30
49
  FGraph.object('/cocacola/photos')
31
50
  FGraph.object_photos('cocacola')
51
+
52
+ # Passing object hash as id
53
+ friend = { 'name' => 'Mark Zuckerberg', 'id' => '4'}
54
+ friend_details = FGraph.object(friend)
32
55
 
33
56
  # Current user: https://graph.facebook.com/me?access_token=...
34
57
  FGraph.me(:access_token => '...')
@@ -40,11 +63,27 @@ Facebook Graph Ruby API implementation with Ruby magic (http://graph.facebook.co
40
63
  === Multiple objects query
41
64
 
42
65
  # Multiple users select: https://graph.facebook.com?ids=arjun,vernal
43
- FGraph.objects('arjun', 'vernel')
66
+ FGraph.objects('arjun', 'herryanto')
44
67
 
45
68
  # Filter fields: https://graph.facebook.com?ids=arjun,vernal&fields=id,name,picture
46
- FGraph.objects('arjun', 'vernel', :fields => 'id,name,picture')
69
+ FGraph.objects('arjun', 'herryanto', :fields => 'id,name,picture')
70
+
71
+ # Passing hash objects
72
+ FGraph.objects([{:name => 'Arjun Banker', :id => 'arjun'}, {:name => 'Herryanto Siatono', :id => 'herryanto'}])
47
73
 
74
+ === Collection Response
75
+
76
+ friends = FGraph.me_friends(:limit => 5, :access_token => '...')
77
+ friends.each do |friend|
78
+ puts friend['name']
79
+ puts friend['id']
80
+ end
81
+
82
+ # Other convenient methods
83
+ friends.next?
84
+ friends.next_url
85
+ friends.next_options
86
+
48
87
  === OAuth
49
88
 
50
89
  OAuth authorization URL:
@@ -115,13 +154,51 @@ OAuth Application Access Token, required to access application anlytics data:
115
154
  fg_client = FGraph::Client.new(:access_token => '...')
116
155
  fg_client.me
117
156
  fg.client.publish_feed('herryanto', :message => 'Cool!')
118
-
157
+
119
158
  === Pagination Options
120
159
 
121
160
  * <tt>limit</tt> - max no of records
122
161
  * <tt>offset</tt> - offset
123
162
  * <tt>until</tt> - since (a unix timestamp or any date accepted by strtotime, e.g. yesterday)
124
163
 
164
+ === Rails Helper
165
+
166
+ Sample codes:
167
+
168
+ <%= fgraph_javascript_init_tag %>
169
+ <script type="text/javascript">
170
+ FB.Event.subscribe('auth.sessionChange', function(response) {
171
+ if (response.session) {
172
+ // A user has logged in, and a new cookie has been saved
173
+ } else {
174
+ // The user has logged out, and the cookie has been cleared
175
+ }
176
+ });
177
+ </script>
178
+
179
+ <!-- Facebook Login Button -->
180
+ <fb:login-button autologoutlink="true" perms="email,publish_stream"></fb:login-button>
181
+
182
+ <% if fgraph_logged_in? %>
183
+ <br>Hello <%= fgraph_current_user['name'] %>,
184
+ <br><%= fgraph_image_tag(fgraph_current_user, 'large') %>
185
+ <% end %>
186
+
187
+ For Asynchronous load, use <tt>window.afterFbAsyncInit</tt>:
188
+
189
+ <%= fgraph_javascript_init_tag :async => true %>
190
+ <script type="text/javascript">
191
+ window.afterFbAsyncInit = function() {
192
+ FB.Event.subscribe('auth.sessionChange', function(response) {
193
+ if (response.session) {
194
+ // A user has logged in, and a new cookie has been saved
195
+ } else {
196
+ // The user has logged out, and the cookie has been cleared
197
+ }
198
+ });
199
+ }
200
+ </script>
201
+
125
202
  == License
126
203
 
127
204
  (The MIT License)
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ begin
9
9
  gem.email = "herryanto@gmail.com"
10
10
  gem.homepage = "http://github.com/jugend/fgraph"
11
11
  gem.authors = ["Herryanto Siatono"]
12
- gem.files = FileList["[A-Z]*", "{examples,lib,test}/**/*"]
12
+ gem.files = FileList["[A-Z]*", "{examples,lib,test,rails,tasks,templates}/**/*"]
13
13
 
14
14
  gem.add_dependency("httparty", "~> 0.5.0")
15
15
  # gem.add_dependency("hashie", "~> 0.2.0")
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- :patch: 5
2
+ :patch: 0
3
3
  :major: 0
4
4
  :build:
5
- :minor: 1
5
+ :minor: 2
@@ -1,10 +1,13 @@
1
1
  module FGraph
2
2
  module Rails
3
3
  module FGraphHelper
4
+
5
+ # Access FGraph.config initialized with values set in <tt>[RAILS_ROOT]/config/fgraph.yml</tt>.
4
6
  def fgraph_config
5
7
  FGraph.config || {}
6
8
  end
7
-
9
+
10
+ # Return Facebook session, default to retrieve session from cookies
8
11
  def fgraph_session(app_id = fgraph_config['app_id'],
9
12
  app_secret = fgraph_config['app_secret'])
10
13
 
@@ -12,6 +15,7 @@ module FGraph
12
15
  @fgraph_session = fgraph_session_cookies(app_id, app_secret)
13
16
  end
14
17
 
18
+ # Return Facebook_session cookies
15
19
  def fgraph_session_cookies(app_id = fgraph_config['app_id'],
16
20
  app_secret = fgraph_config['app_secret'])
17
21
 
@@ -60,10 +64,11 @@ module FGraph
60
64
  @fgraph_current_user = fgraph_client.me
61
65
  end
62
66
 
67
+ # Return FGraph::Client.instance initialized with settings set in <tt>fgraph.yml</tt>.
68
+ # Initialized with <tt>:access_token</tt> as well if Facebook session exists.
63
69
  def fgraph_client
64
70
  return @fgraph_client if @fgraph_client
65
- session = fgraph_session || {}
66
-
71
+
67
72
  @fgraph_client = FGraph::Client.new(
68
73
  :client_id => fgraph_config['app_id'],
69
74
  :client_secret => fgraph_config['app_secret'],
@@ -0,0 +1,90 @@
1
+ module FGraph
2
+ module Rails
3
+ module FGraphTagHelper
4
+ def fgraph_javascript_include_tag
5
+ %{<script src="http://connect.facebook.net/en_US/all.js"></script>}
6
+ end
7
+
8
+ # Inititalize XFBML Javascript include and initialization script.
9
+ #
10
+ # ==== Options
11
+ # * <tt>app_id</tt> - overrride Fgraph.config['app_id'] value.
12
+ # * <tt>async</tt> - asynchronous javascript include & initialization.
13
+ # for other Facebook JS initialization codes please wrap under:
14
+ #
15
+ # window.afterFbAsyncInit = function() {
16
+ # ....
17
+ # }
18
+ #
19
+ def fgraph_javascript_init_tag(options={})
20
+ options = { :app_id => FGraph.config['app_id'] }.merge(options || {})
21
+
22
+ if options[:async]
23
+ %{
24
+ <div id="fb-root"></div>
25
+ <script>
26
+ window.fbAsyncInit = function() {
27
+ FB.init({appId: '#{options[:app_id]}', status: true, cookie: true,
28
+ xfbml: true});
29
+
30
+ if (window.afterFbAsyncInit) {
31
+ window.afterFbAsyncInit();
32
+ }
33
+ };
34
+ (function() {
35
+ var e = document.createElement('script'); e.async = true;
36
+ e.src = document.location.protocol +
37
+ '//connect.facebook.net/en_US/all.js';
38
+ document.getElementById('fb-root').appendChild(e);
39
+ }());
40
+ </script>
41
+ }
42
+ else
43
+ tag = fgraph_javascript_include_tag
44
+ tag << %{
45
+ <div id="fb-root"></div>
46
+ <script>
47
+ FB.init({appId: '#{options[:app_id]}', status: true, cookie: true, xfbml: true});
48
+ </script>
49
+ }
50
+ end
51
+ end
52
+
53
+ # Return Facebook object picture url: http://graph.facebook.com/[id]/picture
54
+ #
55
+ # ==== Type Options
56
+ # * <tt>square</tt> - 50x50 (default)
57
+ # * <tt>small</tt> - 50 pixels wide, variable height
58
+ # * <tt>normal</tt> - 100 pixels wide, variable height
59
+ # * <tt>large</tt> - 200 pixels wide, variable height
60
+ #
61
+ def fgraph_picture_url(id, type=nil)
62
+ id = FGraph.get_id(id)
63
+ url = "http://graph.facebook.com/#{id}/picture"
64
+ url += "?type=#{type}" if type
65
+ url
66
+ end
67
+
68
+ def fgraph_image_tag(id, type=nil, options={})
69
+ default_options = fgraph_image_options(type)
70
+ default_options[:alt] = id['name'] if id.is_a?(Hash)
71
+ image_tag(fgraph_picture_url(id, type), default_options.merge(options || {}))
72
+ end
73
+
74
+ def fgraph_image_options(type)
75
+ case type
76
+ when 'square'
77
+ {:width => 50, :height => 50}
78
+ when 'small'
79
+ {:width => 50}
80
+ when 'normal'
81
+ {:width => 100}
82
+ when 'large'
83
+ {:width => 200}
84
+ else
85
+ {:width => 50, :height => 50}
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
data/lib/fgraph.rb CHANGED
@@ -8,14 +8,6 @@ module FGraph
8
8
  base_uri 'https://graph.facebook.com'
9
9
  format :json
10
10
 
11
- def self.config
12
- @@config
13
- end
14
-
15
- def self.config=(config)
16
- @@config = config
17
- end
18
-
19
11
  # Facebook Error
20
12
  class FacebookError < StandardError
21
13
  attr_reader :data
@@ -31,299 +23,377 @@ module FGraph
31
23
  class OAuthError < FacebookError; end
32
24
  class OAuthAccessTokenError < OAuthError; end
33
25
 
34
- # Single object query.
35
- #
36
- # # Users: https://graph.facebook.com/btaylor (Bret Taylor)
37
- # FGraph.object('btaylor')
38
- #
39
- # # Pages: https://graph.facebook.com/cocacola (Coca-Cola page)
40
- # FGraph.object('cocacola')
41
- #
42
- # # Fields selection with metadata
43
- # FGraph.object('btaylor', :fields => 'id,name,picture', :metadata => 1)
26
+ # Collection objects for Graph response with array data.
44
27
  #
45
- # # Page photos
46
- # FGraph.object('/cocacola/photos')
47
- # FGraph.object_photos('cocacola')
48
- #
49
- def self.object(id, options={})
50
- perform_get("/#{id}", options)
28
+ class Collection < Array
29
+ attr_reader :next_url, :previous_url, :next_options, :previous_options
30
+
31
+ # Initialize Facebook response object with 'data' array value.
32
+ def initialize(response)
33
+ return super unless response
34
+
35
+ super(response['data'])
36
+ paging = response['paging'] || {}
37
+ self.next_url = paging['next']
38
+ self.previous_url = paging['previous']
39
+ end
40
+
41
+ def next_url=(url)
42
+ @next_url = url
43
+ @next_options = self.url_options(url)
44
+ end
45
+
46
+ def previous_url=(url)
47
+ @previous_url = url
48
+ @previous_options = self.url_options(url)
49
+ end
50
+
51
+ def first?
52
+ @previous_url.blank? and not @next_url.blank?
53
+ end
54
+
55
+ def next?
56
+ not @next_url.blank?
57
+ end
58
+
59
+ def previous?
60
+ not @previous_url.blank?
61
+ end
62
+
63
+ def url_options(url)
64
+ return unless url
65
+
66
+ uri = URI.parse(url)
67
+ options = {}
68
+ uri.query.split('&').each do |param_set|
69
+ param_set = param_set.split('=')
70
+ options[param_set[0]] = CGI.unescape(param_set[1])
71
+ end
72
+ options
73
+ end
51
74
  end
52
75
 
53
- # call-seq:
54
- # FGraph.objects(id, id)
55
- # FGraph.objects(id, id, options_hash)
56
- #
57
- # Multiple objects query.
58
- #
59
- # # Multiple users select: https://graph.facebook.com?ids=arjun,vernal
60
- # FGraph.objects('arjun', 'vernel')
61
- #
62
- # # Filter fields: https://graph.facebook.com?ids=arjun,vernal&fields=id,name,picture
63
- # FGraph.objects('arjun', 'vernel', :fields => 'id,name,picture')
64
- #
65
- def self.objects(*args)
66
- options = args.last.is_a?(Hash) ? args.pop : {}
67
- options = options.merge(:ids => args.join(','))
68
- perform_get("/", options)
69
- end
76
+ class << self
77
+ attr_accessor :config
78
+
79
+ # Single object query.
80
+ #
81
+ # # Users: https://graph.facebook.com/btaylor (Bret Taylor)
82
+ # FGraph.object('btaylor')
83
+ #
84
+ # # Pages: https://graph.facebook.com/cocacola (Coca-Cola page)
85
+ # FGraph.object('cocacola')
86
+ #
87
+ # # Fields selection with metadata
88
+ # FGraph.object('btaylor', :fields => 'id,name,picture', :metadata => 1)
89
+ #
90
+ # # Page photos
91
+ # FGraph.object('/cocacola/photos')
92
+ # photos = FGraph.object_photos('cocacola')
93
+ #
94
+ # # Support id from object hash
95
+ # friend = { 'name' => 'Mark Zuckerberg', 'id' => '4'}
96
+ # friend_details = FGraph.object(friend)
97
+ def object(id, options={})
98
+ id = self.get_id(id)
99
+ perform_get("/#{id}", options)
100
+ end
70
101
 
71
- # call-seq:
72
- # FGraph.me(category)
73
- # FGraph.me(category, options_hash)
74
- #
75
- # Returns current user object details.
76
- #
77
- # <tt>category</tt> - <tt>friends|home|feed|likes|movies|books|notes|photos|videos|events|groups</tt>
78
- #
79
- # # Current user: https://graph.facebook.com/me?access_token=...
80
- # FGraph.me(:access_token => '...')
81
- #
82
- # # Current user's friends: https://graph.facebook.com/me/friends?access_token=...
83
- # FGraph.me('friends', :access_token => '...')
84
- # FGraph.me_friends(:access_token => '...')
85
- #
86
- def self.me(*args)
87
- options = args.last.is_a?(Hash) ? args.pop : {}
88
- category = args.shift
102
+ # call-seq:
103
+ # FGraph.objects(id, id)
104
+ # FGraph.objects(id, id, options_hash)
105
+ #
106
+ # Multiple objects query.
107
+ #
108
+ # # Multiple users select: https://graph.facebook.com?ids=arjun,vernal
109
+ # FGraph.objects('arjun', 'vernel')
110
+ #
111
+ # # Filter fields: https://graph.facebook.com?ids=arjun,vernal&fields=id,name,picture
112
+ # FGraph.objects('arjun', 'vernel', :fields => 'id,name,picture')
113
+ #
114
+ def objects(*args)
115
+ options = args.last.is_a?(Hash) ? args.pop : {}
89
116
 
90
- path = "me"
91
- path += "/#{category}" unless category.blank?
92
- self.object(path, options)
93
- end
117
+ # If first input before option is an array
118
+ if args.count == 1 and args.first.is_a?(Array)
119
+ args = args.first.map do |arg|
120
+ self.get_id(arg)
121
+ end
122
+ end
123
+
124
+ options = options.merge(:ids => args.join(','))
125
+ perform_get("/", options)
126
+ end
94
127
 
95
- # Request authorization from Facebok to fetch private data in the profile or permission to publish on a
96
- # user's behalf. Returns Oauth Authorization URL, redirect to this URL to allow user to authorize your
97
- # application from Facebook.
98
- #
99
- # <tt>client_id</tt> - Application ID
100
- # <tt>redirect_uri</tt> - Needs to begin with your app's Connect URL. For instance, if your Connect URL
101
- # is http://www.example.com then your redirect URI could be http://www.example.com/oauth_redirect.
102
- # <tt>scope (optional)</tt> -
103
- #
104
- # ==== Options
105
- # * <tt>scope</tt> - Extended permission required to fetch private data or request permision to
106
- # publish to Facebook on a user's behalf.
107
- # * <tt>display</tt> - Other display type for authentication/authorization form, i.e. popup, touch.
108
- #
109
- # # https://graph.facebook.com/oauth/authorize?
110
- # # client_id=...&
111
- # # redirect_uri=http://www.example.com/oauth_redirect&
112
- # # scope=publish_stream
113
- #
114
- # FGraph.oauth_authorize_url('[client id]', 'http://www.example.com/oauth_redirect', :scope =>
115
- # 'publish_stream')
116
- #
117
- def self.oauth_authorize_url(client_id, redirect_uri, options={})
118
- self.format_url('/oauth/authorize', {
119
- :client_id => client_id,
120
- :redirect_uri => redirect_uri
121
- }.merge(options))
122
- end
128
+ # call-seq:
129
+ # FGraph.me(category)
130
+ # FGraph.me(category, options_hash)
131
+ #
132
+ # Returns current user object details.
133
+ #
134
+ # <tt>category</tt> - <tt>friends|home|feed|likes|movies|books|notes|photos|videos|events|groups</tt>
135
+ #
136
+ # # Current user: https://graph.facebook.com/me?access_token=...
137
+ # FGraph.me(:access_token => '...')
138
+ #
139
+ # # Current user's friends: https://graph.facebook.com/me/friends?access_token=...
140
+ # FGraph.me('friends', :access_token => '...')
141
+ # FGraph.me_friends(:access_token => '...')
142
+ #
143
+ def me(*args)
144
+ options = args.last.is_a?(Hash) ? args.pop : {}
145
+ category = args.shift
146
+
147
+ path = "me"
148
+ path += "/#{category}" unless category.blank?
149
+ self.object(path, options)
150
+ end
123
151
 
124
- # Return OAuth access_token. There are two types of access token, user access token and application
125
- # access token.
126
- #
127
- # User access_token requires <tt>code</tt> and and <tt>redirect_uri</tt> options. <tt>code</tt> is
128
- # the autorization code appended as query string to redirect URI when accessing oauth authorization URL.
129
- #
130
- # # https://graph.facebook.com/oauth/access_token?
131
- # # client_id=...&
132
- # # client_secret=...&
133
- # # redirect_uri=http://www.example.com/oauth_redirect&
134
- # # code=...
135
- # FGraph.oauth_access_token('[client id]', '[client secret]',
136
- # :redirect_uri => ''http://www.example.com/oauth_redirect',
137
- # :code => '[authorization code]')
138
- #
139
- # Application access token requires <tt>:type => 'client_cred'</td> option. Used to access application
140
- # insights data.
141
- #
142
- # # https://graph.facebook.com/oauth/access_token?
143
- # # client_id=...&
144
- # # client_secret=...&
145
- # # type=client_cred
146
- # FGraph.oauth_access_token('[client id]', '[client secret]', :type => 'client_cred')
147
- #
148
- def self.oauth_access_token(client_id, client_secret, options={})
149
- url = self.format_url('/oauth/access_token', {
150
- :client_id => client_id,
151
- :client_secret => client_secret
152
- }.merge(options || {}))
152
+ # Request authorization from Facebok to fetch private data in the profile or permission to publish on a
153
+ # user's behalf. Returns Oauth Authorization URL, redirect to this URL to allow user to authorize your
154
+ # application from Facebook.
155
+ #
156
+ # <tt>client_id</tt> - Application ID
157
+ # <tt>redirect_uri</tt> - Needs to begin with your app's Connect URL. For instance, if your Connect URL
158
+ # is http://www.example.com then your redirect URI could be http://www.example.com/oauth_redirect.
159
+ # <tt>scope (optional)</tt> -
160
+ #
161
+ # ==== Options
162
+ # * <tt>scope</tt> - Extended permission required to fetch private data or request permision to
163
+ # publish to Facebook on a user's behalf.
164
+ # * <tt>display</tt> - Other display type for authentication/authorization form, i.e. popup, touch.
165
+ #
166
+ # # https://graph.facebook.com/oauth/authorize?
167
+ # # client_id=...&
168
+ # # redirect_uri=http://www.example.com/oauth_redirect&
169
+ # # scope=publish_stream
170
+ #
171
+ # FGraph.oauth_authorize_url('[client id]', 'http://www.example.com/oauth_redirect', :scope =>
172
+ # 'publish_stream')
173
+ #
174
+ def oauth_authorize_url(client_id, redirect_uri, options={})
175
+ self.format_url('/oauth/authorize', {
176
+ :client_id => client_id,
177
+ :redirect_uri => redirect_uri
178
+ }.merge(options))
179
+ end
180
+
181
+ # Return OAuth access_token. There are two types of access token, user access token and application
182
+ # access token.
183
+ #
184
+ # User access_token requires <tt>code</tt> and and <tt>redirect_uri</tt> options. <tt>code</tt> is
185
+ # the autorization code appended as query string to redirect URI when accessing oauth authorization URL.
186
+ #
187
+ # # https://graph.facebook.com/oauth/access_token?
188
+ # # client_id=...&
189
+ # # client_secret=...&
190
+ # # redirect_uri=http://www.example.com/oauth_redirect&
191
+ # # code=...
192
+ # FGraph.oauth_access_token('[client id]', '[client secret]',
193
+ # :redirect_uri => ''http://www.example.com/oauth_redirect',
194
+ # :code => '[authorization code]')
195
+ #
196
+ # Application access token requires <tt>:type => 'client_cred'</td> option. Used to access application
197
+ # insights data.
198
+ #
199
+ # # https://graph.facebook.com/oauth/access_token?
200
+ # # client_id=...&
201
+ # # client_secret=...&
202
+ # # type=client_cred
203
+ # FGraph.oauth_access_token('[client id]', '[client secret]', :type => 'client_cred')
204
+ #
205
+ def oauth_access_token(client_id, client_secret, options={})
206
+ url = self.format_url('/oauth/access_token', {
207
+ :client_id => client_id,
208
+ :client_secret => client_secret
209
+ }.merge(options || {}))
153
210
 
154
- response = self.perform_get(url)
155
- response_hash = {}
156
- response.split('&').each do |value|
157
- value_pair = value.split('=')
158
- response_hash[value_pair[0]] = value_pair[1]
211
+ response = self.perform_get(url)
212
+ response_hash = {}
213
+ response.split('&').each do |value|
214
+ value_pair = value.split('=')
215
+ response_hash[value_pair[0]] = value_pair[1]
216
+ end
217
+ response_hash
159
218
  end
160
- response_hash
161
- end
162
219
 
163
- # Shortcut to retrieve application access token.
164
- def self.oauth_app_access_token(client_id, client_secret)
165
- self.oauth_access_token(client_id, client_secret, :type => 'client_cred')
166
- end
220
+ # Shortcut to retrieve application access token.
221
+ def oauth_app_access_token(client_id, client_secret)
222
+ self.oauth_access_token(client_id, client_secret, :type => 'client_cred')
223
+ end
167
224
 
168
- # Publish to Facebook, you would need to be authorized and provide access token.
169
- #
170
- # # Post to user's feed.
171
- # # curl -F 'access_token=...' \
172
- # # -F 'message=Hello, Arjun. I like this new API.' \
173
- # # https://graph.facebook.com/arjun/feed
174
- # FGraph.publish('arjun/feed', :message => 'Hello, Arjun. I like this new API.',
175
- # :access_token => '...')
176
- # FGraph.publish_feed('arjun', :message => '...', :access_token => '...')
177
- # FGraph.publish_feed('me', ':message => '...', :access_token => '...')
178
- #
179
- # ==== Options
180
- #
181
- # Method Description Options
182
- # -------------------------------------------------------------------------------------
183
- # /PROFILE_ID/feed write to the given profile's feed/wall :message, :picture,
184
- # :link, :name, description
185
- # /POST_ID/comments comment on the given post :message
186
- # /POST_ID/likes like the given post none
187
- # /PROFILE_ID/notes write a note on the given profile :message, :subject
188
- # /PROFILE_ID/links write a link on the given profile :link, :message
189
- # /EVENT_ID/attending attend the given event none
190
- # /EVENT_ID/maybe maybe attend the given event none
191
- # /EVENT_ID/declined decline the given event none
192
- #
193
- def self.publish(id, options={})
194
- self.perform_post("/#{id}", options)
195
- end
225
+ # Publish to Facebook, you would need to be authorized and provide access token.
226
+ #
227
+ # # Post to user's feed.
228
+ # # curl -F 'access_token=...' \
229
+ # # -F 'message=Hello, Arjun. I like this new API.' \
230
+ # # https://graph.facebook.com/arjun/feed
231
+ # FGraph.publish('arjun/feed', :message => 'Hello, Arjun. I like this new API.',
232
+ # :access_token => '...')
233
+ # FGraph.publish_feed('arjun', :message => '...', :access_token => '...')
234
+ # FGraph.publish_feed('me', ':message => '...', :access_token => '...')
235
+ #
236
+ # ==== Options
237
+ #
238
+ # Method Description Options
239
+ # -------------------------------------------------------------------------------------
240
+ # /PROFILE_ID/feed write to the given profile's feed/wall :message, :picture,
241
+ # :link, :name, description
242
+ # /POST_ID/comments comment on the given post :message
243
+ # /POST_ID/likes like the given post none
244
+ # /PROFILE_ID/notes write a note on the given profile :message, :subject
245
+ # /PROFILE_ID/links write a link on the given profile :link, :message
246
+ # /EVENT_ID/attending attend the given event none
247
+ # /EVENT_ID/maybe maybe attend the given event none
248
+ # /EVENT_ID/declined decline the given event none
249
+ #
250
+ def publish(id, options={})
251
+ id = self.get_id(id)
252
+ self.perform_post("/#{id}", options)
253
+ end
196
254
 
197
- # Delete objects in the graph.
198
- #
199
- # # DELETE https://graph.facebook.com/ID?access_token=... HTTP/1.1
200
- #
201
- # FGraph.remove('[ID]')
202
- # FGraph.remove('[ID]/likes')
203
- # FGraph.remove_likes('[ID]')
204
- #
205
- def self.remove(id, options={})
206
- self.perform_delete("/#{id}", options)
207
- end
255
+ # Delete objects in the graph.
256
+ #
257
+ # # DELETE https://graph.facebook.com/ID?access_token=... HTTP/1.1
258
+ #
259
+ # FGraph.remove('[ID]')
260
+ # FGraph.remove('[ID]/likes')
261
+ # FGraph.remove_likes('[ID]')
262
+ #
263
+ def remove(id, options={})
264
+ id = self.get_id(id)
265
+ self.perform_delete("/#{id}", options)
266
+ end
208
267
 
209
- # Search over all public objects in the social graph.
210
- #
211
- # # https://graph.facebook.com/search?q=watermelon&type=post
212
- # FGraph.search('watermelon', :type => 'post')
213
- # FGraph.search_post('watermelon')
214
- #
215
- # ==== Options
216
- # * <tt>type</tt> - <tt>album|event|group|link|note|page|photo|post|status|user|video</tt>
217
- # * <tt>limit</tt> - max no of records
218
- # * <tt>offset</tt> - offset
219
- # * <tt>until</tt> - since (a unix timestamp or any date accepted by strtotime, e.g. yesterday)
220
- def self.search(query, options={})
221
- self.perform_get("/search", {
222
- :q => query
223
- }.merge(options|| {}))
224
- end
268
+ # Search over all public objects in the social graph.
269
+ #
270
+ # # https://graph.facebook.com/search?q=watermelon&type=post
271
+ # FGraph.search('watermelon', :type => 'post')
272
+ # FGraph.search_post('watermelon')
273
+ #
274
+ # ==== Options
275
+ # * <tt>type</tt> - <tt>album|event|group|link|note|page|photo|post|status|user|video</tt>
276
+ # * <tt>limit</tt> - max no of records
277
+ # * <tt>offset</tt> - offset
278
+ # * <tt>until</tt> - since (a unix timestamp or any date accepted by strtotime, e.g. yesterday)
279
+ def search(query, options={})
280
+ self.perform_get("/search", {
281
+ :q => query
282
+ }.merge(options|| {}))
283
+ end
225
284
 
226
- # Download insights data for your application.
227
- #
228
- # # https://graph.facebook.com/[client_id]/insights?access_token=...
229
- # FGraph.insights('[client_id]', '[app_access_token]')
230
- #
231
- # # https://graph.facebook.com/[client_id]/insights/application_api_call/day?access_token=...
232
- # FGraph.insights('[client_id]', '[app_access_token]', :metric_path => 'application_api_call/day')
233
- #
234
- # ==== Options
235
- # * <tt>metric_path</tt> - e.g. application_api_calls/day
236
- # * <tt>since</tt> - since (a unix timestamp or any date accepted by strtotime, e.g. yesterday)
237
- # * <tt>until</tt> - until (a unix timestamp or any date accepted by strtotime, e.g. yesterday)
238
- def self.insights(client_id, app_access_token, options={})
239
- metric_path = options.delete(:metric_path)
285
+ # Download insights data for your application.
286
+ #
287
+ # # https://graph.facebook.com/[client_id]/insights?access_token=...
288
+ # FGraph.insights('[client_id]', '[app_access_token]')
289
+ #
290
+ # # https://graph.facebook.com/[client_id]/insights/application_api_call/day?access_token=...
291
+ # FGraph.insights('[client_id]', '[app_access_token]', :metric_path => 'application_api_call/day')
292
+ #
293
+ # ==== Options
294
+ # * <tt>metric_path</tt> - e.g. application_api_calls/day
295
+ # * <tt>since</tt> - since (a unix timestamp or any date accepted by strtotime, e.g. yesterday)
296
+ # * <tt>until</tt> - until (a unix timestamp or any date accepted by strtotime, e.g. yesterday)
297
+ def insights(client_id, app_access_token, options={})
298
+ metric_path = options.delete(:metric_path)
240
299
 
241
- path = "/#{client_id}/insights"
242
- path += "/#{metric_path}" if metric_path
300
+ path = "/#{client_id}/insights"
301
+ path += "/#{metric_path}" if metric_path
243
302
 
244
- self.perform_get(path, {
245
- :access_token => app_access_token
246
- }.merge(options || {}))
247
- end
303
+ self.perform_get(path, {
304
+ :access_token => app_access_token
305
+ }.merge(options || {}))
306
+ end
248
307
 
249
- def self.perform_get(uri, options = {})
250
- handle_response(get(uri, {:query => options}))
251
- end
308
+ def perform_get(uri, options = {})
309
+ handle_response(get(uri, {:query => options}))
310
+ end
252
311
 
253
- def self.perform_post(uri, options = {})
254
- handle_response(post(uri, {:body => options}))
255
- end
312
+ def perform_post(uri, options = {})
313
+ handle_response(post(uri, {:body => options}))
314
+ end
256
315
 
257
- def self.perform_delete(uri, options = {})
258
- handle_response(delete(uri, {:body => options}))
259
- end
316
+ def perform_delete(uri, options = {})
317
+ handle_response(delete(uri, {:body => options}))
318
+ end
260
319
 
261
- def self.handle_response(response)
262
- # Check for error
263
- return response unless response['error']
264
-
265
- case response['error']['type']
266
- when 'QueryParseException'
267
- raise QueryParseError, response['error']
268
- when 'GraphMethodException'
269
- raise GraphMethodError, response['error']
270
- when 'OAuthException'
271
- raise OAuthError, response['error']
272
- when 'OAuthAccessTokenException'
273
- raise OAuthAccessTokenError, response['error']
320
+ def handle_response(response)
321
+ unless response['error']
322
+ return FGraph::Collection.new(response) if response['data']
323
+ response
274
324
  else
275
- raise FacebookError, response['error']
325
+ case response['error']['type']
326
+ when 'QueryParseException'
327
+ raise QueryParseError, response['error']
328
+ when 'GraphMethodException'
329
+ raise GraphMethodError, response['error']
330
+ when 'OAuthException'
331
+ raise OAuthError, response['error']
332
+ when 'OAuthAccessTokenException'
333
+ raise OAuthAccessTokenError, response['error']
334
+ else
335
+ raise FacebookError, response['error']
336
+ end
337
+ end
276
338
  end
277
- end
278
339
 
279
- def self.format_url(path, options={})
280
- url = self.base_uri.dup
281
- url << path
282
- unless options.blank?
283
- url << "?"
340
+ def format_url(path, options={})
341
+ url = self.base_uri.dup
342
+ url << path
343
+ unless options.blank?
344
+ url << "?"
284
345
 
285
- option_count = 0
346
+ option_count = 0
286
347
 
287
- stringified_options = {}
288
- options.each do |key, value|
289
- stringified_options[key.to_s] = value
290
- end
291
- options = stringified_options
348
+ stringified_options = {}
349
+ options.each do |key, value|
350
+ stringified_options[key.to_s] = value
351
+ end
352
+ options = stringified_options
292
353
 
293
- options.each do |option|
294
- next if option[1].blank?
295
- url << "&" if option_count > 0
296
- url << "#{option[0]}=#{CGI.escape(option[1].to_s)}"
297
- option_count += 1
354
+ options.each do |option|
355
+ next if option[1].blank?
356
+ url << "&" if option_count > 0
357
+ url << "#{option[0]}=#{CGI.escape(option[1].to_s)}"
358
+ option_count += 1
359
+ end
298
360
  end
361
+ url
299
362
  end
300
- url
301
- end
302
363
 
303
- def self.method_missing(name, *args, &block)
304
- names = name.to_s.split('_')
305
- super unless names.length > 1
364
+ def method_missing(name, *args, &block)
365
+ names = name.to_s.split('_')
366
+ super unless names.length > 1
306
367
 
307
- case names.shift
308
- when 'object'
309
- # object_photos
310
- self.object("#{args[0]}/#{names[0]}", args[1])
311
- when 'me'
312
- # me_photos
313
- self.me(names[0], args[0])
314
- when 'publish'
315
- # publish_feed(id)
316
- self.publish("#{args[0]}/#{names[0]}", args[1])
317
- when 'remove'
318
- # remove_feed(id)
319
- self.remove("#{args[0]}/#{names[0]}", args[1])
320
- when 'search'
321
- # search_user(query)
322
- options = args[1] || {}
323
- options[:type] = names[0]
324
- self.search(args[0], options)
325
- else
326
- super
368
+ case names.shift
369
+ when 'object'
370
+ # object_photos
371
+ self.object("#{args[0]}/#{names[0]}", args[1])
372
+ when 'me'
373
+ # me_photos
374
+ self.me(names[0], args[0])
375
+ when 'publish'
376
+ # publish_feed(id)
377
+ self.publish("#{args[0]}/#{names[0]}", args[1])
378
+ when 'remove'
379
+ # remove_feed(id)
380
+ self.remove("#{args[0]}/#{names[0]}", args[1])
381
+ when 'search'
382
+ # search_user(query)
383
+ options = args[1] || {}
384
+ options[:type] = names[0]
385
+ self.search(args[0], options)
386
+ else
387
+ super
388
+ end
389
+ end
390
+
391
+ # Return ID['id'] if ID is a hash object
392
+ #
393
+ def get_id(id)
394
+ return unless id
395
+ id = id['id'] if id.is_a?(Hash)
396
+ id
327
397
  end
328
398
  end
329
399
  end
@@ -0,0 +1,15 @@
1
+ require 'fileutils'
2
+
3
+ namespace :fgraph do
4
+ desc "Create fgraph.yml configuration file in Rails config folder"
5
+ task :setup => :environment do
6
+ fgraph_config = File.join(RAILS_ROOT, "config", "fgraph.yml")
7
+ unless File.exist?(fgraph_config)
8
+ fgraph_config_template = File.join(RAILS_ROOT, "vendor", "plugins", "fgraph", "templates", "fgraph.yml")
9
+ FileUtils.cp fgraph_config_teirmplate, fgraph_config
10
+ puts "#{RAILS_ROOT}/config/fgraph.yml created, please update your app_id and app_secret."
11
+ else
12
+ puts "#{RAILS_ROOT}/config/fgraph.yml already exists."
13
+ end
14
+ end
15
+ end
@@ -0,0 +1 @@
1
+ load 'tasks/fgraph.rake'
data/rails/init.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'fgraph'
2
+ require 'fgraph/rails/fgraph_helper'
3
+ require 'fgraph/rails/fgraph_tag_helper'
4
+
5
+ FGRAPH_CONFIG = "#{RAILS_ROOT}/config/fgraph.yml"
6
+
7
+ # Load configuration file
8
+ if File.exists?(FGRAPH_CONFIG)
9
+ fgraph_config = YAML.load(ERB.new(File.read(FGRAPH_CONFIG)).result)
10
+ FGraph.config = fgraph_config[RAILS_ENV]
11
+ end
12
+
13
+ ActionController::Base.send :include, FGraph::Rails::FGraphHelper
14
+ ActionView::Base.send :include, FGraph::Rails::FGraphHelper
15
+ ActionView::Base.send :include, FGraph::Rails::FGraphTagHelper
data/rails/install.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'fileutil'
3
+
4
+ fgraph_config = File.join(RAILS_ROOT, "config", "fgraph.yml")
5
+ unless File.exist?(fgraph_config)
6
+ fgraph_config_template = File.join(RAILS_ROOT, "vendor", "plugins", "fgraph", "templates", "fgraph.yml")
7
+ FileUtils.cp fgraph_config_template, fgraph_config
8
+ puts "#{RAILS_ROOT}/config/fgraph.yml created, please update your app_id and app_secret."
9
+ end
@@ -0,0 +1,16 @@
1
+ # FGraph Facebook Configuration File
2
+ #
3
+ # Register your application to get your app_id and app_secret:
4
+ # http://developers.facebook.com/setup/
5
+ #
6
+ development:
7
+ app_id:
8
+ app_secret:
9
+
10
+ test:
11
+ app_id:
12
+ app_secret:
13
+
14
+ production:
15
+ app_id:
16
+ app_secret:
data/test/fgraph_test.rb CHANGED
@@ -8,6 +8,20 @@ class FGraphTest < Test::Unit::TestCase
8
8
  FACEBOOK_OAUTH_ACCESS_TOKEN = "115187085478818|rDIv_5zgjCSM_fWBv5Z-lQr5gFk."
9
9
  FACEBOOK_OAUTH_APP_ACCESS_TOKEN = "112167085478818|rDIv_5zgjCSM_fWBv5Z-lQr5gFk."
10
10
 
11
+ context "FGraph.get_id" do
12
+ should "return 'id' if input 'id' is not a Hash" do
13
+ test_id = '123'
14
+ id = FGraph.get_id(test_id)
15
+ id.should == test_id
16
+ end
17
+
18
+ should "return 'id' value from hash object if input 'id' is a Hash" do
19
+ test_id = { 'name' => 'Anthony', 'id' => '123' }
20
+ id = FGraph.get_id(test_id)
21
+ id.should == test_id['id']
22
+ end
23
+ end
24
+
11
25
  context "FGraph.object" do
12
26
  should "return object hash" do
13
27
  stub_get('/cocacola', 'object_cocacola.json')
@@ -28,13 +42,29 @@ class FGraphTest < Test::Unit::TestCase
28
42
  FGraph.expects(:perform_get).with('/cocacola', options)
29
43
  FGraph.object('cocacola', options)
30
44
  end
45
+
46
+ should "call FGraph.get_id" do
47
+ stub_get('/cocacola', 'object_cocacola.json')
48
+ FGraph.expects(:get_id).with('cocacola')
49
+ FGraph.expects(:perform_get)
50
+ object = FGraph.object('cocacola')
51
+ end
31
52
  end
32
53
 
33
54
  context "FGraph.objects" do
34
55
  should "call perform_get with ids and query options" do
35
56
  options = {:fields => 'id,name'}
36
- FGraph.expects(:perform_get).with('/', options.merge(:ids => 'herry,john'))
37
- FGraph.objects('herry', 'john', options)
57
+ FGraph.expects(:perform_get).with('/', options.merge(:ids => '1,2'))
58
+ FGraph.objects('1', '2', options)
59
+ end
60
+
61
+ should "collect id values if input is an array of hash values" do
62
+ test_ids = [
63
+ { 'name' => 'Herry', 'id' => '1'},
64
+ { 'name' => 'John', 'id' => '2'}
65
+ ]
66
+ FGraph.expects(:perform_get).with('/', :ids => '1,2')
67
+ FGraph.objects(test_ids)
38
68
  end
39
69
  end
40
70
 
@@ -204,6 +234,28 @@ class FGraphTest < Test::Unit::TestCase
204
234
  end
205
235
 
206
236
  context "FGraph.handle_response" do
237
+ should "return response object if there's no error" do
238
+ fb_response = {'name' => 'test'}
239
+ response = FGraph.handle_response(fb_response)
240
+ response.should == fb_response
241
+ end
242
+
243
+ should "convert to FGraph::Collection object if response contain 'data' value" do
244
+ fb_response = {
245
+ "data" => [
246
+ { "name" =>"Belle Clara", "id" => "100000133774483" },
247
+ { "name" =>"Rosemary Schapira", "id" => "100000237306697" }
248
+ ],
249
+ "paging" => {
250
+ "next" => "https://graph.facebook.com/756314021/friends?offset=4&limit=2&access_token=101507589896698"
251
+ }
252
+ }
253
+
254
+ collection = FGraph.handle_response(fb_response)
255
+ collection.class.should == FGraph::Collection
256
+ collection.count.should == fb_response['data'].count
257
+ end
258
+
207
259
  should "raise QueryParseError" do
208
260
  lambda do
209
261
  object = FGraph.handle_response(response_error('QueryParseException'))
@@ -229,6 +281,29 @@ class FGraphTest < Test::Unit::TestCase
229
281
  end
230
282
  end
231
283
 
284
+ context "FGraph::Collection" do
285
+ should "should convert response object to Collection" do
286
+ response = {
287
+ "data" => [
288
+ {"name"=>"Belle Clara", "id"=>"100000133774483"},
289
+ {"name"=>"Rosemary Schapira", "id"=>"100000237306697"}
290
+ ],
291
+ "paging"=> {
292
+ "previous"=> "https://graph.facebook.com/756314021/friends?offset=0&limit=2&access_token=101507589896698",
293
+ "next"=> "https://graph.facebook.com/756314021/friends?offset=4&limit=2&access_token=101507589896698"
294
+ }
295
+ }
296
+
297
+ collection = FGraph::Collection.new(response)
298
+ collection.count.should == response['data'].count
299
+ collection.first.should == response['data'].first
300
+ collection.next_url.should == response['paging']['next']
301
+ collection.previous_url.should == response['paging']['previous']
302
+ collection.previous_options.should == {'offset' => '0', 'limit' => '2', 'access_token' => '101507589896698'}
303
+ collection.next_options.should == {'offset' => '4', 'limit' => '2', 'access_token' => '101507589896698'}
304
+ end
305
+ end
306
+
232
307
  def response_error(type, msg=nil)
233
308
  {'error' => { 'type' => type, 'message' => msg}}
234
309
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 5
9
- version: 0.1.5
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Herryanto Siatono
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-25 00:00:00 +08:00
17
+ date: 2010-05-26 00:00:00 +08:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -107,6 +107,11 @@ files:
107
107
  - lib/fgraph/client.rb
108
108
  - lib/fgraph/rails/fgraph_helper.rb
109
109
  - lib/fgraph/rails/fgraph_tag_helper.rb
110
+ - lib/tasks/fgraph.rake
111
+ - lib/tasks/fgraph.rb
112
+ - rails/init.rb
113
+ - rails/install.rb
114
+ - templates/fgraph.yml
110
115
  - test/fgraph/client_test.rb
111
116
  - test/fgraph_test.rb
112
117
  - test/fixtures/access_token.txt