twitter 6.1.0 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +22 -15
  3. data/README.md +69 -394
  4. data/lib/twitter/base.rb +2 -16
  5. data/lib/twitter/basic_user.rb +0 -3
  6. data/lib/twitter/client.rb +5 -19
  7. data/lib/twitter/configuration.rb +3 -2
  8. data/lib/twitter/creatable.rb +1 -1
  9. data/lib/twitter/cursor.rb +0 -1
  10. data/lib/twitter/entity/uri.rb +0 -4
  11. data/lib/twitter/error.rb +81 -96
  12. data/lib/twitter/geo_results.rb +0 -1
  13. data/lib/twitter/headers.rb +11 -10
  14. data/lib/twitter/media/photo.rb +4 -0
  15. data/lib/twitter/media/video.rb +4 -1
  16. data/lib/twitter/media/video_info.rb +1 -1
  17. data/lib/twitter/null_object.rb +2 -2
  18. data/lib/twitter/profile.rb +3 -2
  19. data/lib/twitter/rate_limit.rb +1 -1
  20. data/lib/twitter/rest/api.rb +0 -2
  21. data/lib/twitter/rest/client.rb +0 -78
  22. data/lib/twitter/rest/direct_messages.rb +3 -3
  23. data/lib/twitter/rest/favorites.rb +25 -4
  24. data/lib/twitter/rest/friends_and_followers.rb +1 -3
  25. data/lib/twitter/rest/lists.rb +18 -29
  26. data/lib/twitter/rest/oauth.rb +15 -15
  27. data/lib/twitter/rest/request.rb +105 -16
  28. data/lib/twitter/rest/saved_searches.rb +0 -2
  29. data/lib/twitter/rest/search.rb +2 -0
  30. data/lib/twitter/rest/trends.rb +1 -0
  31. data/lib/twitter/rest/tweets.rb +80 -15
  32. data/lib/twitter/rest/undocumented.rb +3 -4
  33. data/lib/twitter/rest/users.rb +20 -34
  34. data/lib/twitter/rest/utils.rb +13 -20
  35. data/lib/twitter/search_results.rb +1 -2
  36. data/lib/twitter/streaming/client.rb +17 -23
  37. data/lib/twitter/streaming/connection.rb +23 -10
  38. data/lib/twitter/streaming/deleted_tweet.rb +0 -1
  39. data/lib/twitter/streaming/event.rb +6 -6
  40. data/lib/twitter/streaming/message_parser.rb +1 -1
  41. data/lib/twitter/streaming/response.rb +2 -2
  42. data/lib/twitter/trend_results.rb +1 -2
  43. data/lib/twitter/tweet.rb +1 -5
  44. data/lib/twitter/user.rb +0 -2
  45. data/lib/twitter/utils.rb +1 -16
  46. data/lib/twitter/version.rb +1 -1
  47. data/twitter.gemspec +13 -13
  48. metadata +35 -27
  49. data/lib/twitter/rest/media.rb +0 -30
  50. data/lib/twitter/rest/request/multipart_with_file.rb +0 -47
  51. data/lib/twitter/rest/response/parse_error_json.rb +0 -13
  52. data/lib/twitter/rest/response/parse_json.rb +0 -31
  53. data/lib/twitter/rest/response/raise_error.rb +0 -32
  54. data/lib/twitter/token.rb +0 -20
@@ -13,7 +13,6 @@ module Twitter
13
13
  attr_reader :attrs
14
14
  alias to_h attrs
15
15
  alias to_hash to_h
16
- deprecate_alias :to_hsh, :to_hash
17
16
 
18
17
  class << self
19
18
  # Define methods that retrieve the value from attributes
@@ -29,7 +28,6 @@ module Twitter
29
28
  def predicate_attr_reader(*attrs)
30
29
  attrs.each do |attr|
31
30
  define_predicate_method(attr)
32
- deprecate_attribute_method(attr)
33
31
  end
34
32
  end
35
33
 
@@ -87,25 +85,13 @@ module Twitter
87
85
  define_method(key1) do
88
86
  if attr_falsey_or_empty?(key1)
89
87
  NullObject.new
90
- elsif klass.nil?
91
- @attrs[key1]
92
88
  else
93
- attrs = attrs_for_object(key1, key2)
94
- Twitter.const_get(klass).new(attrs)
89
+ klass.nil? ? @attrs[key1] : Twitter.const_get(klass).new(attrs_for_object(key1, key2))
95
90
  end
96
91
  end
97
92
  memoize(key1)
