twitter 5.8.0 → 5.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/README.md +10 -36
  4. data/lib/twitter/base.rb +20 -3
  5. data/lib/twitter/basic_user.rb +6 -4
  6. data/lib/twitter/client.rb +2 -1
  7. data/lib/twitter/configuration.rb +1 -1
  8. data/lib/twitter/cursor.rb +1 -1
  9. data/lib/twitter/entities.rb +10 -6
  10. data/lib/twitter/enumerable.rb +2 -2
  11. data/lib/twitter/error.rb +7 -0
  12. data/lib/twitter/geo_results.rb +1 -1
  13. data/lib/twitter/list.rb +3 -2
  14. data/lib/twitter/media/photo.rb +1 -1
  15. data/lib/twitter/place.rb +13 -15
  16. data/lib/twitter/profile.rb +1 -1
  17. data/lib/twitter/profile_banner.rb +1 -1
  18. data/lib/twitter/rest/client.rb +17 -2
  19. data/lib/twitter/rest/friends_and_followers.rb +1 -1
  20. data/lib/twitter/rest/lists.rb +4 -2
  21. data/lib/twitter/rest/spam_reporting.rb +1 -1
  22. data/lib/twitter/rest/tweets.rb +17 -17
  23. data/lib/twitter/rest/users.rb +77 -13
  24. data/lib/twitter/rest/utils.rb +10 -6
  25. data/lib/twitter/search_results.rb +1 -1
  26. data/lib/twitter/settings.rb +4 -3
  27. data/lib/twitter/source_user.rb +3 -2
  28. data/lib/twitter/streaming/client.rb +7 -2
  29. data/lib/twitter/streaming/connection.rb +9 -2
  30. data/lib/twitter/streaming/response.rb +3 -3
  31. data/lib/twitter/suggestion.rb +1 -1
  32. data/lib/twitter/target_user.rb +1 -1
  33. data/lib/twitter/trend.rb +2 -1
  34. data/lib/twitter/trend_results.rb +1 -1
  35. data/lib/twitter/tweet.rb +4 -4
  36. data/lib/twitter/user.rb +60 -19
  37. data/lib/twitter/utils.rb +12 -5
  38. data/lib/twitter/version.rb +1 -1
  39. data/spec/fixtures/following.json +1 -1
  40. data/spec/fixtures/sferik.json +1 -1
  41. data/spec/helper.rb +14 -5
  42. data/spec/twitter/base_spec.rb +16 -4
  43. data/spec/twitter/direct_message_spec.rb +12 -13
  44. data/spec/twitter/entity/uri_spec.rb +2 -2
  45. data/spec/twitter/error_spec.rb +2 -2
  46. data/spec/twitter/media/photo_spec.rb +4 -4
  47. data/spec/twitter/oembed_spec.rb +3 -3
  48. data/spec/twitter/place_spec.rb +1 -1
  49. data/spec/twitter/rest/client_spec.rb +54 -14
  50. data/spec/twitter/rest/friends_and_followers_spec.rb +76 -76
  51. data/spec/twitter/rest/lists_spec.rb +85 -64
  52. data/spec/twitter/rest/timelines_spec.rb +2 -2
  53. data/spec/twitter/rest/tweets_spec.rb +20 -16
  54. data/spec/twitter/rest/undocumented_spec.rb +17 -17
  55. data/spec/twitter/rest/users_spec.rb +101 -17
  56. data/spec/twitter/streaming/client_spec.rb +1 -1
  57. data/spec/twitter/streaming/connection_spec.rb +32 -0
  58. data/spec/twitter/streaming/response_spec.rb +21 -0
  59. data/spec/twitter/trend_spec.rb +1 -1
  60. data/spec/twitter/tweet_spec.rb +14 -23
  61. data/spec/twitter/user_spec.rb +120 -13
  62. data/twitter.gemspec +3 -3
  63. metadata +8 -4
@@ -151,7 +151,7 @@ module Twitter
151
151
  # @param users [Enumerable<Integer, String, Twitter::User>] A collection of Twitter user IDs, screen names, or objects.
