twitter 4.8.1 → 5.0.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.
Files changed (215) hide show
  1. data/CHANGELOG.md +36 -0
  2. data/CONTRIBUTING.md +13 -15
  3. data/LICENSE.md +1 -1
  4. data/README.md +401 -261
  5. data/Rakefile +6 -0
  6. data/lib/twitter/arguments.rb +14 -0
  7. data/lib/twitter/base.rb +109 -89
  8. data/lib/twitter/client.rb +38 -115
  9. data/lib/twitter/configuration.rb +5 -2
  10. data/lib/twitter/core_ext/kernel.rb +5 -1
  11. data/lib/twitter/creatable.rb +7 -4
  12. data/lib/twitter/cursor.rb +57 -45
  13. data/lib/twitter/direct_message.rb +2 -11
  14. data/lib/twitter/entity/uri.rb +14 -0
  15. data/lib/twitter/enumerable.rb +15 -0
  16. data/lib/twitter/error/already_favorited.rb +1 -1
  17. data/lib/twitter/error/already_posted.rb +10 -0
  18. data/lib/twitter/error/already_retweeted.rb +1 -1
  19. data/lib/twitter/error/bad_gateway.rb +2 -3
  20. data/lib/twitter/error/bad_request.rb +2 -2
  21. data/lib/twitter/error/forbidden.rb +2 -2
  22. data/lib/twitter/error/gateway_timeout.rb +2 -3
  23. data/lib/twitter/error/internal_server_error.rb +2 -3
  24. data/lib/twitter/error/not_acceptable.rb +2 -2
  25. data/lib/twitter/error/not_found.rb +2 -2
  26. data/lib/twitter/error/service_unavailable.rb +2 -3
  27. data/lib/twitter/error/too_many_requests.rb +2 -2
  28. data/lib/twitter/error/unauthorized.rb +2 -2
  29. data/lib/twitter/error/unprocessable_entity.rb +2 -2
  30. data/lib/twitter/error.rb +65 -14
  31. data/lib/twitter/factory.rb +13 -12
  32. data/lib/twitter/geo.rb +2 -7
  33. data/lib/twitter/geo_factory.rb +11 -7
  34. data/lib/twitter/geo_results.rb +40 -0
  35. data/lib/twitter/identity.rb +4 -34
  36. data/lib/twitter/list.rb +21 -4
  37. data/lib/twitter/media/photo.rb +6 -4
  38. data/lib/twitter/media_factory.rb +11 -7
  39. data/lib/twitter/null_object.rb +25 -0
  40. data/lib/twitter/oembed.rb +3 -2
  41. data/lib/twitter/place.rb +15 -15
  42. data/lib/twitter/profile_banner.rb +3 -2
  43. data/lib/twitter/rate_limit.rb +4 -17
  44. data/lib/twitter/relationship.rb +2 -19
  45. data/lib/twitter/rest/api/direct_messages.rb +138 -0
  46. data/lib/twitter/rest/api/favorites.rb +115 -0
  47. data/lib/twitter/rest/api/friends_and_followers.rb +287 -0
  48. data/lib/twitter/rest/api/help.rb +58 -0
  49. data/lib/twitter/rest/api/lists.rb +498 -0
  50. data/lib/twitter/rest/api/oauth.rb +62 -0
  51. data/lib/twitter/rest/api/places_and_geo.rb +86 -0
  52. data/lib/twitter/rest/api/saved_searches.rb +93 -0
  53. data/lib/twitter/rest/api/search.rb +37 -0
  54. data/lib/twitter/rest/api/spam_reporting.rb +29 -0
  55. data/lib/twitter/rest/api/suggested_users.rb +51 -0
  56. data/lib/twitter/rest/api/timelines.rb +202 -0
  57. data/lib/twitter/rest/api/trends.rb +58 -0
  58. data/lib/twitter/rest/api/tweets.rb +291 -0
  59. data/lib/twitter/rest/api/undocumented.rb +52 -0
  60. data/lib/twitter/rest/api/users.rb +383 -0
  61. data/lib/twitter/rest/api/utils.rb +246 -0
  62. data/lib/twitter/rest/client.rb +175 -0
  63. data/lib/twitter/rest/request/multipart_with_file.rb +36 -0
  64. data/lib/twitter/rest/response/parse_error_json.rb +15 -0
  65. data/lib/twitter/rest/response/parse_json.rb +31 -0
  66. data/lib/twitter/{response → rest/response}/raise_error.rb +8 -11
  67. data/lib/twitter/search_results.rb +37 -21
  68. data/lib/twitter/settings.rb +1 -6
  69. data/lib/twitter/size.rb +2 -15
  70. data/lib/twitter/streaming/client.rb +89 -0
  71. data/lib/twitter/streaming/connection.rb +22 -0
  72. data/lib/twitter/streaming/event.rb +35 -0
  73. data/lib/twitter/streaming/friend_list.rb +13 -0
  74. data/lib/twitter/streaming/message_parser.rb +18 -0
  75. data/lib/twitter/streaming/response.rb +34 -0
  76. data/lib/twitter/suggestion.rb +5 -8
  77. data/lib/twitter/token.rb +11 -1
  78. data/lib/twitter/trend.rb +4 -8
  79. data/lib/twitter/trend_results.rb +65 -0
  80. data/lib/twitter/tweet.rb +43 -92
  81. data/lib/twitter/user.rb +72 -47
  82. data/lib/twitter/version.rb +4 -4
  83. data/lib/twitter.rb +4 -39
  84. data/spec/fixtures/already_posted.json +1 -0
  85. data/spec/fixtures/ids_list.json +1 -1
  86. data/spec/fixtures/ids_list2.json +1 -1
  87. data/spec/fixtures/request_token.txt +6 -0
  88. data/spec/fixtures/search.json +1 -1
  89. data/spec/fixtures/search_malformed.json +1 -1
  90. data/spec/fixtures/track_streaming.json +3 -0
  91. data/spec/fixtures/track_streaming_user.json +5 -0
  92. data/spec/helper.rb +8 -13
  93. data/spec/twitter/base_spec.rb +13 -103
  94. data/spec/twitter/basic_user_spec.rb +3 -3
  95. data/spec/twitter/configuration_spec.rb +1 -1
  96. data/spec/twitter/cursor_spec.rb +17 -35
  97. data/spec/twitter/direct_message_spec.rb +44 -11
  98. data/spec/twitter/entity/uri_spec.rb +75 -0
  99. data/spec/twitter/error_spec.rb +59 -11
  100. data/spec/twitter/geo/point_spec.rb +6 -6
  101. data/spec/twitter/geo/polygon_spec.rb +5 -5
  102. data/spec/twitter/geo_factory_spec.rb +4 -4
  103. data/spec/twitter/geo_results_spec.rb +35 -0
  104. data/spec/twitter/geo_spec.rb +6 -6
  105. data/spec/twitter/identifiable_spec.rb +5 -26
  106. data/spec/twitter/list_spec.rb +54 -11
  107. data/spec/twitter/media/photo_spec.rb +122 -6
  108. data/spec/twitter/media_factory_spec.rb +3 -3
  109. data/spec/twitter/null_object_spec.rb +27 -0
  110. data/spec/twitter/oembed_spec.rb +69 -45
  111. data/spec/twitter/place_spec.rb +84 -28
  112. data/spec/twitter/profile_banner_spec.rb +1 -1
  113. data/spec/twitter/rate_limit_spec.rb +8 -25
  114. data/spec/twitter/relationship_spec.rb +26 -12
  115. data/spec/twitter/{api → rest/api}/direct_messages_spec.rb +28 -15
  116. data/spec/twitter/{api → rest/api}/favorites_spec.rb +80 -7
  117. data/spec/twitter/{api → rest/api}/friends_and_followers_spec.rb +121 -152
  118. data/spec/twitter/{api → rest/api}/geo_spec.rb +9 -23
  119. data/spec/twitter/{api → rest/api}/help_spec.rb +6 -6
  120. data/spec/twitter/{api → rest/api}/lists_spec.rb +116 -95
  121. data/spec/twitter/{api → rest/api}/oauth_spec.rb +21 -10
  122. data/spec/twitter/{api → rest/api}/saved_searches_spec.rb +13 -13
  123. data/spec/twitter/{api → rest/api}/search_spec.rb +8 -9
  124. data/spec/twitter/{api → rest/api}/spam_reporting_spec.rb +3 -3
  125. data/spec/twitter/{api → rest/api}/suggested_users_spec.rb +5 -5
  126. data/spec/twitter/{api → rest/api}/timelines_spec.rb +9 -9
  127. data/spec/twitter/{api → rest/api}/trends_spec.rb +6 -6
  128. data/spec/twitter/rest/api/tweets_spec.rb +503 -0
  129. data/spec/twitter/{api → rest/api}/undocumented_spec.rb +19 -45
  130. data/spec/twitter/{api → rest/api}/users_spec.rb +64 -39
  131. data/spec/twitter/rest/client_spec.rb +193 -0
  132. data/spec/twitter/saved_search_spec.rb +14 -3
  133. data/spec/twitter/search_results_spec.rb +32 -45
  134. data/spec/twitter/settings_spec.rb +17 -6
  135. data/spec/twitter/size_spec.rb +5 -15
  136. data/spec/twitter/source_user_spec.rb +3 -3
  137. data/spec/twitter/streaming/client_spec.rb +92 -0
  138. data/spec/twitter/streaming/event_spec.rb +45 -0
  139. data/spec/twitter/suggestion_spec.rb +5 -15
  140. data/spec/twitter/target_user_spec.rb +3 -3
  141. data/spec/twitter/token_spec.rb +16 -0
  142. data/spec/twitter/trend_results_spec.rb +89 -0
  143. data/spec/twitter/trend_spec.rb +26 -13
  144. data/spec/twitter/tweet_spec.rb +137 -124
  145. data/spec/twitter/user_spec.rb +139 -80
  146. data/spec/twitter_spec.rb +0 -119
  147. data/twitter.gemspec +12 -6
  148. data.tar.gz.sig +0 -0
  149. metadata +197 -138
  150. metadata.gz.sig +0 -0
  151. data/lib/twitter/action/favorite.rb +0 -19
  152. data/lib/twitter/action/follow.rb +0 -30
  153. data/lib/twitter/action/list_member_added.rb +0 -39
  154. data/lib/twitter/action/mention.rb +0 -46
  155. data/lib/twitter/action/reply.rb +0 -27
  156. data/lib/twitter/action/retweet.rb +0 -27
  157. data/lib/twitter/action/tweet.rb +0 -20
  158. data/lib/twitter/action_factory.rb +0 -22
  159. data/lib/twitter/api/arguments.rb +0 -13
  160. data/lib/twitter/api/direct_messages.rb +0 -148
  161. data/lib/twitter/api/favorites.rb +0 -126
  162. data/lib/twitter/api/friends_and_followers.rb +0 -334
  163. data/lib/twitter/api/help.rb +0 -64
  164. data/lib/twitter/api/lists.rb +0 -618
  165. data/lib/twitter/api/oauth.rb +0 -44
  166. data/lib/twitter/api/places_and_geo.rb +0 -121
  167. data/lib/twitter/api/saved_searches.rb +0 -99
  168. data/lib/twitter/api/search.rb +0 -37
  169. data/lib/twitter/api/spam_reporting.rb +0 -30
  170. data/lib/twitter/api/suggested_users.rb +0 -55
  171. data/lib/twitter/api/timelines.rb +0 -214
  172. data/lib/twitter/api/trends.rb +0 -63
  173. data/lib/twitter/api/tweets.rb +0 -304
  174. data/lib/twitter/api/undocumented.rb +0 -97
  175. data/lib/twitter/api/users.rb +0 -439
  176. data/lib/twitter/api/utils.rb +0 -187
  177. data/lib/twitter/configurable.rb +0 -96
  178. data/lib/twitter/default.rb +0 -102
  179. data/lib/twitter/entity/url.rb +0 -9
  180. data/lib/twitter/error/client_error.rb +0 -35
  181. data/lib/twitter/error/decode_error.rb +0 -9
  182. data/lib/twitter/error/identity_map_key_error.rb +0 -9
  183. data/lib/twitter/error/server_error.rb +0 -28
  184. data/lib/twitter/exceptable.rb +0 -36
  185. data/lib/twitter/identity_map.rb +0 -22
  186. data/lib/twitter/request/multipart_with_file.rb +0 -34
  187. data/lib/twitter/response/parse_json.rb +0 -25
  188. data/spec/fixtures/about_me.json +0 -1
  189. data/spec/fixtures/activity_summary.json +0 -1
  190. data/spec/fixtures/bad_gateway.json +0 -1
  191. data/spec/fixtures/bad_request.json +0 -1
  192. data/spec/fixtures/by_friends.json +0 -1
  193. data/spec/fixtures/end_session.json +0 -1
  194. data/spec/fixtures/forbidden.json +0 -1
  195. data/spec/fixtures/internal_server_error.json +0 -1
  196. data/spec/fixtures/not_acceptable.json +0 -1
  197. data/spec/fixtures/phoenix_search.phoenix +0 -1
  198. data/spec/fixtures/resolve.json +0 -1
  199. data/spec/fixtures/service_unavailable.json +0 -1
  200. data/spec/fixtures/totals.json +0 -1
  201. data/spec/fixtures/trends.json +0 -1
  202. data/spec/fixtures/unauthorized.json +0 -1
  203. data/spec/fixtures/video_facets.json +0 -1
  204. data/spec/twitter/action/favorite_spec.rb +0 -29
  205. data/spec/twitter/action/follow_spec.rb +0 -29
  206. data/spec/twitter/action/list_member_added_spec.rb +0 -41
  207. data/spec/twitter/action/mention_spec.rb +0 -52
  208. data/spec/twitter/action/reply_spec.rb +0 -41
  209. data/spec/twitter/action/retweet_spec.rb +0 -41
  210. data/spec/twitter/action_factory_spec.rb +0 -35
  211. data/spec/twitter/action_spec.rb +0 -16
  212. data/spec/twitter/api/tweets_spec.rb +0 -285
  213. data/spec/twitter/client_spec.rb +0 -223
  214. data/spec/twitter/error/client_error_spec.rb +0 -23
  215. data/spec/twitter/error/server_error_spec.rb +0 -20