98
93
  end
99
94
 
100
- # @param key [Symbol]
101
- def deprecate_attribute_method(key)
102
- define_method(key) do
103
- warn "#{Kernel.caller.first}: [DEPRECATION] ##{key} is deprecated. Use ##{key}? instead."
104
- @attrs[key]
105
- end
106
- memoize(key)
107
- end
108
-
109
95
  # Dynamically define a predicate method for an attribute
110
96
  #
111
97
  # @param key1 [Symbol]
@@ -139,7 +125,7 @@ module Twitter
139
125
  private
140
126
 
141
127
  def attr_falsey_or_empty?(key)
142
- @attrs[key].nil? || @attrs[key] == false || @attrs[key].respond_to?(:empty?) && @attrs[key].empty?
128
+ !@attrs[key] || @attrs[key].respond_to?(:empty?) && @attrs[key].empty?
143
129
  end
144
130
 
145
131
  def attrs_for_object(key1, key2 = nil)
@@ -5,9 +5,6 @@ module Twitter
5
5
  class BasicUser < Twitter::Identity
6
6
  # @return [String]
7
7
  attr_reader :screen_name
8
- deprecate_alias :handle, :screen_name
9
- deprecate_alias :username, :screen_name
10
- deprecate_alias :user_name, :screen_name
11
8
  predicate_attr_reader :following
12
9
  end
13
10
  end
@@ -5,12 +5,8 @@ require 'twitter/version'
5
5
  module Twitter
6
6
  class Client
7
7
  include Twitter::Utils
8
- attr_accessor :access_token, :access_token_secret, :consumer_key, :consumer_secret, :proxy
8
+ attr_accessor :access_token, :access_token_secret, :consumer_key, :consumer_secret, :proxy, :timeouts
9
9
  attr_writer :user_agent
10
- deprecate_alias :oauth_token, :access_token
11
- deprecate_alias :oauth_token=, :access_token=
12
- deprecate_alias :oauth_token_secret, :access_token_secret
13
- deprecate_alias :oauth_token_secret=, :access_token_secret=
14
10
 
15
11
  # Initializes a new Client object
16
12
  #
@@ -21,12 +17,11 @@ module Twitter
21
17
  instance_variable_set("@#{key}", value)
22
18
  end
23
19
  yield(self) if block_given?
24
- validate_credentials!
25
20
  end
26
21
 
27
22
  # @return [Boolean]
28
23
  def user_token?
29
- !!(access_token && access_token_secret)
24
+ !(blank?(access_token) || blank?(access_token_secret))
30
25
  end
31
26
 
32
27
  # @return [String]
@@ -41,27 +36,18 @@ module Twitter
41
36
  consumer_secret: consumer_secret,
42
37
  token: access_token,
43
38
  token_secret: access_token_secret,
44
- ignore_extra_keys: true,
45
39
  }
46
40
  end
47
41
 
48
42
  # @return [Boolean]
49
43
  def credentials?
50
- credentials.values.all?
44
+ credentials.values.none? { |v| blank?(v) }
51
45
  end
52
46
 
53
47
  private
54
48
 
55
- # Ensures that all credentials set during configuration are of a
56
- # valid type. Valid types are String and Boolean.
57
- #
58
- # @raise [Twitter::Error::ConfigurationError] Error is raised when
59
- # supplied twitter credentials are not a String or Boolean.
60
- def validate_credentials!
61
- credentials.each do |credential, value|
62
- next if value.nil? || value == true || value == false || value.is_a?(String)
63
- raise(Twitter::Error::ConfigurationError.new("Invalid #{credential} specified: #{value.inspect} must be a String."))
64
- end
49
+ def blank?(s)
50
+ s.respond_to?(:empty?) ? s.empty? : !s
65
51
  end
66
52
  end
67
53
  end
@@ -8,8 +8,9 @@ module Twitter
8
8
  # @return [Array<String>]
9
9
  attr_reader :non_username_paths
10
10
  # @return [Integer]
11
- attr_reader :characters_reserved_per_media, :max_media_per_upload,
12
- :photo_size_limit, :short_url_length, :short_url_length_https
11
+ attr_reader :characters_reserved_per_media, :dm_text_character_limit,
12
+ :max_media_per_upload, :photo_size_limit, :short_url_length,
13
+ :short_url_length_https
13
14
  alias short_uri_length short_url_length
14
15
  alias short_uri_length_https short_url_length_https
15
16
 
@@ -9,7 +9,7 @@ module Twitter
9
9
  #
