facebooker 1.0.31 → 1.0.41

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.
Files changed (43) hide show
  1. data/CHANGELOG.rdoc +7 -0
  2. data/Manifest.txt +5 -0
  3. data/README.rdoc +9 -0
  4. data/facebooker.gemspec +8 -9
  5. data/generators/facebook/templates/public/javascripts/facebooker.js +10 -16
  6. data/init.rb +4 -1
  7. data/install.rb +1 -1
  8. data/lib/facebooker.rb +75 -20
  9. data/lib/facebooker/adapters/bebo_adapter.rb +9 -9
  10. data/lib/facebooker/data.rb +14 -14
  11. data/lib/facebooker/models/page.rb +16 -0
  12. data/lib/facebooker/models/photo.rb +7 -0
  13. data/lib/facebooker/models/user.rb +75 -28
  14. data/lib/facebooker/parser.rb +187 -127
  15. data/lib/facebooker/rails/backwards_compatible_param_checks.rb +31 -0
  16. data/lib/facebooker/rails/controller.rb +30 -7
  17. data/lib/facebooker/rails/extensions/rack_setup.rb +5 -1
  18. data/lib/facebooker/rails/facebook_request_fix.rb +5 -5
  19. data/lib/facebooker/rails/facebook_request_fix_2-3.rb +31 -0
  20. data/lib/facebooker/rails/facebook_url_rewriting.rb +7 -2
  21. data/lib/facebooker/rails/helpers.rb +29 -5
  22. data/lib/facebooker/rails/helpers/fb_connect.rb +14 -5
  23. data/lib/facebooker/rails/publisher.rb +26 -12
  24. data/lib/facebooker/service.rb +64 -56
  25. data/lib/facebooker/session.rb +56 -22
  26. data/lib/facebooker/version.rb +1 -1
  27. data/lib/rack/facebook.rb +26 -14
  28. data/lib/tasks/tunnel.rake +1 -1
  29. data/test/facebooker/adapters_test.rb +78 -0
  30. data/test/facebooker/data_test.rb +14 -14
  31. data/test/facebooker/models/page_test.rb +46 -0
  32. data/test/facebooker/models/photo_test.rb +16 -0
  33. data/test/facebooker/models/user_test.rb +83 -48
  34. data/test/facebooker/rails/facebook_request_fix_2-3_test.rb +25 -0
  35. data/test/facebooker/rails/facebook_url_rewriting_test.rb +39 -0
  36. data/test/facebooker/rails/publisher_test.rb +5 -1
  37. data/test/facebooker/rails_integration_test.rb +52 -8
  38. data/test/facebooker/service_test.rb +58 -0
  39. data/test/facebooker/session_test.rb +106 -92
  40. data/test/facebooker_test.rb +2 -2
  41. data/test/rack/facebook_test.rb +4 -4
  42. data/test/test_helper.rb +10 -3
  43. metadata +14 -4
@@ -8,5 +8,12 @@ module Facebooker
8
8
  :story_fbid
9
9
 
10
10
  id_is :pid
11
+
12
+ #override the generated method for id_is to use a string
13
+ def pid=(val)
14
+ @pid = val
15
+ end
16
+
17
+ alias :id= :pid=
11
18
  end
12
19
  end
@@ -10,7 +10,7 @@ module Facebooker
10
10
  include Model
11
11
  attr_accessor :message, :time, :status_id
12
12
  end
13
- FIELDS = [:political, :pic_small, :name, :quotes, :is_app_user, :tv, :profile_update_time, :meeting_sex, :hs_info, :timezone, :relationship_status, :hometown_location, :about_me, :wall_count, :significant_other_id, :pic_big, :music, :work_history, :sex, :religion, :notes_count, :activities, :pic_square, :movies, :has_added_app, :education_history, :birthday, :first_name, :meeting_for, :last_name, :interests, :current_location, :pic, :books, :affiliations, :locale, :profile_url, :proxied_email, :email_hashes, :allowed_restrictions, :pic_with_logo, :pic_big_with_logo, :pic_small_with_logo, :pic_square_with_logo]
13
+ FIELDS = [:status, :political, :pic_small, :name, :quotes, :is_app_user, :tv, :profile_update_time, :meeting_sex, :hs_info, :timezone, :relationship_status, :hometown_location, :about_me, :wall_count, :significant_other_id, :pic_big, :music, :work_history, :sex, :religion, :notes_count, :activities, :pic_square, :movies, :has_added_app, :education_history, :birthday, :first_name, :meeting_for, :last_name, :interests, :current_location, :pic, :books, :affiliations, :locale, :profile_url, :proxied_email, :email_hashes, :allowed_restrictions, :pic_with_logo, :pic_big_with_logo, :pic_small_with_logo, :pic_square_with_logo]
14
14
  STANDARD_FIELDS = [:uid, :first_name, :last_name, :name, :timezone, :birthday, :sex, :affiliations, :locale, :profile_url, :pic_square]