data/README.md CHANGED
@@ -29,32 +29,6 @@ Then, install the gem with the high security trust policy:
29
29
 
30
30
  gem install twitter -P HighSecurity
31
31
 
32
- ## Quick Start Guide
33
- So you want to get up and tweeting as fast as possible?
34
-
35
- First, [register your application with Twitter][register].
36
-
37
- Then, copy and paste in your OAuth data.
38
-
39
- ```ruby
40
- Twitter.configure do |config|
41
- config.consumer_key = YOUR_CONSUMER_KEY
42
- config.consumer_secret = YOUR_CONSUMER_SECRET
43
- config.oauth_token = YOUR_OAUTH_TOKEN
44
- config.oauth_token_secret = YOUR_OAUTH_TOKEN_SECRET
45
- end
46
- ```
47
-
48
- That's it! You're ready to Tweet:
49
- ```ruby
50
- Twitter.update("I'm tweeting with @gem!")
51
- ```
52
-
53
- For more examples of how to use the gem, read the [documentation][] or see [Usage Examples][] below.
54
-
55
- [register]: https://dev.twitter.com/apps/new
56
- [Usage Examples]: #usage-examples
57
-
58
32
  ## CLI
59
33
 
60
34
  Looking for the Twitter command-line interface? It was [removed][] from this