10
10
  # @return [Time]
11
11
  def created_at
12
- Time.parse(@attrs[:created_at]) unless @attrs[:created_at].nil?
12
+ Time.parse(@attrs[:created_at]).utc unless @attrs[:created_at].nil?
13
13
  end
14
14
  memoize :created_at
15
15
 
@@ -10,7 +10,6 @@ module Twitter
10
10
  attr_reader :attrs
11
11
  alias to_h attrs
12
12
  alias to_hash to_h
13
- deprecate_alias :to_hsh, :to_hash
14
13
 
15
14
  # Initializes a new Cursor
16
15
  #
@@ -6,9 +6,5 @@ module Twitter
6
6
  display_uri_attr_reader
7
7
  uri_attr_reader :expanded_uri, :uri
8
8
  end
9
-
10
- URL = URI
11
- Uri = URI
12
- Url = URI
13
9
  end
14
10
  end
@@ -8,6 +8,79 @@ module Twitter
8
8
  # @return [Twitter::RateLimit]
9
9
  attr_reader :rate_limit
10
10
 
11
+ # Raised when Twitter returns a 4xx HTTP status code
12
+ ClientError = Class.new(self)
13
+
14
+ # Raised when Twitter returns the HTTP status code 400
15
+ BadRequest = Class.new(ClientError)
16
+
17
+ # Raised when Twitter returns the HTTP status code 401
18
+ Unauthorized = Class.new(ClientError)
19
+
20
+ # Raised when Twitter returns the HTTP status code 403
21
+ Forbidden = Class.new(ClientError)
22
+
23
+ # Raised when Twitter returns the HTTP status code 413
24
+ RequestEntityTooLarge = Class.new(ClientError)
25
+
26
+ # Raised when a Tweet has already been favorited
27
+ AlreadyFavorited = Class.new(Forbidden)
28
+
29
+ # Raised when a Tweet has already been retweeted
30
+ AlreadyRetweeted = Class.new(Forbidden)
31
+
32
+ # Raised when a Tweet has already been posted
33
+ DuplicateStatus = Class.new(Forbidden)
34
+
35
+ # Raised when Twitter returns the HTTP status code 404
36
+ NotFound = Class.new(ClientError)
37
+
38
+ # Raised when Twitter returns the HTTP status code 406
39
+ NotAcceptable = Class.new(ClientError)
40
+
41
+ # Raised when Twitter returns the HTTP status code 422
42
+ UnprocessableEntity = Class.new(ClientError)
43
+
44
+ # Raised when Twitter returns the HTTP status code 429
45
+ TooManyRequests = Class.new(ClientError)
46
+
47
+ # Raised when Twitter returns a 5xx HTTP status code
48
+ ServerError = Class.new(self)
49
+
50
+ # Raised when Twitter returns the HTTP status code 500
51
+ InternalServerError = Class.new(ServerError)
52
+
53
+ # Raised when Twitter returns the HTTP status code 502
54
+ BadGateway = Class.new(ServerError)
55
+
56
+ # Raised when Twitter returns the HTTP status code 503
57
+ ServiceUnavailable = Class.new(ServerError)
58
+
59
+ # Raised when Twitter returns the HTTP status code 504
60
+ GatewayTimeout = Class.new(ServerError)
61
+
62
+ ERRORS = {
63
+ 400 => Twitter::Error::BadRequest,
64
+ 401 => Twitter::Error::Unauthorized,
65
+ 403 => Twitter::Error::Forbidden,
66
+ 404 => Twitter::Error::NotFound,
67
+ 406 => Twitter::Error::NotAcceptable,
68
+ 413 => Twitter::Error::RequestEntityTooLarge,
69
+ 422 => Twitter::Error::UnprocessableEntity,
70
+ 429 => Twitter::Error::TooManyRequests,
71
+ 500 => Twitter::Error::InternalServerError,
72
+ 502 => Twitter::Error::BadGateway,
73
+ 503 => Twitter::Error::ServiceUnavailable,
74
+ 504 => Twitter::Error::GatewayTimeout,
75
+ }.freeze
76
+
77
+ FORBIDDEN_MESSAGES = {
78
+ 'Status is a duplicate.' => Twitter::Error::DuplicateStatus,
79
+ 'You have already favorited this status.' => Twitter::Error::AlreadyFavorited,
80
+ 'You have already retweeted this tweet.' => Twitter::Error::AlreadyRetweeted,
81
+ 'sharing is not permissible for this status (Share validations failed)' => Twitter::Error::AlreadyRetweeted,
82
+ }.freeze
83
+
11
84
  # If error code is missing see https://dev.twitter.com/overview/api/response-codes