15
15
  populating_attr_accessor(*FIELDS)
16
16
  attr_reader :affiliations
@@ -69,47 +69,88 @@ module Facebooker
69
69
  # Set the list of friends, given an array of User objects. If the list has been retrieved previously, will not set
70
70
  def friends=(list_of_friends,flid=nil)
71
71
  @friends_hash ||= {}
72
- flid=cast_to_friend_list_id(flid)
73
- #use __blank instead of nil so that this is cached
74
- cache_key = flid||"__blank"
75
-
72
+ flid=cast_to_friend_list_id(flid)
73
+ #use __blank instead of nil so that this is cached
74
+ cache_key = flid||"__blank"
75
+
76
76
  @friends_hash[cache_key] ||= list_of_friends
77
77
  end
78
78
 
79
79
  def cast_to_friend_list_id(flid)
80
80
  case flid
81
- when String
82
- list=friend_lists.detect {|f| f.name==flid}
83
- raise Facebooker::Session::InvalidFriendList unless list
84
- list.flid
85
- when FriendList
86
- flid.flid
87
- else
88
- flid
89
- end
90
- end
81
+ when String
82
+ list=friend_lists.detect {|f| f.name==flid}
83
+ raise Facebooker::Session::InvalidFriendList unless list
84
+ list.flid
85
+ when FriendList
86
+ flid.flid
87
+ else
88
+ flid
89
+ end
90
+ end
91
91
  ##
92
92
  # Retrieve friends
93
93
  def friends(flid = nil)
94
- @friends_hash ||= {}
95
- flid=cast_to_friend_list_id(flid)
96
-
97
- #use __blank instead of nil so that this is cached
98
- cache_key = flid||"__blank"
99
- options = {:uid=>self.id}
100
- options[:flid] = flid unless flid.nil?
101
- @friends_hash[cache_key] ||= @session.post('facebook.friends.get', options,false).map do |uid|
94
+ @friends_hash ||= {}
95
+ flid=cast_to_friend_list_id(flid)
96
+
97
+ #use __blank instead of nil so that this is cached
98
+ cache_key = flid||"__blank"
99
+ options = {:uid=>self.id}
100
+ options[:flid] = flid unless flid.nil?
101
+ @friends_hash[cache_key] ||= @session.post('facebook.friends.get', options,false).map do |uid|
102
102
  User.new(uid, @session)
103
103
  end
104
104
  @friends_hash[cache_key]
105
105
  end
106
+
107
+ ###
108
+ # Publish a post into the stream on the user's Wall and News Feed. This
109
+ # post also appears in the user's friend's streams. The +publish_stream+
110
+ # extended permission must be granted in order to use this method.
111
+ #
112
+ # See: http://wiki.developers.facebook.com/index.php/Stream.publish
113
+ #
114
+ # +target+ can be the current user or some other user.
115
+ #
116
+ # Example:
117
+ # # Publish a message to my own wall:
118
+ # me.publish_to(me, :message => 'hello world')
119
+ #
120
+ # # Publish to a friend's wall with an action link:
121
+ # me.publish_to(my_friend, :message => 'how are you?', :action_links => [
122
+ # :text => 'my website',
123
+ # :href => 'http://tenderlovemaking.com/'
124
+ # ])
125
+ def publish_to target, options = {}
126
+ @session.post('facebook.stream.publish',
127
+ :uid => self.id,
128
+ :target_id => target.id,
129
+ :message => options[:message],
130
+ :attachment => Facebooker.json_encode(options[:attachment]),
131
+ :action_links => Facebooker.json_encode(options[:action_links])
132
+ )
133
+ end
106
134
 
