secobarbital-twitter 0.9.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. data/History +271 -0
  2. data/License +20 -0
  3. data/Notes +33 -0
  4. data/README.rdoc +19 -0
  5. data/Rakefile +39 -0
  6. data/VERSION.yml +5 -0
  7. data/examples/connect.rb +30 -0
  8. data/examples/friendship_existance.rb +13 -0
  9. data/examples/helpers/config_store.rb +38 -0
  10. data/examples/httpauth.rb +11 -0
  11. data/examples/ids.rb +13 -0
  12. data/examples/lists.rb +11 -0
  13. data/examples/oauth.rb +27 -0
  14. data/examples/search.rb +15 -0
  15. data/examples/timeline.rb +19 -0
  16. data/examples/tumblr.rb +9 -0
  17. data/examples/unauthorized.rb +16 -0
  18. data/examples/update.rb +11 -0
  19. data/examples/user.rb +5 -0
  20. data/lib/twitter/base.rb +371 -0
  21. data/lib/twitter/httpauth.rb +39 -0
  22. data/lib/twitter/local_trends.rb +15 -0
  23. data/lib/twitter/oauth.rb +58 -0
  24. data/lib/twitter/request.rb +71 -0
  25. data/lib/twitter/search.rb +157 -0
  26. data/lib/twitter/trends.rb +41 -0
  27. data/lib/twitter.rb +148 -0
  28. data/test/fixtures/blocking.json +1632 -0
  29. data/test/fixtures/firehose.json +1 -0
  30. data/test/fixtures/follower_ids.json +1 -0
  31. data/test/fixtures/followers.json +1 -0
  32. data/test/fixtures/friend_ids.json +1 -0
  33. data/test/fixtures/friends_timeline.json +1 -0
  34. data/test/fixtures/friendship.json +1 -0
  35. data/test/fixtures/home_timeline.json +1 -0
  36. data/test/fixtures/ids.json +1 -0
  37. data/test/fixtures/list.json +1 -0
  38. data/test/fixtures/list_statuses.json +1 -0
  39. data/test/fixtures/list_statuses_1_1.json +1 -0
  40. data/test/fixtures/list_statuses_2_1.json +1 -0
  41. data/test/fixtures/list_subscriptions.json +1 -0
  42. data/test/fixtures/list_users.json +1 -0
  43. data/test/fixtures/lists.json +1 -0
  44. data/test/fixtures/memberships.json +1 -0
  45. data/test/fixtures/mentions.json +1 -0
  46. data/test/fixtures/not_found.json +1 -0
  47. data/test/fixtures/people_search.json +39 -0
  48. data/test/fixtures/rate_limit_exceeded.json +1 -0
  49. data/test/fixtures/retweet.json +1 -0
  50. data/test/fixtures/retweeted_by_me.json +1 -0
  51. data/test/fixtures/retweeted_to_me.json +1 -0
  52. data/test/fixtures/retweeters_of_tweet.json +166 -0
  53. data/test/fixtures/retweets.json +1 -0
  54. data/test/fixtures/retweets_of_me.json +1 -0
  55. data/test/fixtures/sample-image.png +0 -0
  56. data/test/fixtures/search.json +1 -0
  57. data/test/fixtures/search_from_jnunemaker.json +1 -0
  58. data/test/fixtures/status.json +1 -0
  59. data/test/fixtures/status_show.json +1 -0
  60. data/test/fixtures/trends_available.json +253 -0
  61. data/test/fixtures/trends_current.json +1 -0
  62. data/test/fixtures/trends_current_exclude.json +1 -0
  63. data/test/fixtures/trends_daily.json +1925 -0
  64. data/test/fixtures/trends_daily_date.json +1 -0
  65. data/test/fixtures/trends_daily_exclude.json +1 -0
  66. data/test/fixtures/trends_location.json +57 -0
  67. data/test/fixtures/trends_weekly.json +1 -0
  68. data/test/fixtures/trends_weekly_date.json +1 -0
  69. data/test/fixtures/trends_weekly_exclude.json +1 -0
  70. data/test/fixtures/unauthorized.json +1 -0
  71. data/test/fixtures/update_profile_background_image.json +1 -0
  72. data/test/fixtures/update_profile_image.json +1 -0
  73. data/test/fixtures/user.json +1 -0
  74. data/test/fixtures/user_timeline.json +710 -0
  75. data/test/fixtures/users.json +1 -0
  76. data/test/test_helper.rb +46 -0
  77. data/test/twitter/base_test.rb +364 -0
  78. data/test/twitter/httpauth_test.rb +76 -0
  79. data/test/twitter/oauth_test.rb +108 -0
  80. data/test/twitter/request_test.rb +217 -0
  81. data/test/twitter/search_test.rb +208 -0
  82. data/test/twitter/trends_test.rb +112 -0
  83. data/test/twitter_test.rb +106 -0
  84. metadata +280 -0