@@ -85,107 +59,419 @@ wiki][apps]!
85
59
 
86
60
  [apps]: https://github.com/sferik/twitter/wiki/apps
87
61
 
88
- ## Configuration
89
- Twitter API v1.1 requires you to authenticate via OAuth, so you'll need to
90
- [register your application with Twitter][register]. Once you've registered an
91
- application, make sure to set the correct access level, otherwise you may see
92
- the error:
62
+ ## What's New in Version 5?
63
+ ### Configuration
64
+ Global configuration has been removed, as it was not threadsafe. Instead, you
65
+ can configure a `Twitter::REST::Client` by passing it a block when it's
66
+ initialized.
93
67
 
94
- Read-only application cannot POST
68
+ ```ruby
69
+ client = Twitter::REST::Client.new do |config|
70
+ config.consumer_key = "YOUR_CONSUMER_KEY"
71
+ config.consumer_secret = "YOUR_CONSUMER_SECRET"
72
+ config.access_token = "YOUR_ACCESS_TOKEN"
73
+ config.access_token_secret = "YOUR_ACCESS_SECRET"
74
+ end
75
+ ```
95
76
 
96
- Your new application will be assigned a consumer key/secret pair and you will
97
- be assigned an OAuth access token/secret pair for that application. You'll need
98
- to configure these values before you make a request or else you'll get the
99
- error:
77
+ Note: `oauth_token` has been renamed to `access_token` and `oauth_token_secret`
78
+ is now `access_token_secret` to conform to the terminology used in Twitter's
79
+ developer documentation.
100
80
 
101
- Bad Authentication data
81
+ ### Streaming (Experimental)
82
+ This library now offers support for the [Twitter Streaming API][streaming]. We
83
+ previously recommended using [TweetStream][] for this, however [TweetStream
84
+ does not work on Ruby 2.0.0][bug].
85
+
86
+ [streaming]: https://dev.twitter.com/docs/streaming-apis
87
+ [tweetstream]: http://rubygems.org/gems/tweetstream
88
+ [bug]: https://github.com/tweetstream/tweetstream/issues/117
89
+
90
+ Unlike the rest of this library, this feature is not well tested and not
91
+ recommended for production applications. That said, if you need to do Twitter
92
+ streaming on Ruby 2.0.0, this is probably your best option. I've decided to
93
+ ship it as an experimental feature and make it more robust over time. Patches
94
+ in this area are particularly welcome.
95
+
96
+ Hopefully, by the time version 6 is released, this gem can fully replace
97
+ [TweetStream][], [em-twitter][], [twitterstream][], and [twitter-stream].
98
+ Special thanks to [Steve Agalloco][spagalloco], [Tim Carey-Smith][halorgium],
99
+ and [Tony Arcieri][tarcieri] for helping to develop this feature.
102
100
 
