twitter 6.1.0 → 6.2.0

Sign up to get free protection for your applications and to get access to all the features.
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