12
85
  module Code
13
86
  AUTHENTICATION_PROBLEM = 32
@@ -35,49 +108,24 @@ module Twitter
35
108
  CANNOT_MUTE = 271
36
109
  CANNOT_UNMUTE = 272
37
110
  end
38
- Codes = Code
39
111
 
40
112
  class << self
113
+ include Twitter::Utils
114
+
41
115
  # Create a new error from an HTTP response
42
116
  #
43
- # @param response [Faraday::Response]
117
+ # @param body [String]
118
+ # @param headers [Hash]
44
119
  # @return [Twitter::Error]
45
- def from_response(response)
46
- message, code = parse_error(response.body)
47
- new(message, response.response_headers, code)
48
- end
49
-
50
- # @return [Hash]
51
- def errors
52
- @errors ||= {
53
- 400 => Twitter::Error::BadRequest,
54
- 401 => Twitter::Error::Unauthorized,
55
- 403 => Twitter::Error::Forbidden,
56
- 404 => Twitter::Error::NotFound,
57
- 406 => Twitter::Error::NotAcceptable,
58
- 408 => Twitter::Error::RequestTimeout,
59
- 420 => Twitter::Error::EnhanceYourCalm,
60
- 422 => Twitter::Error::UnprocessableEntity,
61
- 429 => Twitter::Error::TooManyRequests,
62
- 500 => Twitter::Error::InternalServerError,
63
- 502 => Twitter::Error::BadGateway,
64
- 503 => Twitter::Error::ServiceUnavailable,
65
- 504 => Twitter::Error::GatewayTimeout,
66
- }
67
- end
68
-
69
- def forbidden_messages
70
- @forbidden_messages ||= {
71
- 'Status is a duplicate.' => Twitter::Error::DuplicateStatus,
72
- 'You have already favorited this status.' => Twitter::Error::AlreadyFavorited,
73
- 'sharing is not permissible for this status (Share validations failed)' => Twitter::Error::AlreadyRetweeted,
74
- }
120
+ def from_response(body, headers)
121
+ message, code = parse_error(body)
122
+ new(message, headers, code)
75
123
  end
76
124
 
77
125
  private
78
126
 
79
127
  def parse_error(body)
80
- if body.nil?
128
+ if body.nil? || body.empty?
81
129
  ['', nil]
82
130
  elsif body[:error]
83
131
  [body[:error], nil]
@@ -107,68 +155,5 @@ module Twitter
107
155
  @rate_limit = Twitter::RateLimit.new(rate_limit)
108
156
  @code = code
109
157
  end
110
-
111
- ConfigurationError = Class.new(::ArgumentError)
112
-
113
- # Raised when a Tweet includes media that doesn't have a to_io method
114
- class UnacceptableIO < StandardError
115
- def initialize
116
- super('The IO object for media must respond to to_io')
117
- end
118
- end
119
-
120
- # Raised when Twitter returns a 4xx HTTP status code
121
- ClientError = Class.new(self)
122
-
123
- # Raised when Twitter returns the HTTP status code 400
124
- BadRequest = Class.new(ClientError)
125
-
126
- # Raised when Twitter returns the HTTP status code 401
127
- Unauthorized = Class.new(ClientError)
128
-
129
- # Raised when Twitter returns the HTTP status code 403
130
- Forbidden = Class.new(ClientError)
131
-
132
- # Raised when a Tweet has already been favorited
133
- AlreadyFavorited = Class.new(Forbidden)
134
-
135
- # Raised when a Tweet has already been retweeted
136
- AlreadyRetweeted = Class.new(Forbidden)
137
-
138
- # Raised when a Tweet has already been posted
139
- DuplicateStatus = Class.new(Forbidden)
140
- AlreadyPosted = DuplicateStatus
141
-
142
- # Raised when Twitter returns the HTTP status code 404
143
- NotFound = Class.new(ClientError)
144
-
145
- # Raised when Twitter returns the HTTP status code 406
146
- NotAcceptable = Class.new(ClientError)
147
-
148
- # Raised when Twitter returns the HTTP status code 408
149
- RequestTimeout = Class.new(ClientError)
150
-
151
- # Raised when Twitter returns the HTTP status code 422
152
- UnprocessableEntity = Class.new(ClientError)
153
-
154
- # Raised when Twitter returns the HTTP status code 429
155
- TooManyRequests = Class.new(ClientError)
156
- EnhanceYourCalm = TooManyRequests
157
- RateLimited = TooManyRequests
158
-
159
- # Raised when Twitter returns a 5xx HTTP status code
160
- ServerError = Class.new(self)
161
-
162
- # Raised when Twitter returns the HTTP status code 500
163
- InternalServerError = Class.new(ServerError)
164
-
165
- # Raised when Twitter returns the HTTP status code 502
166
- BadGateway = Class.new(ServerError)
167
-
168
- # Raised when Twitter returns the HTTP status code 503
169
- ServiceUnavailable = Class.new(ServerError)
170
-
171
- # Raised when Twitter returns the HTTP status code 504
172
- GatewayTimeout = Class.new(ServerError)
173
158
  end