103
- Applications that make requests on behalf of a single Twitter user can pass
104
- global configuration options as a block to the `Twitter.configure` method.
101
+ [em-twitter]: http://rubygems.org/gems/em-twitter
102
+ [twitterstream]: http://rubygems.org/gems/twitterstream
103
+ [twitter-stream]: http://rubygems.org/gems/twitter-stream
104
+ [spagalloco]: https://github.com/spagalloco
105
+ [halorgium]: https://github.com/halorgium
106
+ [tarcieri]: https://github.com/tarcieri
107
+
108
+ **Configuration works just like `Twitter::REST::Client`**
105
109
 
106
110
  ```ruby
107
- Twitter.configure do |config|
108
- config.consumer_key = YOUR_CONSUMER_KEY
109
- config.consumer_secret = YOUR_CONSUMER_SECRET
110
- config.oauth_token = YOUR_OAUTH_TOKEN
111
- config.oauth_token_secret = YOUR_OAUTH_TOKEN_SECRET
111
+ client = Twitter::Streaming::Client.new do |config|
112
+ config.consumer_key = "YOUR_CONSUMER_KEY"
113
+ config.consumer_secret = "YOUR_CONSUMER_SECRET"
114
+ config.access_token = "YOUR_ACCESS_TOKEN"
115
+ config.access_token_secret = "YOUR_ACCESS_SECRET"
112
116
  end
113
117
  ```
114
118
 
115
- Alternately, you can set the following environment variables:
119
+ **Stream mentions of coffee or tea**
116
120
 
117
- TWITTER_CONSUMER_KEY
118
- TWITTER_CONSUMER_SECRET
119
- TWITTER_OAUTH_TOKEN
120
- TWITTER_OAUTH_TOKEN_SECRET
121
+ ```ruby
122
+ topics = ["coffee", "tea"]
123
+ client.filter(:track => topics.join(",")) do |tweet|
124
+ puts tweet.text
125
+ end
126
+ ```
121
127
 
122
- After configuration, requests can be made like so:
128
+ **Stream a random sample of all tweets**
123
129
 
124
130
  ```ruby
125
- Twitter.update("I'm tweeting with @gem!")
131
+ client.sample do |tweet|
132
+ puts tweet.text
133
+ end
126
134
  ```
127
135
 
128
- #### Thread Safety
129
- Applications that make requests on behalf of multiple Twitter users should
130
- avoid using global configuration. In this case, you may still specify the
131
- `consumer_key` and `consumer_secret` globally. (In a Rails application, this
132
- could go in `config/initializers/twitter.rb`.)
136
+ **Stream tweets, events and direct messages for the authenticated user**
133
137
 
134
138
  ```ruby
135
- Twitter.configure do |config|
136
- config.consumer_key = YOUR_CONSUMER_KEY
137
- config.consumer_secret = YOUR_CONSUMER_SECRET
139
+ client.user do |message|
140
+ puts message
138
141
  end
139
142
  ```
140
143
 