107
- def friend_lists
135
+
136
+ ###
137
+ # Publish a comment on a post
138
+ #
139
+ # See: http://wiki.developers.facebook.com/index.php/Stream.addComment
140
+ #
141
+ # +post_id+ the post_id for the post that is being commented on
142
+ # +comment+ the text of the comment
143
+ def comment_on(post_id, comment)
144
+ @session.post('facebook.stream.addComment', {:post_id=>post_id, :comment=>comment})
145
+ end
146
+
147
+
148
+ def friend_lists
108
149
  @friend_lists ||= @session.post('facebook.friends.getLists').map do |hash|
109
- friend_list = FriendList.from_hash(hash)
110
- friend_list.session = session
111
- friend_list
112
- end
150
+ friend_list = FriendList.from_hash(hash)
151
+ friend_list.session = session
152
+ friend_list
153
+ end
113
154
  end
114
155
  ###
115
156
  # Retrieve friends with user info populated
@@ -323,6 +364,12 @@ module Facebooker
323
364
  session.post('facebook.users.hasAppPermission',:ext_perm=>ext_perm) == "1"
324
365
  end
325
366
 
367
+ ##
368
+ # Convenience method to check multiple permissions at once
369
+ def has_permissions?(ext_perms)
370
+ ext_perms.all?{|p| has_permission?(p)}
371
+ end
372
+
326
373
  ##
327
374
  # Convenience method to send email to the current user
328
375
  def send_email(subject, text=nil, fbml=nil)
@@ -2,34 +2,50 @@ require 'rexml/document'
2
2
  require 'facebooker/session'
3
3
  module Facebooker
4
4
  class Parser
5
-
6
- module REXMLElementExtensions
7
- def text_value
8
- self.children.first.to_s.strip
5
+
6
+ module REXMLElementExtensions # :nodoc:
7
+ def content
8
+ self.text || ''
9
+ end
10
+
11
+ def [] key
12
+ attributes[key]
13
+ end
14
+
15
+ def text?
16
+ false
17
+ end
18
+ end
19
+
20
+ module REXMLTextExtensions # :nodoc:
21
+ def text?
22
+ true
9
23
  end
10
24
  end
11
-
25
+
12
26
  ::REXML::Element.__send__(:include, REXMLElementExtensions)
13
-
27
+ ::REXML::Text.__send__(:include, REXMLTextExtensions)
28
+
14
29
  def self.parse(method, data)
15
30
  Errors.process(data)
16
31
  parser = Parser::PARSERS[method]
17
- parser.process(
18
- data
19
- )
32
+ raise "Can't find a parser for '#{method}'" unless parser
33
+ parser.process(data)
20
34
  end
21
-
35
+
22
36
  def self.array_of(response_element, element_name)
23
37
  values_to_return = []
24
- response_element.elements.each(element_name) do |element|
38
+ response_element.children.each do |element|
39
+ next if element.text?
40
+ next unless element.name == element_name
25
41
  values_to_return << yield(element)
26
42
  end
27
43
  values_to_return
28
44
  end
29
-
45
+
30
46
  def self.array_of_text_values(response_element, element_name)
31
47
  array_of(response_element, element_name) do |element|
32
- element.text_value
48
+ element.content.strip
33
49
  end
34
50
  end
35
51
 
@@ -38,75 +54,85 @@ module Facebooker
38
54
  hashinate(element)
39
55
  end
40
56
  end
41
-
57
+
42
58
  def self.element(name, data)
43
59
  data = data.body rescue data # either data or an HTTP response
44
- doc = REXML::Document.new(data)
45
- doc.elements.each(name) do |element|
46
- return element
60
+ begin
61
+ xml = Nokogiri::XML(data.strip).at(name)
62
+ if node = xml.at(name)
63
+ return node
64
+ end
65
+ if xml.root.name == name
66
+ return xml.root
67
+ end
68
+ rescue # Can't parse with Nokogiri
69
+ doc = REXML::Document.new(data)
70
+ doc.elements.each(name) do |element|
71
+ return element
72
+ end
47
73
  end
48
74
  raise "Element #{name} not found in #{data}"
49
75
  end
50
-
76
+
51
77
  def self.hash_or_value_for(element)
52
- if element.children.size == 1 && element.children.first.kind_of?(REXML::Text)
53
- element.text_value
78
+ if element.children.size == 1 && element.children.first.text?
79
+ element.content.strip
54
80
  else