152
152
  # @param options [Hash] A customizable set of options.
153
153
  def unfollow(*args)
154
- parallel_user_objects_from_response(:post, '/1.1/friendships/destroy.json', args)
154
+ parallel_users_from_response(:post, '/1.1/friendships/destroy.json', args)
155
155
  end
156
156
  alias_method :destroy_friendship, :unfollow
157
157
  deprecate_alias :friendship_destroy, :unfollow
@@ -477,10 +477,12 @@ module Twitter
477
477
  # @param user[Integer, String, Twitter::User] A Twitter user ID, screen_name, or object.
478
478
  # @return [Hash]
479
479
  def merge_owner!(hash, user)
480
- unless hash[:owner_id] || hash[:owner_screen_name]
481
- user ||= screen_name
480
+ return hash if hash[:owner_id] || hash[:owner_screen_name]
481
+ if user
482
482
  merge_user!(hash, user, 'owner')
483
483
  hash[:owner_id] = hash.delete(:owner_user_id) unless hash[:owner_user_id].nil?
484
+ else
485
+ hash[:owner_id] = user_id
484
486
  end
485
487
  hash
486
488
  end
@@ -20,7 +20,7 @@ module Twitter
20
20
  # @param users [Enumerable<Integer, String, Twitter::User>] A collection of Twitter user IDs, screen names, or objects.
21
21
  # @param options [Hash] A customizable set of options.
22
22
  def report_spam(*args)
23
- parallel_user_objects_from_response(:post, '/1.1/users/report_spam.json', args)
23
+ parallel_users_from_response(:post, '/1.1/users/report_spam.json', args)
24
24
  end
25
25
  end
26
26
  end
@@ -11,6 +11,7 @@ module Twitter
11
11
  module Tweets
12
12
  include Twitter::REST::Utils
13
13
  include Twitter::Utils
14
+ MAX_TWEETS_PER_REQUEST = 100
14
15
 
15
16
  # Returns up to 100 of the first retweets of a given tweet
16
17
  #
@@ -38,7 +39,7 @@ module Twitter
38
39
  # @param options [Hash] A customizable set of options.
39
40
  # @option options [Integer] :count Specifies the number of records to retrieve. Must be less than or equal to 100.
40
41
  # @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
41
- # @option options [Boolean] :ids_only ('false') Only return user ids instead of full user objects.
42
+ # @option options [Boolean] :ids_only ('false') Only return user IDs instead of full user objects.
42
43
  def retweeters_of(tweet, options = {})
43
44
  ids_only = !!options.delete(:ids_only)
44
45
  retweeters = retweets(tweet, options).collect(&:user)
@@ -62,19 +63,24 @@ module Twitter
62
63
 
63
64
  # Returns Tweets
64
65
  #
65
- # @see https://dev.twitter.com/docs/api/1.1/get/statuses/show/:id
66
+ # @see https://dev.twitter.com/docs/api/1.1/get/statuses/lookup
66
67
  # @rate_limited Yes
67
- # @authentication Requires user context
68
- # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
68
+ # @authentication Required
69
69
  # @return [Array<Twitter::Tweet>] The requested Tweets.
70
70
  # @overload statuses(*tweets)
71
71
  # @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
72
72
  # @overload statuses(*tweets, options)
73
73
  # @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
74
74
  # @param options [Hash] A customizable set of options.
75
+ # @option options [Symbol, String] :method Requests users via a GET request instead of the standard POST request if set to ':get'.
76
+ # @option options [Boolean] :include_entities The tweet entities node will be disincluded when set to false.
75
77
  # @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
76
78
  def statuses(*args)
77
- parallel_tweets_from_response(:get, '/1.1/statuses/show', args)
79
+ arguments = Twitter::Arguments.new(args)
80
+ request_method = arguments.options.delete(:method) || :post
81
+ flat_pmap(arguments.each_slice(MAX_TWEETS_PER_REQUEST)) do |tweets|
82
+ perform_with_objects(request_method, '/1.1/statuses/lookup.json', arguments.options.merge(:id => tweets.collect { |u| extract_id(u) }.join(',')), Twitter::Tweet)
83
+ end
78
84
  end