141
- Then, for each user's access token/secret pair, instantiate a
142
- `Twitter::Client`:
144
+ `message` can be one of
145
+ + Twitter::Tweet
146
+ + Twitter::DirectMessage
147
+ + Twitter::Streaming::Event
148
+ + Twitter::Streaming::FriendList
149
+
150
+ [messages]: https://dev.twitter.com/docs/streaming-apis/messages
151
+
152
+ ### Cursors
153
+ The `Twitter::Cursor` class has been completely redesigned with a focus on
154
+ simplicity and performance.
155
+
156
+ [cursors]: https://dev.twitter.com/docs/misc/cursoring
157
+
158
+ <table>
159
+ <thead>
160
+ <tr>
161
+ <th>Notes</th>
162
+ <th colspan="2">Version 4</th>
163
+ <th colspan="2">Version 5</th>
164
+ </th>
165
+ <tr>
166
+ <th></th>
167
+ <th>Code</th>
168
+ <th>HTTP GETs</th>
169
+ <th>Code</th>
170
+ <th>HTTP GETs</th>
171
+ </th>
172
+ </thead>
173
+ <tbody>
174
+ <tr>
175
+ <td>
176
+ Are you at the start of the cursor?
177
+ </td>
178
+ <td>
179
+ <pre><code lang="ruby">client.friends.first</code></pre>
180
+ </td>
181
+ <td>
182
+ <em>Θ(1)</em>
183
+ </td>
184
+ <td>
185
+ <pre><code lang="ruby">client.friends.first?</code></pre>
186
+ </td>
187
+ <td>
188
+ <em>Θ(1)</em>
189
+ </td>
190
+ </tr>
191
+ <tr>
192
+ <td>
193
+ Return your most recent follower.
194
+ </td>
195
+ <td>
196
+ <pre><code lang="ruby">client.friends.users.first</code></pre>
197
+ </td>
198
+ <td>
199
+ <em>Θ(1)</em>
200
+ </td>
201
+ <td>
202
+ <pre><code lang="ruby">client.friends.first</code></pre>
203
+ </td>
204
+ <td>
205
+ <em>Θ(1)</em>
206
+ </td>
207
+ </tr>
208
+ <tr>
209
+ <td>
210
+ Return an array of all your friends.
211
+ </td>
212
+ <td>
213
+ <pre><code lang="ruby">client.friends.all</code></pre>
214
+ </td>
215
+ <td>
216
+ <em>Θ(n+1)</em>
217
+ </td>
218
+ <td>
219
+ <pre><code lang="ruby">client.friends.to_a</code></pre>
220
+ </td>
221
+ <td>
222
+ <em>Θ(n)</em>
223
+ </td>
224
+ </tr>
225
+ <tr>
226
+ <td>
227
+ Collect your 20 most recent friends.
228
+ </td>
229
+ <td>
230
+ <pre><code lang="ruby">client.friends.take(20)</code></pre>
231
+ </td>
232
+ <td>
233
+ <em>Θ(n+1)</em>
234
+ </td>
235
+ <td>
236
+ <pre><code lang="ruby">client.friends.take(20)</code></pre>
237
+ </td>
238
+ <td>
239
+ <em>Θ(1)</em>
240
+ </td>
241
+ </tr>
242
+ <tr>
243
+ <td>
244
+ Collect your 20 most recent friends twice.
245
+ </td>
246
+ <td>
247
+ <pre><code lang="ruby">friends = client.friends
248
+ 2.times.collect do
249
+ friends.take(20)
250
+ end</code></pre>
251
+ </td>
252
+ <td>
253
+ <em>Θ(2n+2)</em>
254
+ </td>
255
+ <td>
256
+ <pre><code lang="ruby">friends = client.friends
257
+ 2.times.collect do
258
+ friends.take(20)
259
+ end</code></pre>
260
+ </td>
261
+ <td>
262
+ <em>Θ(1)</em>
263
+ </td>
264
+ </tr>
265
+ </tbody>
266
+ </table>
267
+
268
+ In the examples above, *n* varies with the number of people the authenticated
269
+ user follows on Twitter. This resource returns up to 20 friends per HTTP GET,
270
+ so if the authenticated user follows 200 people, calling
271
+ `client.friends.take(20)` would make 11 HTTP requests in version 4. In version
272
+ 5, it makes just 1 HTTP request. Keep in mind, eliminating a single HTTP
273
+ request to the Twitter API will reduce the latency of your application by
274
+ [about 500 ms][status].
275
+
276
+ [status]: https://dev.twitter.com/status
277
+
278
+ The last example might seem contrived ("Why would I call
279
+ `client.friends.take(20)` twice?") but it applies to any
280
+ [`Enumerable`][enumerable] method you might call on a cursor, including:
281
+ `#all?`, `#collect`, `#count`, `#each`, `#inject`, `#max`, `#min`, `#reject`,
282
+ `#reverse_each`, `#select`, `#sort`, `#sort_by`, and `#to_a`. In version 4,
283
+ each time you called one of those methods, it would perform *n+1* HTTP
284
+ requests. In version 5, it only performs those HTTP requests the first time any
285
+ one of those methods is called. Each subsequent call fetches data from a
286
+ [cache][].
287
+
288
+ [enumerable]: http://ruby-doc.org/core-2.0/Enumerable.html
289
+ [cache]: https://github.com/sferik/twitter/commit/7d8b2727af9400643ac397207185fd54e3f6387b
290
+
291
+ The performance improvements are actually even **better** than the table above
292
+ indicates. In version 5, calling `Twitter::Cursor#each` (or any
293
+ [`Enumerable`][enumerable] method) starts yielding results immediately and
294
+ continues yielding as each response comes back from the server. In version 4,
295
+ `#each` made a series of requests and waited for the last one to complete
296
+ before yielding any data.
297
+
298
+ Here is a list of the interface changes to `Twitter::Cursor`:
299
+
300
+ * `#all` has been replaced by `#to_a`.
301
+ * `#last` has been replaced by `#last?`.
302
+ * `#first` has been replaced by `#first?`.
303
+ * `#first` now returns the first element in the collection, as prescribed by `Enumerable`.
304
+ * `#collection` and its aliases have been removed.
305
+
306
+ ### Search Results
307
+ The `Twitter::SearchResults` class has also been redesigned to have an
308
+ [`Enumerable`][enumerable] interface. The `#statuses` method and its aliases
309
+ (`#collection` and `#results`) have been replaced by `#to_a`. Additionally,
310
+ this class no longer inherits from `Twitter::Base`. As a result, the `#[]`
311
+ method has been removed.
312
+
313
+ ### Trend Results
314
+ The `#trends` method now returns an [`Enumerable`][enumerable]
315
+ `Twitter::TrendResults` object instead of an array. This object provides
316
+ methods to determinte the recency of the trend (`#as_of`), when the trend
317
+ started (`#created_at`), and the location of the trend (`#location`). This data
318
+ was previously unavailable.
319
+
320
+ ### Geo Results
321
+ Similarly, the `#reverse_geocode`, `#geo_search`, and `#similar_places` methods
322
+ now return an [`Enumerable`][enumerable] `Twitter::GeoResults` object instead
323
+ of an array. This object provides access to the token to create a new place
324
+ (`#token`), which was previously unavailable.
325
+
326
+ ### Tweets
327
+ The `Twitter::Tweet` object has been cleaned up. The following methods have been
328
+ removed:
329
+
330
+ * `#from_user`
331
+ * `#from_user_id`
332
+ * `#from_user_name`
333
+ * `#to_user`
334
+ * `#to_user_id`
335
+ * `#to_user_name`
336
+ * `#profile_image_url`
337
+ * `#profile_image_url_https`
338
+
339
+ These attributes can be accessed via the `Twitter::User` object, returned
340
+ through the `#user` method.
341
+
342
+ ### Users
343
+ The `Twitter::User` object has also been cleaned up. The following aliases have
344
+ been removed:
345
+
346
+ * `#favorite_count` (use `#favorites_count`)
347
+ * `#favoriters_count` (use `#favorites_count`)
348
+ * `#favourite_count` (use `#favorites_count`)
349
+ * `#favouriters_count` (use `#favorites_count`)
350
+ * `#follower_count` (use `#followers_count`)
351
+ * `#friend_count` (use `#friends_count`)
352
+ * `#status_count` (use `#statuses_count`)
353
+ * `#tweet_count` (use `#tweets_count`)
354
+ * `#update_count` (use `#tweets_count`)
355
+ * `#updates_count` (use `#tweets_count`)
356
+ * `#translator` (use `#translator?`)
357
+
358
+ ### Remove British English aliases
359
+ Earlier versions of this library aliased `favourites` to `favorites`. These
360
+ aliases have been removed. Ruby is implemented in American English. The
361
+ `initialize` method is spelled with a "z", not an "s", and Ruby provides no
362
+ alias. Likewise, this library does not provide aliases for Commonwealthers.
363
+ Merica. :us:
364
+
365
+ ### More natural method names
366
+ All create, destroy, add, and remove methods have been renamed to put the verb
367
+ at the beginning:
368
+
369
+ * `#direct_message_create` is now `#create_direct_message`
370
+ * `#direct_message_destroy` is now `#destroy_direct_message`
371
+ * `#list_create` is now `#create_list`
372
+ * `#list_destroy` is now `#destroy_list`
373
+ * `#list_remove_member` is now `#remove_list_member`
374
+ * `#list_remove_members` is now `#remove_list_members`
375
+ * `#list_add_member` is now `#add_list_member`
376
+ * `#list_add_members` is now `#add_list_members`
377
+ * `#lists_owned` is now `#owned_list`
378
+ * `#saved_search_create` is now `#create_saved_search`
379
+ * `#saved_search_destroy` is now `#destroy_saved_search`
380
+ * `#status_destroy` is now `#destroy_status`
381
+
382
+ ### Errors
383
+ The `Twitter::Error::ClientError` and `Twitter::Error::ServerError` class
384
+ hierarchy has been removed. All errors now inherit directly from
385
+ `Twitter::Error`.
386
+
387
+ ### Null Objects
388
+ In version 4, methods you would expect to return a `Twitter` object would
389
+ return `nil` if that object was missing. This may have resulted in a
390
+ `NoMethodError`. To prevent such errors, you may have introduced checks for the
391
+ truthiness of the response, for example:
143
392
 
144
393
  ```ruby
145
- erik = Twitter::Client.new(
146
- :oauth_token => "Erik's access token",
147
- :oauth_token_secret => "Erik's access secret"
148
- )
394
+ status = client.status(55709764298092545)
395
+ if status.place
396
+ # Do something with the Twitter::Place object
397
+ elsif status.geo
398
+ # Do something with the Twitter::Geo object
399
+ end
400
+ ```
401
+ In version 5, all such methods will return a `Twitter::NullObject` instead of
402
+ `nil`. This should prevent `NoMethodError` but may result in unexpected
403
+ behavior if you have truthiness checks in place, since everything is truthy in
404
+ Ruby except `false` and `nil`. For these cases, there are now predicate
405
+ methods:
149
406
 
150
- john = Twitter::Client.new(
151
- :oauth_token => "John's access token",
152
- :oauth_token_secret => "John's access secret"
153
- )
407
+ ```ruby
408
+ status = client.status(55709764298092545)
409
+ if status.place?
410
+ # Do something with the Twitter::Place object
411
+ elsif status.geo?
412
+ # Do something with the Twitter::Geo object
413
+ end
154
414
  ```
155
415
 
156
- You can now make threadsafe requests as the authenticated user:
416
+ ### URI Methods
417
+ The `Twitter::List`, `Twitter::Tweet`, and `Twitter::User` objects all have a
418
+ `#uri` method, which returns an HTTPS URI to twitter.com. This clobbers the
419
+ `Twitter::List#uri` method, which previously returned the list URI's path (not
420
+ a URI).
421
+
422
+ These methods are aliased to `#url` for users who prefer that nomenclature.
423
+ `Twitter::User` previously had a `#url` method, which returned the user's
424
+ website. This URI is now available via the `#website` method.
425
+
426
+ All `#uri` methods now return `URI` objects instead of strings. To convert a
427
+ `URI` object to a string, call `#to_s` on it.
428
+
429
+ ## Configuration
430
+ Twitter API v1.1 requires you to authenticate via OAuth, so you'll need to
431
+ [register your application with Twitter][register]. Once you've registered an
432
+ application, make sure to set the correct access level, otherwise you may see
433
+ the error:
434
+
435
+ [register]: https://dev.twitter.com/apps
436
+
437
+ Read-only application cannot POST
438
+
439
+ Your new application will be assigned a consumer key/secret pair and you will
440
+ be assigned an OAuth access token/secret pair for that application. You'll need
441
+ to configure these values before you make a request or else you'll get the
442
+ error:
443
+
444
+ Bad Authentication data
445
+
446
+ You can pass configuration options as a block to `Twitter::REST::Client.new`.
157
447
 
