fgraph 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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