79
85
 
80
86
  # Destroys the specified Tweets
@@ -92,7 +98,10 @@ module Twitter
92
98
  # @param options [Hash] A customizable set of options.
93
99
  # @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
94
100
  def destroy_status(*args)
95
- parallel_tweets_from_response(:post, '/1.1/statuses/destroy', args)
101
+ arguments = Twitter::Arguments.new(args)
102
+ pmap(arguments) do |tweet|
103
+ perform_with_object(:post, "/1.1/statuses/destroy/#{extract_id(tweet)}.json", arguments.options, Twitter::Tweet)
104
+ end
96
105
  end
97
106
  alias_method :destroy_tweet, :destroy_status
98
107
  deprecate_alias :status_destroy, :destroy_status
@@ -200,6 +209,7 @@ module Twitter
200
209
  # @rate_limited No
201
210
  # @authentication Requires user context
202
211
  # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
212
+ # @raise [Twitter::Error::UnacceptableIO] Error when the IO object for the media argument does not have a to_io method.
203
213
  # @return [Twitter::Tweet] The created Tweet.
204
214
  # @param status [String] The text of your status update, up to 140 characters.
205
215
  # @param media [File, Hash] A File object with your picture (PNG, JPEG or GIF)
@@ -214,6 +224,7 @@ module Twitter
214
224
  # @option options [String] :display_coordinates Whether or not to put a pin on the exact coordinates a tweet has been sent from.
215
225
  # @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
216
226
  def update_with_media(status, media, options = {})
227
+ fail(Twitter::Error::UnacceptableIO.new) unless media.respond_to?(:to_io)
217
228
  hash = options.dup
218
229
  hash[:in_reply_to_status_id] = hash.delete(:in_reply_to_status).id unless hash[:in_reply_to_status].nil?
219
230
  hash[:place_id] = hash.delete(:place).woeid unless hash[:place].nil?
@@ -287,17 +298,6 @@ module Twitter
287
298
 
288
299
  private
289
300
 
290
- # @param request_method [Symbol]
291
- # @param path [String]
292
- # @param args [Array]
293
- # @return [Array<Twitter::Tweet>]
294
- def parallel_tweets_from_response(request_method, path, args)
295
- arguments = Twitter::Arguments.new(args)
296
- pmap(arguments) do |tweet|
297
- perform_with_object(request_method, path + "/#{extract_id(tweet)}.json", arguments.options, Twitter::Tweet)
298
- end
299
- end
300
-
301
301
  def post_retweet(tweet, options)
302
302
  response = post("/1.1/statuses/retweet/#{extract_id(tweet)}.json", options).body
303
303
  Twitter::Tweet.new(response)
@@ -34,7 +34,7 @@ module Twitter
34
34
  request_method = options.size.zero? ? :get : :post
35
35
  response = send(request_method.to_sym, '/1.1/account/settings.json', options).body
36
36
  # https://dev.twitter.com/issues/59
37
- response.update(:trend_location => Array(response[:trend_location]).first)
37
+ response.update(:trend_location => response.fetch(:trend_location, []).first)
38
38
  Twitter::Settings.new(response)
39
39
  end
40
40
 
@@ -136,19 +136,21 @@ module Twitter
136
136
  # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
137
137
  # @return [Array<Twitter::User>] User objects that the authenticating user is blocking.
138
138
  # @param options [Hash] A customizable set of options.
139
- # @option options [Integer] :page Specifies the page of results to retrieve.
140
- def blocking(options = {})
139
+ # @option options [Boolean] :include_entities The tweet entities node will be disincluded when set to false.
140
+ # @option options [Boolean, String, Integer] :skip_status Do not include user's Tweets when set to true, 't' or 1.
141
+ def blocked(options = {})
141
142
  perform_with_cursor(:get, '/1.1/blocks/list.json', options, :users, Twitter::User)
142
143
  end
144
+ deprecate_alias :blocking, :blocked
143
145
 
144
- # Returns an array of numeric user ids the authenticating user is blocking
146
+ # Returns an array of numeric user IDs the authenticating user is blocking
145
147
  #