158
448
  ```ruby
159
- Thread.new{erik.update("Tweeting as Erik!")}
160
- Thread.new{john.update("Tweeting as John!")}
449
+ client = Twitter::REST::Client.new do |config|
450
+ config.consumer_key = "YOUR_CONSUMER_KEY"
451
+ config.consumer_secret = "YOUR_CONSUMER_SECRET"
452
+ config.access_token = "YOUR_ACCESS_TOKEN"
453
+ config.access_token_secret = "YOUR_ACCESS_SECRET"
454
+ end
161
455
  ```
162
456
 
163
- Or, if you prefer, you can specify all configuration options when instantiating
164
- a `Twitter::Client`:
457
+ After configuration, requests can be made like so:
165
458
 
166
459
  ```ruby
167
- client = Twitter::Client.new(
168
- :consumer_key => "an application's consumer key",
169
- :consumer_secret => "an application's consumer secret",
170
- :oauth_token => "a user's access token",
171
- :oauth_token_secret => "a user's access secret"
172
- )
460
+ client.update("I'm tweeting with @gem!")
173
461
  ```
174
462
 
175
- This may be useful if you're using multiple consumer key/secret pairs.
176
-
177
- #### Middleware
463
+ ### Middleware
178
464
  The Faraday middleware stack is fully configurable and is exposed as a
179
465
  `Faraday::Builder` object. You can modify the default middleware in-place:
180
466
 
181
467
  ```ruby
182
- Twitter.middleware.insert_after Twitter::Response::RaiseError, CustomMiddleware
468
+ client.middleware.insert_after Twitter::Response::RaiseError, CustomMiddleware
183
469
  ```
184
470
 
185
471
  A custom adapter may be set as part of a custom middleware stack:
186
472
 
187
473
  ```ruby
188
- Twitter.middleware = Faraday::Builder.new(
474
+ client.middleware = Faraday::Builder.new(
189
475
  &Proc.new do |builder|
190
476
  # Specify a middleware stack here
191
477
  builder.adapter :some_other_adapter
@@ -195,113 +481,92 @@ Twitter.middleware = Faraday::Builder.new(
195
481
 
196
482
  ## Usage Examples
197
483
  All examples require an authenticated Twitter client. See the section on <a
198
- href="#configuration">configuration</a> above.
484
+ href="#configuration">configuration</a>.
199
485
 
200
486
  **Tweet (as the authenticated user)**
201
487
 
202
488
  ```ruby
203
- Twitter.update("I'm tweeting with @gem!")
489
+ client.update("I'm tweeting with @gem!")
204
490
  ```
205
491
  **Follow a user (by screen name or user ID)**
206
492
 
207
493
  ```ruby
