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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +22 -15
- data/README.md +69 -394
- data/lib/twitter/base.rb +2 -16
- data/lib/twitter/basic_user.rb +0 -3
- data/lib/twitter/client.rb +5 -19
- data/lib/twitter/configuration.rb +3 -2
- data/lib/twitter/creatable.rb +1 -1
- data/lib/twitter/cursor.rb +0 -1
- data/lib/twitter/entity/uri.rb +0 -4
- data/lib/twitter/error.rb +81 -96
- data/lib/twitter/geo_results.rb +0 -1
- data/lib/twitter/headers.rb +11 -10
- data/lib/twitter/media/photo.rb +4 -0
- data/lib/twitter/media/video.rb +4 -1
- data/lib/twitter/media/video_info.rb +1 -1
- data/lib/twitter/null_object.rb +2 -2
- data/lib/twitter/profile.rb +3 -2
- data/lib/twitter/rate_limit.rb +1 -1
- data/lib/twitter/rest/api.rb +0 -2
- data/lib/twitter/rest/client.rb +0 -78
- data/lib/twitter/rest/direct_messages.rb +3 -3
- data/lib/twitter/rest/favorites.rb +25 -4
- data/lib/twitter/rest/friends_and_followers.rb +1 -3
- data/lib/twitter/rest/lists.rb +18 -29
- data/lib/twitter/rest/oauth.rb +15 -15
- data/lib/twitter/rest/request.rb +105 -16
- data/lib/twitter/rest/saved_searches.rb +0 -2
- data/lib/twitter/rest/search.rb +2 -0
- data/lib/twitter/rest/trends.rb +1 -0
- data/lib/twitter/rest/tweets.rb +80 -15
- data/lib/twitter/rest/undocumented.rb +3 -4
- data/lib/twitter/rest/users.rb +20 -34
- data/lib/twitter/rest/utils.rb +13 -20
- data/lib/twitter/search_results.rb +1 -2
- data/lib/twitter/streaming/client.rb +17 -23
- data/lib/twitter/streaming/connection.rb +23 -10
- data/lib/twitter/streaming/deleted_tweet.rb +0 -1
- data/lib/twitter/streaming/event.rb +6 -6
- data/lib/twitter/streaming/message_parser.rb +1 -1
- data/lib/twitter/streaming/response.rb +2 -2
- data/lib/twitter/trend_results.rb +1 -2
- data/lib/twitter/tweet.rb +1 -5
- data/lib/twitter/user.rb +0 -2
- data/lib/twitter/utils.rb +1 -16
- data/lib/twitter/version.rb +1 -1
- data/twitter.gemspec +13 -13
- metadata +35 -27
- data/lib/twitter/rest/media.rb +0 -30
- data/lib/twitter/rest/request/multipart_with_file.rb +0 -47
- data/lib/twitter/rest/response/parse_error_json.rb +0 -13
- data/lib/twitter/rest/response/parse_json.rb +0 -31
- data/lib/twitter/rest/response/raise_error.rb +0 -32
- data/lib/twitter/token.rb +0 -20
data/lib/twitter/base.rb
CHANGED
@@ -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
|
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
|
-
|
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)
|
data/lib/twitter/basic_user.rb
CHANGED
@@ -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
|
data/lib/twitter/client.rb
CHANGED
@@ -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
|
-
|
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.
|
44
|
+
credentials.values.none? { |v| blank?(v) }
|
51
45
|
end
|
52
46
|
|
53
47
|
private
|
54
48
|
|
55
|
-
|
56
|
-
|
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, :
|
12
|
-
:photo_size_limit, :short_url_length,
|
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
|
|
data/lib/twitter/creatable.rb
CHANGED
data/lib/twitter/cursor.rb
CHANGED
data/lib/twitter/entity/uri.rb
CHANGED
data/lib/twitter/error.rb
CHANGED
@@ -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
|
117
|
+
# @param body [String]
|
118
|
+
# @param headers [Hash]
|
44
119
|
# @return [Twitter::Error]
|
45
|
-
def from_response(
|
46
|
-
message, code = parse_error(
|
47
|
-
new(message,
|
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
|
data/lib/twitter/geo_results.rb
CHANGED
data/lib/twitter/headers.rb
CHANGED
@@ -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
|
-
|
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, @
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/twitter/media/photo.rb
CHANGED
data/lib/twitter/media/video.rb
CHANGED
@@ -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
|