146
148
  # @see https://dev.twitter.com/docs/api/1.1/get/blocks/ids
147
149
  # @rate_limited Yes
148
150
  # @authentication Requires user context
149
151
  # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
150
152
  # @return [Twitter::Cursor] Numeric user IDs the authenticating user is blocking.
151
- # @overload block(options = {})
153
+ # @overload blocked_ids(options = {})
152
154
  # @param options [Hash] A customizable set of options.
153
155
  def blocked_ids(*args)
154
156
  arguments = Twitter::Arguments.new(args)
@@ -191,7 +193,7 @@ module Twitter
191
193
  # @param users [Enumerable<Integer, String, Twitter::User>] A collection of Twitter user IDs, screen names, or objects.
192
194
  # @param options [Hash] A customizable set of options.
193
195
  def block(*args)
194
- parallel_user_objects_from_response(:post, '/1.1/blocks/create.json', args)
196
+ parallel_users_from_response(:post, '/1.1/blocks/create.json', args)
195
197
  end
196
198
 
197
199
  # Un-blocks the users specified by the authenticating user
@@ -207,14 +209,14 @@ module Twitter
207
209
  # @param users [Enumerable<Integer, String, Twitter::User>] A collection of Twitter user IDs, screen names, or objects.
208
210
  # @param options [Hash] A customizable set of options.
209
211
  def unblock(*args)
210
- parallel_user_objects_from_response(:post, '/1.1/blocks/destroy.json', args)
212
+ parallel_users_from_response(:post, '/1.1/blocks/destroy.json', args)
211
213
  end
212
214
 
213
215
  # Returns extended information for up to 100 users
214
216
  #
215
217
  # @see https://dev.twitter.com/docs/api/1.1/get/users/lookup
216
218
  # @rate_limited Yes
217
- # @authentication Requires user context
219
+ # @authentication Required
218
220
  # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
219
221
  # @return [Array<Twitter::User>] The requested users.
220
222
  # @overload users(*users)
@@ -252,8 +254,8 @@ module Twitter
252
254
  # @option options [Boolean, String, Integer] :skip_status Do not include user's Tweets when set to true, 't' or 1.
253
255
  def user(*args)
254
256
  arguments = Twitter::Arguments.new(args)
255
- if arguments.last
256
- merge_user!(arguments.options, arguments.pop)
257
+ if arguments.last || user_id?
258
+ merge_user!(arguments.options, arguments.pop || user_id)
257
259
  perform_with_object(:get, '/1.1/users/show.json', arguments.options, Twitter::User)
258
260
  else
259
261
  verify_credentials(arguments.options)
@@ -305,7 +307,7 @@ module Twitter
305
307
  # @param options [Hash] A customizable set of options.
306
308
  # @option options [Boolean, String, Integer] :skip_status Do not include contributee's Tweets when set to true, 't' or 1.
307
309
  def contributees(*args)
308
- user_objects_from_response(:get, '/1.1/users/contributees.json', args)
310
+ users_from_response(:get, '/1.1/users/contributees.json', args)
309
311
  end
310
312
 
311
313
  # Returns an array of users who can contribute to the specified account
@@ -323,7 +325,7 @@ module Twitter
323
325
  # @param options [Hash] A customizable set of options.
324
326
  # @option options [Boolean, String, Integer] :skip_status Do not include contributee's Tweets when set to true, 't' or 1.
325
327
  def contributors(*args)
326
- user_objects_from_response(:get, '/1.1/users/contributors.json', args)
328
+ users_from_response(:get, '/1.1/users/contributors.json', args)
327
329
  end
328
330
 
329
331
  # Removes the authenticating user's profile banner image
@@ -375,9 +377,71 @@ module Twitter
375
377
  # @param user [Integer, String, Twitter::User] A Twitter user ID, screen name, URI, or object.
376
378
  def profile_banner(*args)
377
379
  arguments = Twitter::Arguments.new(args)