208
- Twitter.follow("gem")
209
- Twitter.follow(213747670)
494
+ client.follow("gem")
495
+ client.follow(213747670)
210
496
  ```
211
497
  **Fetch a user (by screen name or user ID)**
212
498
 
213
499
  ```ruby
214
- Twitter.user("gem")
215
- Twitter.user(213747670)
500
+ client.user("gem")
501
+ client.user(213747670)
216
502
  ```
217
503
  **Fetch a cursored list of followers with profile details (by screen name or user ID, or by implict authenticated user)**
218
504
 
219
505
  ```ruby
220
- Twitter.followers("gem")
221
- Twitter.followers(213747670)
222
- Twitter.followers
506
+ client.followers("gem")
507
+ client.followers(213747670)
508
+ client.followers
223
509
  ```
224
510
  **Fetch a cursored list of friends with profile details (by screen name or user ID, or by implict authenticated user)**
225
511
 
226
512
  ```ruby
227
- Twitter.friends("gem")
228
- Twitter.friends(213747670)
229
- Twitter.friends
513
+ client.friends("gem")
514
+ client.friends(213747670)
515
+ client.friends
230
516
  ```
231
517
 
232
518
  **Fetch a collection of user_ids that the currently authenticated user does not want to receive retweets from**
233
519
 
234
520
  ```ruby
235
- Twitter.no_retweet_ids
521
+ client.no_retweet_ids
236
522
  ````
237
523
 
238
524
  **Fetch the timeline of Tweets by a user**
239
525
 
240
526
  ```ruby
241
- Twitter.user_timeline("gem")
242
- Twitter.user_timeline(213747670)
527
+ client.user_timeline("gem")
528
+ client.user_timeline(213747670)
243
529
  ```
244
530
  **Fetch the timeline of Tweets from the authenticated user's home page**
245
531
 
246
532
  ```ruby
247
- Twitter.home_timeline
533
+ client.home_timeline
248
534
  ```
249
535
  **Fetch the timeline of Tweets mentioning the authenticated user**
250
536
 
251
537
  ```ruby
252
- Twitter.mentions_timeline
538
+ client.mentions_timeline
253
539
  ```
254
540
  **Fetch a particular Tweet by ID**
255
541
 
256
542
  ```ruby
257
- Twitter.status(27558893223)
543
+ client.status(27558893223)
258
544
  ```
259
- **Find the 3 most recent marriage proposals to @justinbieber**
545
+ **Collect the 3 most recent marriage proposals to @justinbieber**
260
546
 
261
547
  ```ruby
262
- Twitter.search("to:justinbieber marry me", :count => 3, :result_type => "recent").results.map do |status|
263
- "#{status.from_user}: #{status.text}"
548
+ client.search("to:justinbieber marry me", :count => 3, :result_type => "recent").collect do |tweet|
549
+ "#{tweet.user.screen_name}: #{tweet.text}"
264
550
  end
265
551
  ```
266
552
  **Find a Japanese-language Tweet tagged #ruby (excluding retweets)**
267
553
 
268
554
  ```ruby
269
- Twitter.search("#ruby -rt", :lang => "ja", :count => 1).results.first.text
555
+ client.search("#ruby -rt", :lang => "ja").first.text
270
556
  ```
271
557
  For more usage examples, please see the full [documentation][].
272
558
 
273
- ## Streaming
274
- To access the Twitter Streaming API, we recommend [TweetStream][].
275
-
276
- [tweetstream]: https://github.com/intridea/tweetstream
559
+ ## Object Graph
277
560
 
278
- ## Performance
279
- You can improve performance by loading a faster JSON parsing library. By
280
- default, JSON will be parsed with [okjson][]. For faster JSON parsing, we
281
- recommend [Oj][].
561
+ ![Entity-relationship diagram][erd]
282
562
 
283
- [okjson]: https://github.com/ddollar/okjson
284
- [oj]: https://rubygems.org/gems/oj
563
+ [erd]: https://github.com/sferik/twitter/raw/master/etc/erd.png "Entity-relationship diagram"
285
564
 
286
- ## Statistics
287
- Here are some fun facts about this library:
565
+ This entity-relationship diagram is generated programatically. If you add or
566
+ remove any Twitter objects, please regenerate the ERD with the following
567
+ command:
288
568
 
289
- * It is implemented in just 2,000 lines of Ruby code
290
- * With over 5,000 lines of specs, the spec-to-code ratio is about 2.5:1
291
- * The spec suite contains over 750 examples and runs in about 5 seconds
292
- * It has 100% C0 code coverage (the tests execute every line of
293
- source code at least once)
294
- * It is comprehensive: you can request all documented Twitter REST API
295
- resources (over 100 resources)
296
- * This gem works on every major Ruby implementation, including JRuby and
297
- Rubinius
298
- * The first version was released on November 26, 2006
299
- * This gem has just three runtime dependencies: `faraday`, `multi_json`, and
300
- `simple_oauth`
301
- * Previous versions of this gem have been [downloaded over half a million
302
- times][stats]
303
-
304
- [stats]: https://rubygems.org/gems/twitter
569
+ bundle exec rake erd
305
570
 
306
571
  ## Supported Ruby Versions
307
572
  This library aims to support and is [tested against][travis] the following Ruby
@@ -340,133 +605,8 @@ Constraint][pvc] with two digits of precision. For example:
340
605
  [semver]: http://semver.org/
341
606
  [pvc]: http://docs.rubygems.org/read/chapter/16#page74
342
607
 