55
81
  hashinate(element)
56
82
  end
57
83
  end
58
-
84
+
59
85
  def self.hashinate(response_element)
60
- response_element.children.reject{|c| c.kind_of? REXML::Text}.inject({}) do |hash, child|
86
+ response_element.children.reject{|c| c.text? }.inject({}) do |hash, child|
61
87
  # If the node hasn't any child, and is not a list, we want empty strings, not empty hashes,
62
88
  # except if attributes['nil'] == true
63
- hash[child.name] =
64
- if (child.attributes['nil'] == 'true')
65
- nil
66
- elsif (child.children.size == 1 && child.children.first.kind_of?(REXML::Text)) || (child.children.size == 0 && child.attributes['list'] != 'true')
67
- anonymous_field_from(child, hash) || child.text_value
68
- elsif child.attributes['list'] == 'true'
69
- child.children.reject{|c| c.kind_of? REXML::Text}.map { |subchild| hash_or_value_for(subchild)}
89
+ hash[child.name] =
90
+ if (child['nil'] == 'true')
91
+ nil
92
+ elsif (child.children.size == 1 && child.children.first.text?) || (child.children.size == 0 && child['list'] != 'true')
93
+ anonymous_field_from(child, hash) || child.content.strip
94
+ elsif child['list'] == 'true'
95
+ child.children.reject{|c| c.text? }.map { |subchild| hash_or_value_for(subchild)}
70
96
  else
71
- child.children.reject{|c| c.kind_of? REXML::Text}.inject({}) do |subhash, subchild|
97
+ child.children.reject{|c| c.text? }.inject({}) do |subhash, subchild|
72
98
  subhash[subchild.name] = hash_or_value_for(subchild)
73
99
  subhash
74
100
  end
75
101
  end #if (child.attributes)
76
102
  hash
77
- end #do |hash, child|
103
+ end #do |hash, child|
78
104
  end
79
-
105
+
80
106
  def self.booleanize(response)
81
107
  response == "1" ? true : false
82
108
  end
83
-
109
+
84
110
  def self.anonymous_field_from(child, hash)
85
111
  if child.name == 'anon'
86
- (hash[child.name] || []) << child.text_value
112
+ (hash[child.name] || []) << child.content.strip
87
113
  end
88
114
  end
89
-
90
- end
91
-
115
+
116
+ end
117
+
92
118
  class RevokeAuthorization < Parser#:nodoc:
93
119
  def self.process(data)
94
120
  booleanize(data)
95
121
  end
96
122
  end
97
-
123
+
98
124
  class CreateToken < Parser#:nodoc:
99
125
  def self.process(data)
100
- element('auth_createToken_response', data).text_value
126
+ element('auth_createToken_response', data).content.strip
101
127
  end
102
128
  end
103
-
129
+
104
130
  class RegisterUsers < Parser
105
131
  def self.process(data)
106
132
  array_of_text_values(element("connect_registerUsers_response", data), "connect_registerUsers_response_elt")
107
133
  end
108
134
  end
109
-
135
+
110
136
  class UnregisterUsers < Parser
111
137
  def self.process(data)
112
138
  array_of_text_values(element("connect_unregisterUsers_response", data), "connect_unregisterUsers_response_elt")
@@ -115,49 +141,49 @@ module Facebooker
115
141
 
116
142
  class GetUnconnectedFriendsCount < Parser
117
143
  def self.process(data)
118
- hash_or_value_for(element("connect_getUnconnectedFriendsCount_response",data)).to_i
144
+ hash_or_value_for(element("connect_getUnconnectedFriendsCount_response",data)).to_i
119
145
  end
120
146
  end
121
147
 
122
148
  class GetSession < Parser#:nodoc:
123
- def self.process(data)
149
+ def self.process(data)
124
150
  hashinate(element('auth_getSession_response', data))
125
151
  end
126
152
  end
127
-
153
+
128
154
  class GetFriends < Parser#:nodoc:
129
155
  def self.process(data)
130
156
  array_of_text_values(element('friends_get_response', data), 'uid')
131
157
  end
132
158
  end
133
-
159
+
134
160
  class FriendListsGet < Parser#:nodoc:
135
161
  def self.process(data)