378
- merge_user!(arguments.options, arguments.pop || screen_name) unless arguments.options[:user_id] || arguments.options[:screen_name]
380
+ merge_user!(arguments.options, arguments.pop || user_id) unless arguments.options[:user_id] || arguments.options[:screen_name]
379
381
  perform_with_object(:get, '/1.1/users/profile_banner.json', arguments.options, Twitter::ProfileBanner)
380
382
  end
383
+
384
+ # Mutes the users specified by the authenticating user
385
+ #
386
+ # @see https://dev.twitter.com/docs/api/1.1/post/mutes/users/create
387
+ # @rate_limited Yes
388
+ # @authentication Requires user context
389
+ # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
390
+ # @return [Array<Twitter::User>] The muted users.
391
+ # @overload mute(*users)
392
+ # @param users [Enumerable<Integer, String, Twitter::User>] A collection of Twitter user IDs, screen names, or objects.
393
+ # @overload mute(*users, options)
394
+ # @param users [Enumerable<Integer, String, Twitter::User>] A collection of Twitter user IDs, screen names, or objects.
395
+ # @param options [Hash] A customizable set of options.
396
+ def mute(*args)
397
+ parallel_users_from_response(:post, '/1.1/mutes/users/create.json', args)
398
+ end
399
+
400
+ # Un-mutes the user specified by the authenticating user.
401
+ #
402
+ # @see https://dev.twitter.com/docs/api/1.1/post/mutes/users/destroy
403
+ # @rate_limited Yes
404
+ # @authentication Requires user context
405
+ # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
406
+ # @return [Array<Twitter::User>] The un-muted users.
407
+ # @overload unmute(*users)
408
+ # @param users [Enumerable<Integer, String, Twitter::User>] A collection of Twitter user IDs, screen names, or objects.
409
+ # @overload unmute(*users, options)
410
+ # @param users [Enumerable<Integer, String, Twitter::User>] A collection of Twitter user IDs, screen names, or objects.
411
+ # @param options [Hash] A customizable set of options.
412
+ def unmute(*args)
413
+ parallel_users_from_response(:post, '/1.1/mutes/users/destroy.json', args)
414
+ end
415
+
416
+ # Returns an array of user objects that the authenticating user is muting
417
+ #
418
+ # @see https://dev.twitter.com/docs/api/1.1/get/mutes/users/list
419
+ # @rate_limited Yes
420
+ # @authentication Requires user context
421
+ # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
422
+ # @return [Array<Twitter::User>] User objects that the authenticating user is muting.
423
+ # @param options [Hash] A customizable set of options.
424
+ # @option options [Boolean] :include_entities The tweet entities node will be disincluded when set to false.
425
+ # @option options [Boolean, String, Integer] :skip_status Do not include user's Tweets when set to true, 't' or 1.
426
+ def muted(options = {})
427
+ perform_with_cursor(:get, '/1.1/mutes/users/list.json', options, :users, Twitter::User)
428
+ end
429
+ deprecate_alias :muting, :muted
430
+
431
+ # Returns an array of numeric user IDs the authenticating user is muting
432
+ #
433
+ # @see https://dev.twitter.com/docs/api/1.1/get/mutes/users/ids
434
+ # @rate_limited Yes
435
+ # @authentication Requires user context
436
+ # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
437
+ # @return [Twitter::Cursor] Numeric user IDs the authenticating user is muting
438
+ # @overload muted_ids(options = {})
439
+ # @param options [Hash] A customizable set of options.
440
+ def muted_ids(*args)
441
+ arguments = Twitter::Arguments.new(args)
442
+ merge_user!(arguments.options, arguments.pop)
443
+ perform_with_cursor(:get, '/1.1/mutes/users/ids.json', arguments.options, :ids)
444
+ end
381
445
  end
382
446
  end
383
447
  end
@@ -62,7 +62,7 @@ module Twitter
62
62
  # @param path [String]
63
63
  # @param args [Array]
64
64
  # @return [Array<Twitter::User>]
65
- def parallel_user_objects_from_response(request_method, path, args)
65
+ def parallel_users_from_response(request_method, path, args)
66
66
  arguments = Twitter::Arguments.new(args)
67
67
  pmap(arguments) do |user|