@@ -0,0 +1,371 @@
1
+ module Twitter
2
+ class Base
3
+ extend Forwardable
4
+
5
+ def_delegators :client, :get, :post, :put, :delete
6
+
7
+ attr_reader :client
8
+
9
+ def initialize(client)
10
+ @client = client
11
+ end
12
+
13
+ # Options: since_id, max_id, count, page
14
+ def home_timeline(query={})
15
+ perform_get("/#{API_VERSION}/statuses/home_timeline.json", :query => query)
16
+ end
17
+
18
+ # Options: since_id, max_id, count, page, since
19
+ def friends_timeline(query={})
20
+ perform_get("/#{API_VERSION}/statuses/friends_timeline.json", :query => query)
21
+ end
22
+
23
+ # Options: id, user_id, screen_name, since_id, max_id, page, since, count
24
+ def user_timeline(query={})
25
+ perform_get("/#{API_VERSION}/statuses/user_timeline.json", :query => query)
26
+ end
27
+
28
+ def status(id)
29
+ perform_get("/#{API_VERSION}/statuses/show/#{id}.json")
30
+ end
31
+
32
+ # Options: count
33
+ def retweets(id, query={})
34
+ perform_get("/#{API_VERSION}/statuses/retweets/#{id}.json", :query => query)
35
+ end
36
+
37
+ # Options: in_reply_to_status_id
38
+ def update(status, query={})
39
+ perform_post("/#{API_VERSION}/statuses/update.json", :body => {:status => status}.merge(query))
40
+ end
41
+
42
+ # DEPRECATED: Use #mentions instead
43
+ #
44
+ # Options: since_id, max_id, since, page
45
+ def replies(query={})
46
+ warn("DEPRECATED: #replies is deprecated by Twitter; use #mentions instead")
47
+ perform_get("/#{API_VERSION}/statuses/replies.json", :query => query)
48
+ end
49
+
50
+ # Options: since_id, max_id, count, page
51
+ def mentions(query={})
52
+ perform_get("/#{API_VERSION}/statuses/mentions.json", :query => query)
53
+ end
54
+
55
+ # Options: since_id, max_id, count, page
56
+ def retweeted_by_me(query={})
57
+ perform_get("/#{API_VERSION}/statuses/retweeted_by_me.json", :query => query)
58
+ end
59
+
60
+ # Options: since_id, max_id, count, page
61
+ def retweeted_to_me(query={})
62
+ perform_get("/#{API_VERSION}/statuses/retweeted_to_me.json", :query => query)
63
+ end
64
+
65
+ # Options: since_id, max_id, count, page
66
+ def retweets_of_me(query={})
67
+ perform_get("/#{API_VERSION}/statuses/retweets_of_me.json", :query => query)
68
+ end
69
+
70
+ # options: count, page, ids_only
71
+ def retweeters_of(id, options={})
72
+ ids_only = !!(options.delete(:ids_only))
73
+ perform_get("/#{API_VERSION}/statuses/#{id}/retweeted_by#{"/ids" if ids_only}.json", :query => options)
74
+ end
75
+
76
+ def status_destroy(id)
77
+ perform_post("/#{API_VERSION}/statuses/destroy/#{id}.json")
78
+ end
79
+
80
+ def retweet(id)
81
+ perform_post("/#{API_VERSION}/statuses/retweet/#{id}.json")
82
+ end
83
+
84
+ # Options: id, user_id, screen_name, page
85
+ def friends(query={})
86
+ perform_get("/#{API_VERSION}/statuses/friends.json", :query => query)
87
+ end
88
+
89
+ # Options: id, user_id, screen_name, page
90
+ def followers(query={})
91
+ perform_get("/#{API_VERSION}/statuses/followers.json", :query => query)
92
+ end
93
+
94
+ def user(id, query={})
95
+ perform_get("/#{API_VERSION}/users/show/#{id}.json", :query => query)
96
+ end
97
+
98
+ def users(*ids_or_usernames)
99
+ ids, usernames = [], []
100
+ ids_or_usernames.each do |id_or_username|
101
+ if id_or_username.is_a?(Integer)
102
+ ids << id_or_username
103
+ elsif id_or_username.is_a?(String)
104
+ usernames << id_or_username
105
+ end
106
+ end
107
+ query = {}
108
+ query[:user_id] = ids.join(",") unless ids.empty?
109
+ query[:screen_name] = usernames.join(",") unless usernames.empty?
110
+ perform_get("/#{API_VERSION}/users/lookup.json", :query => query)
111
+ end
112
+
113
+ # Options: page, per_page
114
+ def user_search(q, query={})
115
+ q = URI.escape(q)
116
+ perform_get("/#{API_VERSION}/users/search.json", :query => ({:q => q}.merge(query)))
117
+ end
118
+
119
+ # Options: since, since_id, page
120
+ def direct_messages(query={})
121
+ perform_get("/#{API_VERSION}/direct_messages.json", :query => query)
122
+ end
123
+
124
+ # Options: since, since_id, page
125
+ def direct_messages_sent(query={})
126
+ perform_get("/#{API_VERSION}/direct_messages/sent.json", :query => query)
127
+ end
128
+
129
+ def direct_message_create(user, text)
130
+ perform_post("/#{API_VERSION}/direct_messages/new.json", :body => {:user => user, :text => text})
131
+ end
132
+
133
+ def direct_message_destroy(id)
134
+ perform_post("/#{API_VERSION}/direct_messages/destroy/#{id}.json")
135
+ end
136
+
137
+ def friendship_create(id, follow=false)
138
+ body = {}
139
+ body.merge!(:follow => follow) if follow
140
+ perform_post("/#{API_VERSION}/friendships/create/#{id}.json", :body => body)
141
+ end
142
+
143
+ def friendship_destroy(id)
144
+ perform_post("/#{API_VERSION}/friendships/destroy/#{id}.json")
145
+ end
146
+
147
+ def friendship_exists?(a, b)
148
+ perform_get("/#{API_VERSION}/friendships/exists.json", :query => {:user_a => a, :user_b => b})
149
+ end
150
+
151
+ def friendship_show(query)
152
+ perform_get("/#{API_VERSION}/friendships/show.json", :query => query)
153
+ end
154
+
155
+ # Options: id, user_id, screen_name
156
+ def friend_ids(query={})
157
+ perform_get("/#{API_VERSION}/friends/ids.json", :query => query)
158
+ end
159
+
160
+ # Options: id, user_id, screen_name
161
+ def follower_ids(query={})
162
+ perform_get("/#{API_VERSION}/followers/ids.json", :query => query)
163
+ end
164
+
165
+ def verify_credentials
166
+ perform_get("/#{API_VERSION}/account/verify_credentials.json")
167
+ end
168
+
169
+ # Device must be sms, im or none
170
+ def update_delivery_device(device)
171
+ perform_post("/#{API_VERSION}/account/update_delivery_device.json", :body => {:device => device})
172
+ end
173
+
174
+ # One or more of the following must be present:
175
+ # profile_background_color, profile_text_color, profile_link_color,
176
+ # profile_sidebar_fill_color, profile_sidebar_border_color
177
+ def update_profile_colors(colors={})
178
+ perform_post("/#{API_VERSION}/account/update_profile_colors.json", :body => colors)
179
+ end
180
+
181
+ # file should respond to #read and #path
182
+ def update_profile_image(file)
183
+ perform_post("/#{API_VERSION}/account/update_profile_image.json", build_multipart_bodies(:image => file))
184
+ end
185
+
186
+ # file should respond to #read and #path
187
+ def update_profile_background(file, tile = false)
188
+ perform_post("/#{API_VERSION}/account/update_profile_background_image.json", build_multipart_bodies(:image => file).merge(:tile => tile))
189
+ end
190
+
191
+ def rate_limit_status
192
+ perform_get("/#{API_VERSION}/account/rate_limit_status.json")
193
+ end
194
+
195
+ # One or more of the following must be present:
196
+ # name, email, url, location, description
197
+ def update_profile(body={})
198
+ perform_post("/#{API_VERSION}/account/update_profile.json", :body => body)
199
+ end
200
+
201
+ # Options: id, page
202
+ def favorites(query={})
203
+ perform_get("/#{API_VERSION}/favorites.json", :query => query)
204
+ end
205
+
206
+ def favorite_create(id)
207
+ perform_post("/#{API_VERSION}/favorites/create/#{id}.json")
208
+ end
209
+
210
+ def favorite_destroy(id)
211
+ perform_post("/#{API_VERSION}/favorites/destroy/#{id}.json")
212
+ end
213
+
214
+ def enable_notifications(id)
215
+ perform_post("/#{API_VERSION}/notifications/follow/#{id}.json")
216
+ end
217
+
218
+ def disable_notifications(id)
219
+ perform_post("/#{API_VERSION}/notifications/leave/#{id}.json")
220
+ end
221
+
222
+ def block(id)
223
+ perform_post("/#{API_VERSION}/blocks/create/#{id}.json")
224
+ end
225
+
226
+ def unblock(id)
227
+ perform_post("/#{API_VERSION}/blocks/destroy/#{id}.json")
228
+ end
229
+
230
+ def help
231
+ perform_get("/#{API_VERSION}/help/test.json")
232
+ end
233
+
234
+ def list_create(list_owner_username, options)
235
+ perform_post("/#{API_VERSION}/#{list_owner_username}/lists.json", :body => {:user => list_owner_username}.merge(options))
236
+ end
237
+
238
+ def list_update(list_owner_username, slug, options)
239
+ perform_put("/#{API_VERSION}/#{list_owner_username}/lists/#{slug}.json", :body => options)
240
+ end
241
+
242
+ def list_delete(list_owner_username, slug)
243
+ perform_delete("/#{API_VERSION}/#{list_owner_username}/lists/#{slug}.json")
244
+ end
245
+
246
+ def lists(list_owner_username = nil, cursor = nil)
247
+ if list_owner_username
248
+ path = "/#{API_VERSION}/#{list_owner_username}/lists.json"
249
+ else
250
+ path = "/#{API_VERSION}/lists.json"
251
+ end
252
+ query = {}
253
+ query[:cursor] = cursor if cursor
254
+ perform_get(path, :query => query)
255
+ end
256
+
257
+ def list(list_owner_username, slug)
258
+ perform_get("/#{API_VERSION}/#{list_owner_username}/lists/#{slug}.json")
259
+ end
260
+
261
+ # :per_page = max number of statues to get at once
262
+ # :page = which page of tweets you wish to get
263
+ def list_timeline(list_owner_username, slug, query = {})
264
+ perform_get("/#{API_VERSION}/#{list_owner_username}/lists/#{slug}/statuses.json", :query => query)
265
+ end
266
+
267
+ def memberships(list_owner_username, query={})
268
+ perform_get("/#{API_VERSION}/#{list_owner_username}/lists/memberships.json", :query => query)
269
+ end
270
+
271
+ def list_members(list_owner_username, slug, cursor = nil)
272
+ query = {}
273
+ query[:cursor] = cursor if cursor
274
+ perform_get("/#{API_VERSION}/#{list_owner_username}/#{slug}/members.json", :query => query)
275
+ end
276
+
277
+ def list_add_member(list_owner_username, slug, new_id)
278
+ perform_post("/#{API_VERSION}/#{list_owner_username}/#{slug}/members.json", :body => {:id => new_id})
279
+ end
280
+
281
+ def list_remove_member(list_owner_username, slug, id)
282
+ perform_delete("/#{API_VERSION}/#{list_owner_username}/#{slug}/members.json", :query => {:id => id})
283
+ end
284
+
285
+ def is_list_member?(list_owner_username, slug, id)
286
+ perform_get("/#{API_VERSION}/#{list_owner_username}/#{slug}/members/#{id}.json").error.nil?
287
+ end
288
+
289
+ def list_subscribers(list_owner_username, slug)
290
+ perform_get("/#{API_VERSION}/#{list_owner_username}/#{slug}/subscribers.json")
291
+ end
292
+
293
+ def list_subscribe(list_owner_username, slug)
294
+ perform_post("/#{API_VERSION}/#{list_owner_username}/#{slug}/subscribers.json")
295
+ end
296
+
297
+ def list_unsubscribe(list_owner_username, slug)
298
+ perform_delete("/#{API_VERSION}/#{list_owner_username}/#{slug}/subscribers.json")
299
+ end
300
+
301
+ def list_subscriptions(list_owner_username)
302
+ perform_get("/#{API_VERSION}/#{list_owner_username}/lists/subscriptions.json")
303
+ end
304
+
305
+ def blocked_ids
306
+ perform_get("/#{API_VERSION}/blocks/blocking/ids.json", :mash => false)
307
+ end
308
+
309
+ def blocking(options={})
310
+ perform_get("/#{API_VERSION}/blocks/blocking.json", options)
311
+ end
312
+
313
+ protected
314
+
315
+ def self.mime_type(file)
316
+ case
317
+ when file =~ /\.jpg/ then 'image/jpg'
318
+ when file =~ /\.gif$/ then 'image/gif'
319
+ when file =~ /\.png$/ then 'image/png'
320
+ else 'application/octet-stream'
321
+ end
322
+ end
323
+
324
+ def mime_type(f) self.class.mime_type(f) end
325
+
326
+ CRLF = "\r\n"
327
+
328
+ def self.build_multipart_bodies(parts)
329
+ boundary = Time.now.to_i.to_s(16)
330
+ body = ""
331
+ parts.each do |key, value|
332
+ esc_key = CGI.escape(key.to_s)
333
+ body << "--#{boundary}#{CRLF}"
334
+ if value.respond_to?(:read)
335
+ body << "Content-Disposition: form-data; name=\"#{esc_key}\"; filename=\"#{File.basename(value.path)}\"#{CRLF}"
336
+ body << "Content-Type: #{mime_type(value.path)}#{CRLF*2}"
337
+ body << value.read
338
+ else
339
+ body << "Content-Disposition: form-data; name=\"#{esc_key}\"#{CRLF*2}#{value}"
340
+ end
341
+ body << CRLF
342
+ end
343
+ body << "--#{boundary}--#{CRLF*2}"
344
+ {
345
+ :body => body,
346
+ :headers => {"Content-Type" => "multipart/form-data; boundary=#{boundary}"}
347
+ }
348
+ end
349
+
350
+ def build_multipart_bodies(parts) self.class.build_multipart_bodies(parts) end
351
+
352
+ private
353
+
354
+ def perform_get(path, options={})
355
+ Twitter::Request.get(self, path, options)
356
+ end
357
+
358
+ def perform_post(path, options={})
359
+ Twitter::Request.post(self, path, options)
360
+ end
361
+
362
+ def perform_put(path, options={})
363
+ Twitter::Request.put(self, path, options)
364
+ end
365
+
366
+ def perform_delete(path, options={})
367
+ Twitter::Request.delete(self, path, options)
368
+ end
369
+
370
+ end
371
+ end
@@ -0,0 +1,39 @@
1
+ module Twitter
2
+ class HTTPAuth
3
+ include HTTParty
4
+
5
+ format :plain
6
+
7
+ attr_reader :username, :password, :options
8
+
9
+ def initialize(username, password, options={})
10
+ @username, @password = username, password
11
+ @options = {:ssl => false}.merge(options)
12
+ options[:api_endpoint] ||= "api.twitter.com"
13
+ self.class.base_uri "http#{'s' if options[:ssl]}://#{options[:api_endpoint]}"
14
+ end
15
+
16
+ def get(uri, headers={})
17
+ self.class.get(uri, :headers => headers, :basic_auth => basic_auth)
18
+ end
19
+
20
+ def post(uri, body={}, headers={})
21
+ self.class.post(uri, :body => body, :headers => headers, :basic_auth => basic_auth)
22
+ end
23
+
24
+ def put(uri, body={}, headers={})
25
+ self.class.put(uri, :body => body, :headers => headers, :basic_auth => basic_auth)
26
+ end
27
+
28
+ def delete(uri, body={}, headers={})
29
+ self.class.delete(uri, :body => body, :headers => headers, :basic_auth => basic_auth)
30
+ end
31
+
32
+ private
33
+
34
+ def basic_auth
35
+ @basic_auth ||= {:username => @username, :password => @password}
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,15 @@
1
+ module Twitter
2
+ class LocalTrends
3
+ include HTTParty
4
+ base_uri "api.twitter.com/#{API_VERSION}/trends"
5
+ format :json
6
+
7
+ def self.available(query={})
8
+ get("/available.json", :query => query).map{|location| Twitter.mash(location)}
9
+ end
10
+
11
+ def self.for_location(woeid)
12
+ get("/#{woeid}.json").map{|location| Twitter.mash(location)}
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,58 @@
1
+ module Twitter
2
+ class OAuth
3
+ extend Forwardable
4
+
5
+ def_delegators :access_token, :get, :post, :put, :delete
6
+
7
+ attr_reader :ctoken, :csecret, :consumer_options
8
+
9
+ # Options
10
+ # :sign_in => true to just sign in with twitter instead of doing oauth authorization
11
+ # (http://apiwiki.twitter.com/Sign-in-with-Twitter)
12
+ def initialize(ctoken, csecret, options={})
13
+ @ctoken, @csecret, @consumer_options = ctoken, csecret, {}
14
+ if options[:sign_in]
15
+ @consumer_options[:authorize_path] = '/oauth/authenticate'
16
+ end
17
+ end
18
+
19
+ def consumer
20
+ @consumer ||= ::OAuth::Consumer.new(@ctoken, @csecret, {:site => 'http://api.twitter.com'}.merge(consumer_options))
21
+ end
22
+
23
+ def set_callback_url(url)
24
+ clear_request_token
25
+ request_token(:oauth_callback => url)
26
+ end
27
+
28
+ # Note: If using oauth with a web app, be sure to provide :oauth_callback.
29
+ # Options:
30
+ # :oauth_callback => String, url that twitter should redirect to
31
+ def request_token(options={})
32
+ @request_token ||= consumer.get_request_token(options)
33
+ end
34
+
35
+ # For web apps use params[:oauth_verifier], for desktop apps,
36
+ # use the verifier is the pin that twitter gives users.
37
+ def authorize_from_request(rtoken, rsecret, verifier_or_pin)
38
+ request_token = ::OAuth::RequestToken.new(consumer, rtoken, rsecret)
39
+ access_token = request_token.get_access_token(:oauth_verifier => verifier_or_pin)
40
+ @atoken, @asecret = access_token.token, access_token.secret
41
+ end
42
+
43
+ def access_token
44
+ @access_token ||= ::OAuth::AccessToken.new(consumer, @atoken, @asecret)
45
+ end
46
+
47
+ def authorize_from_access(atoken, asecret)
48
+ @atoken, @asecret = atoken, asecret
49
+ end
50
+
51
+ private
52
+
53
+ def clear_request_token
54
+ @request_token = nil
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,71 @@
1
+ module Twitter
2
+ class Request
3
+ extend Forwardable
4
+
5
+ def self.get(client, path, options={})
6
+ new(client, :get, path, options).perform
7
+ end
8
+
9
+ def self.post(client, path, options={})
10
+ new(client, :post, path, options).perform
11
+ end
12
+
13
+ def self.put(client, path, options={})
14
+ new(client, :put, path, options).perform
15
+ end
16
+
17
+ def self.delete(client, path, options={})
18
+ new(client, :delete, path, options).perform
19
+ end
20
+
21
+ attr_reader :client, :method, :path, :options
22
+
23
+ def_delegators :client, :get, :post, :put, :delete
24
+
25
+ def initialize(client, method, path, options={})
26
+ @client, @method, @path, @options = client, method, path, options
27
+ end
28
+
29
+ def uri
30
+ @uri ||= begin
31
+ uri = URI.parse(path)
32
+
33
+ if options[:query] && options[:query] != {}
34
+ uri.query = to_query(options[:query])
35
+ end
36
+
37
+ uri.to_s
38
+ end
39
+ end
40
+
41
+ def perform
42
+ Twitter.make_friendly(send("perform_#{method}"))
43
+ end
44
+
45
+ private
46
+
47
+ def perform_get
48
+ get(uri, options[:headers])
49
+ end
50
+
51
+ def perform_post
52
+ post(uri, options[:body], options[:headers])
53
+ end
54
+
55
+ def perform_put
56
+ put(uri, options[:body], options[:headers])
57
+ end
58
+
59
+ def perform_delete
60
+ delete(uri, options[:headers])
61
+ end
62
+
63
+ def to_query(options)
64
+ options.inject([]) do |collection, opt|
65
+ collection << "#{opt[0]}=#{opt[1]}"
66
+ collection
67
+ end * '&'
68
+ end
69
+
70
+ end
71
+ end