136
162
  array_of_hashes(element('friends_getLists_response', data), 'friendlist')
137
163
  end
138
164
  end
139
-
165
+
140
166
  class UserInfo < Parser#:nodoc:
141
167
  def self.process(data)
142
168
  array_of_hashes(element('users_getInfo_response', data), 'user')
143
169
  end
144
170
  end
145
-
171
+
146
172
  class UserStandardInfo < Parser#:nodoc:
147
173
  def self.process(data)
148
174
  array_of_hashes(element('users_getStandardInfo_response', data), 'standard_user_info')
149
175
  end
150
176
  end
151
-
177
+
152
178
  class GetLoggedInUser < Parser#:nodoc:
153
179
  def self.process(data)
154
- Integer(element('users_getLoggedInUser_response', data).text_value)
180
+ Integer(element('users_getLoggedInUser_response', data).content.strip)
155
181
  end
156
182
  end
157
183
 
158
184
  class PagesIsAdmin < Parser#:nodoc:
159
185
  def self.process(data)
160
- element('pages_isAdmin_response', data).text_value == '1'
186
+ element('pages_isAdmin_response', data).content.strip == '1'
161
187
  end
162
188
  end
163
189
 
@@ -166,22 +192,34 @@ module Facebooker
166
192
  array_of_hashes(element('pages_getInfo_response', data), 'page')
167
193
  end
168
194
  end
169
-
195
+
170
196
  class PagesIsFan < Parser#:nodoc:
171
197
  def self.process(data)
172
- element('pages_isFan_response', data).text_value == '1'
198
+ element('pages_isFan_response', data).content.strip == '1'
173
199
  end
174
- end
200
+ end
175
201
 
176
202
  class PublishStoryToUser < Parser#:nodoc:
177
203
  def self.process(data)
178
- element('feed_publishStoryToUser_response', data).text_value
204
+ element('feed_publishStoryToUser_response', data).content.strip
179
205
  end
180
206
  end
181
207
 
208
+ class StreamPublish < Parser#:nodoc:
209
+ def self.process(data)
210
+ element('stream_publish_response', data).content.strip
211
+ end
212
+ end
213
+
214
+ class StreamAddComment < Parser#:nodoc:
215
+ def self.process(data)
216
+ element('stream_addComment_response', data).content.strip
217
+ end
218
+ end
219
+
182
220
  class RegisterTemplateBundle < Parser#:nodoc:
183
221
  def self.process(data)
184
- element('feed_registerTemplateBundle_response', data).text_value.to_i
222
+ element('feed_registerTemplateBundle_response', data).content.to_i
185
223
  end
186
224
  end
187
225
 
@@ -193,58 +231,58 @@ module Facebooker
193
231
 
194
232
  class DeactivateTemplateBundleByID < Parser#:nodoc:
195
233
  def self.process(data)
196
- element('feed_deactivateTemplateBundleByID_response', data).text_value == '1'
234
+ element('feed_deactivateTemplateBundleByID_response', data).content.strip == '1'
197
235
  end
198
236
  end
199
237
 
200
238
  class PublishUserAction < Parser#:nodoc:
201
239
  def self.process(data)
202
- element('feed_publishUserAction_response', data).children[1].text_value == "1"
240
+ element('feed_publishUserAction_response', data).children[1].content.strip == "1"
203
241
  end
204
242
  end
205
-
243
+
206
244
  class PublishActionOfUser < Parser#:nodoc:
207
245
  def self.process(data)
208
- element('feed_publishActionOfUser_response', data).text_value
246
+ element('feed_publishActionOfUser_response', data).content.strip
209
247
  end
210
248
  end
211
-
249
+
212
250
  class PublishTemplatizedAction < Parser#:nodoc:
213
251
  def self.process(data)
214
- element('feed_publishTemplatizedAction_response', data).children[1].text_value
252
+ element('feed_publishTemplatizedAction_response', data).children[1].content.strip
215
253
  end
216
254
  end
217
-
255
+
218
256
  class SetAppProperties < Parser#:nodoc:
219
257
  def self.process(data)
220
- element('admin_setAppProperties_response', data).text_value
258
+ element('admin_setAppProperties_response', data).content.strip
221
259
  end
222
- end
223
-
260
+ end
261
+
224
262
  class GetAppProperties < Parser#:nodoc:
225
263
  def self.process(data)
226
- element('admin_getAppProperties_response', data).text_value
264
+ element('admin_getAppProperties_response', data).content.strip
227
265
  end
228
266
  end
229
-
267
+
230
268
  class SetRestrictionInfo < Parser#:nodoc:
231
269
  def self.process(data)
232
- element('admin_setRestrictionInfo_response', data).text_value
270
+ element('admin_setRestrictionInfo_response', data).content.strip
233
271
  end
234
- end
235
-
272
+ end
273
+
236
274
  class GetRestrictionInfo < Parser#:nodoc:
237
275
  def self.process(data)
238
- element('admin_getRestrictionInfo_response', data).text_value
276
+ element('admin_getRestrictionInfo_response', data).content.strip
239
277
  end
240
278
  end
241
-
279
+
242
280
  class GetAllocation < Parser#:nodoc:
243
281
  def self.process(data)
244
- element('admin_getAllocation_response', data).text_value
282
+ element('admin_getAllocation_response', data).content.strip
245
283
  end
246
284
  end
247
-
285
+
248
286
  class BatchRun < Parser #:nodoc:
249
287
  class << self
250
288
  def current_batch=(current_batch)
@@ -267,28 +305,28 @@ module Facebooker
267
305
  end
268
306
  end
269
307
  end
270
-
308
+
271
309
  class GetAppUsers < Parser#:nodoc:
272
310
  def self.process(data)
273
311
  array_of_text_values(element('friends_getAppUsers_response', data), 'uid')
274
312
  end
275
313
  end
276
-
314
+
277
315
  class NotificationsGet < Parser#:nodoc:
278
316
  def self.process(data)
279
317
  hashinate(element('notifications_get_response', data))
280
318
  end
281
319
  end
282
-
320
+
283
321
  class NotificationsSend < Parser#:nodoc:
284
322
  def self.process(data)
285
- element('notifications_send_response', data).text_value
323
+ element('notifications_send_response', data).content.strip
286
324
  end
287
- end
325
+ end
288
326
 
289
327
  class NotificationsSendEmail < Parser#:nodoc:
290
- def self.process(data)
291
- element('notifications_sendEmail_response', data).text_value
328
+ def self.process(data)
329
+ element('notifications_sendEmail_response', data).content.strip
292
330
  end
293
331
  end
294
332
 
@@ -297,7 +335,7 @@ module Facebooker
297
335
  array_of_hashes(element('photos_getTags_response', data), 'photo_tag')
298
336
  end
299
337
  end
300
-
338
+
301
339
  class AddTags < Parser#nodoc:
302
340
  def self.process(data)
303
341
  element('photos_addTag_response', data)
@@ -309,19 +347,19 @@ module Facebooker
309
347
  array_of_hashes(element('photos_get_response', data), 'photo')
310
348
  end
311
349
  end
312
-
350
+
313
351
  class GetAlbums < Parser#nodoc:
314
352
  def self.process(data)
315
353
  array_of_hashes(element('photos_getAlbums_response', data), 'album')
316
354
  end
317
355
  end
318
-
356
+
319
357
  class CreateAlbum < Parser#:nodoc:
320
358
  def self.process(data)
321
359
  hashinate(element('photos_createAlbum_response', data))
322
360
  end
323
- end
324
-
361
+ end
362
+
325
363
  class UploadPhoto < Parser#:nodoc:
326
364
  def self.process(data)
327
365
  hashinate(element('photos_upload_response', data))
@@ -333,81 +371,100 @@ module Facebooker
333
371
  hashinate(element('video_upload_response', data))
334
372
  end
335
373
  end
336
-
374
+
337
375
  class SendRequest < Parser#:nodoc:
338
376
  def self.process(data)
339
- element('notifications_sendRequest_response', data).text_value
377
+ element('notifications_sendRequest_response', data).content.strip
340
378
  end
341
379
  end
342
-
380
+
343
381
  class ProfileFBML < Parser#:nodoc:
344
382
  def self.process(data)
345
- element('profile_getFBML_response', data).text_value
383
+ element('profile_getFBML_response', data).content.strip
346
384
  end
347
385
  end
348
-
386
+
349
387
  class ProfileFBMLSet < Parser#:nodoc:
350
388
  def self.process(data)