68
68
  perform_with_object(request_method, path, merge_user(arguments.options, user), Twitter::User)
@@ -73,9 +73,9 @@ module Twitter
73
73
  # @param path [String]
74
74
  # @param args [Array]
75
75
  # @return [Array<Twitter::User>]
76
- def user_objects_from_response(request_method, path, args)
76
+ def users_from_response(request_method, path, args)
77
77
  arguments = Twitter::Arguments.new(args)
78
- merge_user!(arguments.options, arguments.pop || screen_name) unless arguments.options[:user_id] || arguments.options[:screen_name]
78
+ merge_user!(arguments.options, arguments.pop || user_id) unless arguments.options[:user_id] || arguments.options[:screen_name]
79
79
  perform_with_objects(request_method, path, arguments.options, Twitter::User)
80
80
  end
81
81
 
@@ -110,12 +110,16 @@ module Twitter
110
110
  # @return [Twitter::Cursor]
111
111
  def cursor_from_response_with_user(collection_name, klass, request_method, path, args) # rubocop:disable ParameterLists
112
112
  arguments = Twitter::Arguments.new(args)
113
- merge_user!(arguments.options, arguments.pop || screen_name) unless arguments.options[:user_id] || arguments.options[:screen_name]
113
+ merge_user!(arguments.options, arguments.pop || user_id) unless arguments.options[:user_id] || arguments.options[:screen_name]
114
114
  perform_with_cursor(request_method, path, arguments.options, collection_name, klass)
115
115
  end
116
116
 
117
- def screen_name
118
- @screen_name ||= verify_credentials.screen_name
117
+ def user_id
118
+ @user_id ||= verify_credentials(:include_entities => false, :skip_status => true).id
119
+ end
120
+
121
+ def user_id?
122
+ instance_variable_defined?(:@user_id)
119
123
  end
120
124
 
121
125
  def merge_default_cursor!(options)
@@ -58,7 +58,7 @@ module Twitter
58
58
  # @return [Hash]
59
59
  def attrs=(attrs)
60
60
  @attrs = attrs
61
- Array(@attrs[:statuses]).collect do |tweet|
61
+ @attrs.fetch(:statuses, []).collect do |tweet|
62
62
  @collection << Tweet.new(tweet)
63
63
  end
64
64
  @attrs
@@ -2,9 +2,10 @@ require 'twitter/base'
2
2
 
3
3
  module Twitter
4
4
  class Settings < Twitter::Base
5
- attr_reader :always_use_https, :discoverable_by_email, :geo_enabled,
6
- :language, :protected, :screen_name, :show_all_inline_media,
7
- :sleep_time, :time_zone
5
+ attr_reader :language, :screen_name, :sleep_time, :time_zone
8
6
  object_attr_reader :Place, :trend_location
7
+ predicate_attr_reader :always_use_https, :discoverable_by_email,
8
+ :geo_enabled, :protected, :show_all_inline_media,
9
+ :use_cookie_personalization
9
10
  end
10
11
  end
@@ -2,7 +2,8 @@ require 'twitter/basic_user'
2
2
 
3
3
  module Twitter
4
4
  class SourceUser < Twitter::BasicUser
5
- attr_reader :all_replies, :blocking, :can_dm, :followed_by, :marked_spam,
6
- :notifications_enabled, :want_retweets
5
+ predicate_attr_reader :all_replies, :blocking, :can_dm, :followed_by,
6
+ :marked_spam, :muting, :notifications_enabled,
7
+ :want_retweets
7
8
  end
8
9
  end
@@ -9,13 +9,17 @@ module Twitter
9
9
  module Streaming
10
10
  class Client < Twitter::Client
11
11
  attr_writer :connection
12
+ attr_accessor :tcp_socket_class, :ssl_socket_class
12
13
 
13
14
  # Initializes a new Client object
14
15
  #
16
+ # @param options [Hash] A customizable set of options.
17
+ # @option options [String] :tcp_socket_class A class that Connection will use to create a new TCP socket.
18
+ # @option options [String] :ssl_socket_class A class that Connection will use to create a new SSL socket.
15
19
  # @return [Twitter::Streaming::Client]