343
- ## What's new in version 4?
344
- #### Twitter API v1.1
345
- Version 4 of this library targets Twitter API v1.1. To understand the
346
- implications of this change, please read the following announcements from
347
- Twitter:
348
-
349
- * [Changes coming in Version 1.1 of the Twitter API][coming]
350
- * [Current status: API v1.1][status]
351
- * [Overview: Version 1.1 of the Twitter API][overview]
352
-
353
- [coming]: https://dev.twitter.com/blog/changes-coming-to-twitter-api
354
- [status]: https://dev.twitter.com/blog/current-status-api-v1.1
355
- [overview]: https://dev.twitter.com/docs/api/1.1/overview
356
-
357
- Despite the removal of certain underlying functionality in Twitter API v1.1,
358
- this library aims to preserve backward-compatibility wherever possible. For
359
- example, despite the removal of the [`GET
360
- statuses/retweeted_by_user`][retweeted_by_user] resource, the
361
- `Twitter::API#retweeted_by_user` method continues to exist, implemented by
362
- making multiple requests to the [`GET statuses/user_timeline`][user_timeline]
363
- resource. As a result, there is no longer a one-to-one correlation between
364
- method calls and Twitter API requests. In fact, it's possible for a single
365
- method call to exceed the Twitter API rate limit for a resource. If you think
366
- this might cause a problem for your application, feel free to [join the
367
- discussion][discussion].
368
-
369
- [retweeted_by_user]: https://dev.twitter.com/docs/api/1/get/statuses/retweeted_by_user
370
- [user_timeline]: https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline
371
- [discussion]: https://dev.twitter.com/discussions/10644
372
-
373
- #### Rate Limiting
374
- Another consequence of Twitter API v1.1 is that the
375
- `Twitter::Client#rate_limit` method has been removed, since the concept of a
376
- client-wide rate limit no longer exists. Rate limits are now applied on a
377
- per-resource level, however, since there is no longer a one-to-one mapping
378
- between methods and Twitter API resources, it's not entirely obvious how rate
379
- limit information should be exposed. I've decided to go back to the pre-3.0.0
380
- behavior of including rate limit information on `Twitter::Error` objects.
381
- Here's an example of how to handle rate limits:
382
-
383
- ```ruby
384
- MAX_ATTEMPTS = 3
385
- num_attempts = 0
386
- begin
387
- num_attempts += 1
388
- retweets = Twitter.retweeted_by_user("sferik")
389
- rescue Twitter::Error::TooManyRequests => error
390
- if num_attempts <= MAX_ATTEMPTS
391
- # NOTE: Your process could go to sleep for up to 15 minutes but if you
392
- # retry any sooner, it will almost certainly fail with the same exception.
393
- sleep error.rate_limit.reset_in
394
- retry
395
- else
396
- raise
397
- end
398
- end
399
- ```
400
- #### Methods Missing
401
- As a consequence of moving to Twitter API v1.1, the following methods from
402
- version 3 are no longer available in version 4:
403
-
404
- * `Twitter::API#accept`
405
- * `Twitter::API#deny`
406
- * `Twitter::API#disable_notifications`
407
- * `Twitter::API#enable_notifications`
408
- * `Twitter::API#end_session`
409
- * `Twitter::API#rate_limit_status`
410
- * `Twitter::API#rate_limited?`
411
- * `Twitter::API#recommendations`
412
- * `Twitter::API#related_results`
413
- * `Twitter::API#retweeted_to_user`
414
- * `Twitter::API#trends_daily`
415
- * `Twitter::API#trends_weekly`
416
- * `Twitter::Client#rate_limit`
417
- * `Twitter::RateLimit#class`
418
-
419
- #### Custom Endpoints
420
- The `Twitter::API#update_with_media` method no longer uses the custom
421
- `upload.twitter.com` endpoint, so `media_endpoint` configuration has been
422
- removed. Likewise, the `Twitter::API#search` method no longer uses the custom
423
- `search.twitter.com` endpoint, so `search_endpoint` configuration has also been
424
- removed.
425
-
426
- #### Errors
427
- It's worth mentioning new error classes:
428
-
429
- * `Twitter::Error::GatewayTimeout`
430
- * `Twitter::Error::TooManyRequests`
431
- * `Twitter::Error::UnprocessableEntity`
432
-
433
- In previous versions of this library, rate limit errors were indicated by
434
- raising either `Twitter::Error::BadRequest` or
435
- `Twitter::Error::EnhanceYourCalm` (for the Search API). As of version 4, the
436
- library will raise `Twitter::Error::TooManyRequests` for all rate limit errors.
437
- The `Twitter::Error::EnhanceYourCalm` class has been aliased to
438
- `Twitter::Error::TooManyRequests`.
439
-
440
- #### Identity Map
441
- In version 4, the identity map is [disabled by default][disabled]. If you want
442
- to enable this feature, you can use the [default identity map][default] or
443
- [write a custom identity map][custom].
444
-
445
- ```ruby
446
- Twitter.identity_map = Twitter::IdentityMap
447
- ```
448
-
449
- [disabled]: https://github.com/sferik/twitter/commit/c6c5960bea998abdc3e82cbb8dd68766a2df52e1
450
- [default]: lib/twitter/identity_map.rb
451
- [custom]: etc/sqlite_identity_map.rb
452
-
453
- ## Additional Notes
454
- This will be the last major version of this library to support Ruby 1.8.
455
- Requiring Ruby 1.9 will allow us to [remove][class_variable_get]
456
- [various][each_with_object] [hacks][singleton_class] put in place to maintain
457
- Ruby 1.8 compatibility. [The first stable version of Ruby 1.9 was released on
458
- August 19, 2010.][ruby192] If you haven't found the opportunity to upgrade your
459
- Ruby interpreter since then, let this be your nudge. Once version 5 of this
460
- library is released, all previous versions will cease to be supported, even if
461
- critical security vulnerabilities are discovered.
462
-
463
- [class_variable_get]: https://github.com/sferik/twitter/commit/88c5a0513d1b58a1d4ae1a1e3deeb012c9d19547
464
- [each_with_object]: https://github.com/sferik/twitter/commit/6052252a07baf7aefe0f100bba0abd2cbb7139bb
465
- [singleton_class]: https://github.com/sferik/twitter/commit/2ed9db21c87d1218b15373e42a36ad536b07dcbb
466
- [ruby192]: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/367983
467
-
468
608
  ## Copyright
469
- Copyright (c) 2006-2013 John Nunemaker, Wynn Netherland, Erik Michaels-Ober, Steve Richert.
609
+ Copyright (c) 2006-2013 Erik Michaels-Ober, John Nunemaker, Wynn Netherland, Steve Richert, Steve Agalloco.
470
610
  See [LICENSE][] for details.
471
611
 
472
612
  [license]: LICENSE.md