351
- element('profile_setFBML_response', data).text_value
389
+ element('profile_setFBML_response', data).content.strip
352
390
  end
353
391
  end
354
-
392
+
355
393
  class ProfileInfo < Parser#:nodoc:
356
394
  def self.process(data)
357
395
  hashinate(element('profile_getInfo_response info_fields', data))
358
396
  end
359
397
  end
360
-
398
+
361
399
  class ProfileInfoSet < Parser#:nodoc:
362
400
  def self.process(data)
363
- element('profile_setInfo_response', data).text_value
401
+ element('profile_setInfo_response', data).content.strip
364
402
  end
365
403
  end
366
-
404
+
367
405
  class FqlQuery < Parser#nodoc
368
406
  def self.process(data)
369
407
  root = element('fql_query_response', data)
370
- first_child = root.children.reject{|c| c.kind_of?(REXML::Text)}.first
408
+ first_child = root.children.reject{|c| c.text? }.first
371
409
  first_child.nil? ? [] : [first_child.name, array_of_hashes(root, first_child.name)]
372
410
  end
373
411
  end
374
-
412
+
413
+ class FqlMultiquery < Parser#nodoc
414
+ def self.process(data)
415
+ root = element('fql_multiquery_response', data)
416
+ root.elements.collect do |elm|
417
+ [
418
+ elm.elements[1].text,
419
+ if elm.elements[2].elements[1].nil?
420
+ []
421
+ else
422
+ [
423
+ elm.elements[2].elements[1].name,
424
+ array_of_hashes(elm.elements[2], elm.elements[2].elements[1].name)
425
+ ]
426
+ end
427
+ ]
428
+ end
429
+ end
430
+ end
431
+
375
432
  class SetRefHandle < Parser#:nodoc:
376
433
  def self.process(data)
377
- element('fbml_setRefHandle_response', data).text_value
434
+ element('fbml_setRefHandle_response', data).content.strip
378
435
  end
379
436
  end
380
-
437
+
381
438
  class RefreshRefURL < Parser#:nodoc:
382
439
  def self.process(data)
383
- element('fbml_refreshRefUrl_response', data).text_value
440
+ element('fbml_refreshRefUrl_response', data).content.strip
384
441
  end
385
442
  end
386
-
443
+
387
444
  class RefreshImgSrc < Parser#:nodoc:
388
445
  def self.process(data)
389
- element('fbml_refreshImgSrc_response', data).text_value
446
+ element('fbml_refreshImgSrc_response', data).content.strip
390
447
  end
391
448
  end
392
-
449
+
393
450
  class SetCookie < Parser#:nodoc:
394
451
  def self.process(data)
395
- element('data_setCookie_response', data).text_value
452
+ element('data_setCookie_response', data).content.strip
396
453
  end
397
454
  end
398
-
455
+
399
456
  class GetCookies < Parser#:nodoc:
400
457
  def self.process(data)
401
458
  array_of_hashes(element('data_getCookie_response', data), 'cookies')
402
459
  end
403
460
  end
404
-
461
+
405
462
  class EventsGet < Parser#:nodoc:
406
463
  def self.process(data)
407
464
  array_of_hashes(element('events_get_response', data), 'event')
408
465
  end
409
466
  end
410
-
467
+
411
468
  class GroupGetMembers < Parser#:nodoc:
412
469
  def self.process(data)
413
470
  root = element('groups_getMembers_response', data)
@@ -417,10 +474,10 @@ module Facebooker
417
474
  {:position => position}.merge(:uid => uid)
418
475
  end
419
476
  end
420
- end.flatten
477
+ end.flatten
421
478
  end
422
479
  end
423
-
480
+
424
481
  class EventMembersGet < Parser#:nodoc:
425
482
  def self.process(data)
426
483
  root = element('events_getMembers_response', data)
@@ -433,13 +490,13 @@ module Facebooker
433
490
  end.flatten
434
491
  end
435
492
  end
436
-
493
+
437
494
  class GroupsGet < Parser#:nodoc:
438
495
  def self.process(data)
439
496
  array_of_hashes(element('groups_get_response', data), 'group')
440
497
  end
441
498
  end
442
-
499
+
443
500
  class AreFriends < Parser#:nodoc:
444
501
  def self.process(data)
445
502
  array_of_hashes(element('friends_areFriends_response', data), 'friend_info').inject({}) do |memo, hash|