16
20
  def initialize(options = {})
17
21
  super
18
- @connection = Streaming::Connection.new
22
+ @connection = Streaming::Connection.new(options)
19
23
  end
20
24
 
21
25
  # Returns public statuses that match one or more filter predicates
@@ -77,7 +81,8 @@ module Twitter
77
81
  # @see https://dev.twitter.com/docs/streaming-apis/parameters
78
82
  # @param options [Hash] A customizable set of options.
79
83
  # @option options [String] :with Specifies whether to return information for just the users specified in the follow parameter, or include messages from accounts they follow.
80
- # @option options [String] :replies Specifies whether stall warnings should be delivered.
84
+ # @option options [String] :replies Specifies whether to return additional @replies.
85
+ # @option options [String] :stall_warnings Specifies whether stall warnings should be delivered.
81
86
  # @option options [String] :track Includes additional Tweets matching the specified keywords. Phrases of keywords are specified by a comma-separated list.
82
87
  # @option options [String] :locations Includes additional Tweets falling within the specified bounding boxes.
83
88
  # @yield [Twitter::Tweet, Twitter::Streaming::Event, Twitter::DirectMessage, Twitter::Streaming::FriendList, Twitter::Streaming::DeletedTweet, Twitter::Streaming::StallWarning] A stream of Twitter objects.
@@ -5,10 +5,17 @@ require 'resolv'
5
5
  module Twitter
6
6
  module Streaming
7
7
  class Connection
8
+ def initialize(opts = {})
9
+ @tcp_socket_class = opts.fetch(:tcp_socket_class) { TCPSocket }
10
+ @ssl_socket_class = opts.fetch(:ssl_socket_class) { OpenSSL::SSL::SSLSocket }
11
+ end
12
+ attr_reader :tcp_socket_class, :ssl_socket_class
13
+
8
14
  def stream(request, response)
9
15
  client_context = OpenSSL::SSL::SSLContext.new
10
- client = TCPSocket.new(Resolv.getaddress(request.uri.host), request.uri.port)
11
- ssl_client = OpenSSL::SSL::SSLSocket.new(client, client_context)
16
+ client = @tcp_socket_class.new(Resolv.getaddress(request.uri.host), request.uri.port)
17
+ ssl_client = @ssl_socket_class.new(client, client_context)
18
+
12
19
  ssl_client.connect
13
20
  request.stream(ssl_client)
14
21
  while body = ssl_client.readpartial(1024) # rubocop:disable AssignmentInCondition, WhileUntilModifier
@@ -16,9 +16,9 @@ module Twitter
16
16
  @parser << data
17
17
  end
18
18
 
19
- def on_headers_complete(headers)
20
- # TODO: handle response codes
21
- p(:status_code => @parser.status_code, :header => headers) unless @parser.status_code == 200
19
+ def on_headers_complete(_headers)
20
+ error = Twitter::Error.errors[@parser.status_code]
21
+ fail error.new if error
22
22
  end
23
23
 
24
24
  def on_body(data)
@@ -8,7 +8,7 @@ module Twitter
8
8
 
9
9
  # @return [Array<Twitter::User>]
10
10
  def users
11
- Array(@attrs[:users]).collect do |user|
11
+ @attrs.fetch(:users, []).collect do |user|
12
12
  User.new(user)
13
13
  end
14
14
  end
@@ -2,6 +2,6 @@ require 'twitter/basic_user'
2
2
 
3
3
  module Twitter
4
4
  class TargetUser < Twitter::BasicUser
5
- attr_reader :followed_by
5
+ predicate_attr_reader :followed_by
6
6
  end
7
7
  end
@@ -4,7 +4,8 @@ require 'twitter/base'
4
4
  module Twitter
5
5
  class Trend < Twitter::Base
6
6
  include Equalizer.new(:name)
7
- attr_reader :events, :name, :promoted_content, :query
7
+ attr_reader :events, :name, :query
8
+ predicate_attr_reader :promoted_content
8
9
  uri_attr_reader :uri
9
10
  end
10
11
  end