174
159
  end
@@ -9,7 +9,6 @@ module Twitter
9
9
  attr_reader :attrs
10
10
  alias to_h attrs
11
11
  alias to_hash to_h
12
- deprecate_alias :to_hsh, :to_hash
13
12
 
14
13
  # Initializes a new GeoResults object
15
14
  #
@@ -8,21 +8,24 @@ module Twitter
8
8
  @client = client
9
9
  @request_method = request_method.to_sym
10
10
  @uri = Addressable::URI.parse(url)
11
+ @bearer_token_request = options.delete(:bearer_token_request)
11
12
  @options = options
12
- @signature_options = @request_method == :post && @options.values.any? { |value| value.respond_to?(:to_io) } ? {} : @options
13
+ end
14
+
15
+ def bearer_token_request?
16
+ !!@bearer_token_request
13
17
  end
14
18
 
15
19
  def oauth_auth_header
16
- SimpleOAuth::Header.new(@request_method, @uri, @signature_options, @client.credentials)
20
+ SimpleOAuth::Header.new(@request_method, @uri, @options, @client.credentials.merge(ignore_extra_keys: true))
17
21
  end
18
22
 
19
23
  def request_headers
20
- bearer_token_request = @options.delete(:bearer_token_request)
21
24
  headers = {}
22
- if bearer_token_request
25
+ headers[:user_agent] = @client.user_agent
26
+ if bearer_token_request?
23
27
  headers[:accept] = '*/*'
24
28
  headers[:authorization] = bearer_token_credentials_auth_header
25
- headers[:content_type] = 'application/x-www-form-urlencoded; charset=UTF-8'
26
29
  else
27
30
  headers[:authorization] = auth_header
28
31
  end
@@ -40,18 +43,16 @@ module Twitter
40
43
  end
41
44
  end
42
45
 
46
+ # @return [String]
43
47
  def bearer_auth_header
44
- bearer_token = @client.bearer_token
45
- token = bearer_token.is_a?(Twitter::Token) && bearer_token.bearer? ? bearer_token.access_token : bearer_token
46
- "Bearer #{token}"
48
+ "Bearer #{@client.bearer_token}"
47
49
  end
48
50
 
49
51
  # Generates authentication header for a bearer token request
50
52
  #
51
53
  # @return [String]
52
54
  def bearer_token_credentials_auth_header
53
- basic_auth_token = Base64.strict_encode64("#{@client.consumer_key}:#{@client.consumer_secret}")
54
- "Basic #{basic_auth_token}"
55
+ "Basic #{Base64.strict_encode64("#{@client.consumer_key}:#{@client.consumer_secret}")}"
55
56
  end
56
57
  end
57
58
  end
@@ -8,6 +8,10 @@ module Twitter
8
8
 
9
9
  # @return [Array<Integer>]
10
10
  attr_reader :indices
11
+
12
+ # @return [String]
13
+ attr_reader :type
14
+
11
15
  display_uri_attr_reader
12
16
  uri_attr_reader :expanded_uri, :media_uri, :media_uri_https, :uri
13
17
 
@@ -9,6 +9,10 @@ module Twitter
9
9
 
10
10
  # @return [Array<Integer>]
11
11
  attr_reader :indices
12
+
13
+ # @return [String]
14
+ attr_reader :type
15
+
12
16
  display_uri_attr_reader
13
17
  uri_attr_reader :expanded_uri, :media_uri, :media_uri_https, :uri
14
18
 
@@ -18,7 +22,6 @@ module Twitter
18
22
  def sizes
19
23
  @attrs.fetch(:sizes, []).each_with_object({}) do |(key, value), object|
20
24
  object[key] = Size.new(value)
21
- object
22
25
  end
23
26
  end
24
27
  memoize :sizes