@@ -459,40 +516,40 @@ module Facebooker
459
516
  end
460
517
  end
461
518
  end
462
-
519
+
463
520
  class SetStatus < Parser
464
521
  def self.process(data)
465
- element('users_setStatus_response',data).text_value == '1'
522
+ element('users_setStatus_response',data).content.strip == '1'
466
523
  end
467
524
  end
468
-
525
+
469
526
  class GetPreference < Parser#:nodoc:
470
527
  def self.process(data)
471
- element('data_getUserPreference_response', data).text_value
528
+ element('data_getUserPreference_response', data).content.strip
472
529
  end
473
530
  end
474
-
531
+
475
532
  class SetPreference < Parser#:nodoc:
476
533
  def self.process(data)
477
- element('data_setUserPreference_response', data).text_value
534
+ element('data_setUserPreference_response', data).content.strip
478
535
  end
479
536
  end
480
-
537
+
481
538
  class UserHasPermission < Parser
482
539
  def self.process(data)
483
- element('users_hasAppPermission_response', data).text_value
540
+ element('users_hasAppPermission_response', data).content.strip
484
541
  end
485
- end
542
+ end
486
543
 
487
544
  class SmsSend < Parser#:nodoc:
488
545
  def self.process(data)
489
- element('sms_send_response', data).text_value == '0'
546
+ element('sms_send_response', data).content.strip == '0'
490
547
  end
491
548
  end
492
-
549
+
493
550
  class SmsCanSend < Parser#:nodoc:
494
551
  def self.process(data)
495
- element('sms_canSend_response', data).text_value
552
+ element('sms_canSend_response', data).content.strip
496
553
  end
497
554
  end
498
555
 
@@ -521,7 +578,7 @@ module Facebooker
521
578
  345 => Facebooker::Session::BlankFeedTitle,
522
579
  346 => Facebooker::Session::FeedBodyLengthTooLong,
523
580
  347 => Facebooker::Session::InvalidFeedPhotoSource,
524
- 348 => Facebooker::Session::InvalidFeedPhotoLink,
581
+ 348 => Facebooker::Session::InvalidFeedPhotoLink,
525
582
  330 => Facebooker::Session::FeedMarkupInvalid,
526
583
  360 => Facebooker::Session::FeedTitleDataInvalid,
527
584
  361 => Facebooker::Session::FeedTitleTemplateInvalid,
@@ -546,7 +603,7 @@ module Facebooker
546
603
  end
547
604
  end
548
605
  end
549
-
606
+
550
607
  class Parser
551
608
  PARSERS = {
552
609
  'facebook.auth.revokeAuthorization' => RevokeAuthorization,
@@ -562,7 +619,7 @@ module Facebooker
562
619
  'facebook.users.hasAppPermission' => UserHasPermission,
563
620
  'facebook.pages.isAdmin' => PagesIsAdmin,
564
621
  'facebook.pages.getInfo' => PagesGetInfo,
565
- 'facebook.pages.isFan' => PagesIsFan,
622
+ 'facebook.pages.isFan' => PagesIsFan,
566
623
  'facebook.friends.get' => GetFriends,
567
624
  'facebook.friends.getLists' => FriendListsGet,
568
625
  'facebook.friends.areFriends' => AreFriends,
@@ -593,12 +650,15 @@ module Facebooker
593
650
  'facebook.admin.getAllocation' => GetAllocation,
594
651
  'facebook.batch.run' => BatchRun,
595
652
  'facebook.fql.query' => FqlQuery,
653
+ 'facebook.fql.multiquery' => FqlMultiquery,
596
654
  'facebook.photos.get' => GetPhotos,
597
655
  'facebook.photos.getAlbums' => GetAlbums,
598
656
  'facebook.photos.createAlbum' => CreateAlbum,
599
657
  'facebook.photos.getTags' => GetTags,
600
658
  'facebook.photos.addTag' => AddTags,
601
659
  'facebook.photos.upload' => UploadPhoto,
660
+ 'facebook.stream.publish' => StreamPublish,
661
+ 'facebook.stream.addComment' => StreamAddComment,
602
662
  'facebook.events.get' => EventsGet,
603
663
  'facebook.groups.get' => GroupsGet,
604
664
  'facebook.events.getMembers' => EventMembersGet,