twitter 8.2.0 → 8.3.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 +4 -4
- data/LICENSE.md +1 -1
- data/README.md +172 -10
- data/lib/twitter/arguments.rb +14 -1
- data/lib/twitter/base.rb +72 -11
- data/lib/twitter/basic_user.rb +7 -1
- data/lib/twitter/client.rb +94 -3
- data/lib/twitter/creatable.rb +11 -2
- data/lib/twitter/cursor.rb +58 -11
- data/lib/twitter/direct_message.rb +32 -4
- data/lib/twitter/direct_message_event.rb +34 -10
- data/lib/twitter/direct_messages/welcome_message.rb +22 -1
- data/lib/twitter/direct_messages/welcome_message_rule.rb +7 -0
- data/lib/twitter/direct_messages/welcome_message_rule_wrapper.rb +26 -3
- data/lib/twitter/direct_messages/welcome_message_wrapper.rb +36 -11
- data/lib/twitter/entities.rb +84 -8
- data/lib/twitter/entity/hashtag.rb +7 -1
- data/lib/twitter/entity/symbol.rb +7 -1
- data/lib/twitter/entity/uri.rb +2 -1
- data/lib/twitter/entity/user_mention.rb +20 -1
- data/lib/twitter/entity.rb +7 -1
- data/lib/twitter/enumerable.rb +20 -3
- data/lib/twitter/error.rb +137 -61
- data/lib/twitter/factory.rb +9 -5
- data/lib/twitter/geo/point.rb +37 -5
- data/lib/twitter/geo/polygon.rb +1 -0
- data/lib/twitter/geo.rb +16 -2
- data/lib/twitter/geo_factory.rb +7 -3
- data/lib/twitter/geo_results.rb +39 -8
- data/lib/twitter/headers.rb +44 -7
- data/lib/twitter/identity.rb +13 -3
- data/lib/twitter/language.rb +21 -1
- data/lib/twitter/list.rb +101 -11
- data/lib/twitter/media/animated_gif.rb +1 -0
- data/lib/twitter/media/photo.rb +19 -3
- data/lib/twitter/media/video.rb +21 -3
- data/lib/twitter/media/video_info.rb +15 -1
- data/lib/twitter/media_factory.rb +7 -3
- data/lib/twitter/metadata.rb +14 -1
- data/lib/twitter/null_object.rb +16 -14
- data/lib/twitter/oembed.rb +56 -2
- data/lib/twitter/place.rb +74 -6
- data/lib/twitter/premium_search_results.rb +87 -18
- data/lib/twitter/profile.rb +100 -44
- data/lib/twitter/profile_banner.rb +9 -4
- data/lib/twitter/rate_limit.rb +32 -3
- data/lib/twitter/relationship.rb +8 -5
- data/lib/twitter/rest/account_activity.rb +55 -26
- data/lib/twitter/rest/api.rb +2 -0
- data/lib/twitter/rest/client.rb +18 -0
- data/lib/twitter/rest/direct_messages/welcome_messages.rb +89 -18
- data/lib/twitter/rest/direct_messages.rb +158 -94
- data/lib/twitter/rest/favorites.rb +57 -21
- data/lib/twitter/rest/form_encoder.rb +57 -17
- data/lib/twitter/rest/friends_and_followers.rb +101 -35
- data/lib/twitter/rest/help.rb +13 -3
- data/lib/twitter/rest/lists.rb +133 -45
- data/lib/twitter/rest/oauth.rb +23 -17
- data/lib/twitter/rest/places_and_geo.rb +44 -28
- data/lib/twitter/rest/premium_search.rb +18 -13
- data/lib/twitter/rest/request.rb +171 -53
- data/lib/twitter/rest/saved_searches.rb +22 -7
- data/lib/twitter/rest/search.rb +20 -16
- data/lib/twitter/rest/spam_reporting.rb +5 -1
- data/lib/twitter/rest/suggested_users.rb +14 -5
- data/lib/twitter/rest/timelines.rb +92 -52
- data/lib/twitter/rest/trends.rb +31 -12
- data/lib/twitter/rest/tweets.rb +145 -88
- data/lib/twitter/rest/undocumented.rb +11 -2
- data/lib/twitter/rest/upload_utils.rb +42 -26
- data/lib/twitter/rest/users.rb +150 -71
- data/lib/twitter/rest/utils.rb +135 -39
- data/lib/twitter/saved_search.rb +23 -2
- data/lib/twitter/search_results.rb +62 -17
- data/lib/twitter/settings.rb +37 -11
- data/lib/twitter/size.rb +37 -3
- data/lib/twitter/source_user.rb +4 -3
- data/lib/twitter/streaming/client.rb +60 -8
- data/lib/twitter/streaming/connection.rb +55 -8
- data/lib/twitter/streaming/deleted_tweet.rb +8 -0
- data/lib/twitter/streaming/event.rb +43 -1
- data/lib/twitter/streaming/friend_list.rb +1 -0
- data/lib/twitter/streaming/message_parser.rb +20 -10
- data/lib/twitter/streaming/response.rb +31 -5
- data/lib/twitter/streaming/stall_warning.rb +23 -0
- data/lib/twitter/suggestion.rb +25 -1
- data/lib/twitter/target_user.rb +2 -1
- data/lib/twitter/trend.rb +29 -1
- data/lib/twitter/trend_results.rb +50 -7
- data/lib/twitter/tweet.rb +180 -21
- data/lib/twitter/user.rb +289 -53
- data/lib/twitter/utils.rb +12 -13
- data/lib/twitter/variant.rb +12 -1
- data/lib/twitter/version.rb +66 -29
- data/lib/twitter.rb +6 -1
- metadata +23 -57
- data/.yardopts +0 -16
- data/CHANGELOG.md +0 -1040
- data/CONTRIBUTING.md +0 -49
- data/twitter.gemspec +0 -40
data/lib/twitter/enumerable.rb
CHANGED
|
@@ -1,32 +1,49 @@
|
|
|
1
1
|
module Twitter
|
|
2
|
+
# Provides iteration support for collections
|
|
2
3
|
module Enumerable
|
|
3
4
|
include ::Enumerable
|
|
4
5
|
|
|
6
|
+
# Iterates over the collection
|
|
7
|
+
#
|
|
8
|
+
# @api public
|
|
9
|
+
# @example
|
|
10
|
+
# cursor.each { |item| puts item }
|
|
11
|
+
# @param start [Integer] The starting index
|
|
12
|
+
# @yield [Object] Each item in the collection
|
|
5
13
|
# @return [Enumerator]
|
|
6
14
|
def each(start = 0, &block)
|
|
7
15
|
return to_enum(:each, start) unless block
|
|
8
16
|
|
|
9
|
-
Array(@collection[start..]).each(&block)
|
|
17
|
+
Array(@collection[start..]).each(&block) # steep:ignore FallbackAny
|
|
10
18
|
unless finished?
|
|
11
|
-
start = [@collection.size, start].max
|
|
19
|
+
start = [@collection.size, start].max # steep:ignore FallbackAny
|
|
12
20
|
fetch_next_page
|
|
13
21
|
each(start, &block)
|
|
14
22
|
end
|
|
15
23
|
self
|
|
16
24
|
end
|
|
17
25
|
|
|
18
|
-
|
|
26
|
+
private
|
|
19
27
|
|
|
28
|
+
# Returns true if this is the last page
|
|
29
|
+
#
|
|
30
|
+
# @api private
|
|
20
31
|
# @return [Boolean]
|
|
21
32
|
def last?
|
|
22
33
|
true
|
|
23
34
|
end
|
|
24
35
|
|
|
36
|
+
# Returns true if the limit has been reached
|
|
37
|
+
#
|
|
38
|
+
# @api private
|
|
25
39
|
# @return [Boolean]
|
|
26
40
|
def reached_limit?
|
|
27
41
|
false
|
|
28
42
|
end
|
|
29
43
|
|
|
44
|
+
# Returns true if iteration is finished
|
|
45
|
+
#
|
|
46
|
+
# @api private
|
|
30
47
|
# @return [Boolean]
|
|
31
48
|
def finished?
|
|
32
49
|
last? || reached_limit?
|
data/lib/twitter/error.rb
CHANGED
|
@@ -3,77 +3,107 @@ require "twitter/rate_limit"
|
|
|
3
3
|
module Twitter
|
|
4
4
|
# Custom error class for rescuing from all Twitter errors
|
|
5
5
|
class Error < StandardError
|
|
6
|
+
# The error code from Twitter
|
|
7
|
+
#
|
|
8
|
+
# @api public
|
|
9
|
+
# @example
|
|
10
|
+
# error.code
|
|
6
11
|
# @return [Integer]
|
|
7
12
|
attr_reader :code
|
|
13
|
+
|
|
14
|
+
# The rate limit information from the response
|
|
15
|
+
#
|
|
16
|
+
# @api public
|
|
17
|
+
# @example
|
|
18
|
+
# error.rate_limit
|
|
8
19
|
# @return [Twitter::RateLimit]
|
|
9
20
|
attr_reader :rate_limit
|
|
10
21
|
|
|
11
22
|
# Raised when Twitter returns a 4xx HTTP status code
|
|
12
|
-
ClientError = Class.new(self)
|
|
23
|
+
ClientError = Class.new(self) # steep:ignore IncompatibleAssignment
|
|
13
24
|
|
|
14
25
|
# Raised when Twitter returns the HTTP status code 400
|
|
15
|
-
BadRequest
|
|
26
|
+
class BadRequest < ClientError
|
|
27
|
+
end # steep:ignore IncompatibleAssignment
|
|
16
28
|
|
|
17
29
|
# Raised when Twitter returns the HTTP status code 401
|
|
18
|
-
Unauthorized
|
|
30
|
+
class Unauthorized < ClientError
|
|
31
|
+
end # steep:ignore IncompatibleAssignment
|
|
19
32
|
|
|
20
33
|
# Raised when Twitter returns the HTTP status code 403
|
|
21
|
-
Forbidden
|
|
34
|
+
class Forbidden < ClientError
|
|
35
|
+
end # steep:ignore IncompatibleAssignment
|
|
22
36
|
|
|
23
37
|
# Raised when Twitter returns the HTTP status code 413
|
|
24
|
-
RequestEntityTooLarge
|
|
38
|
+
class RequestEntityTooLarge < ClientError
|
|
39
|
+
end # steep:ignore IncompatibleAssignment
|
|
25
40
|
|
|
26
41
|
# Raised when a Tweet has already been favorited
|
|
27
|
-
AlreadyFavorited
|
|
42
|
+
class AlreadyFavorited < Forbidden
|
|
43
|
+
end # steep:ignore IncompatibleAssignment
|
|
28
44
|
|
|
29
45
|
# Raised when a Tweet has already been retweeted
|
|
30
|
-
AlreadyRetweeted
|
|
46
|
+
class AlreadyRetweeted < Forbidden
|
|
47
|
+
end # steep:ignore IncompatibleAssignment
|
|
31
48
|
|
|
32
49
|
# Raised when a Tweet has already been posted
|
|
33
|
-
DuplicateStatus
|
|
50
|
+
class DuplicateStatus < Forbidden
|
|
51
|
+
end # steep:ignore IncompatibleAssignment
|
|
34
52
|
|
|
35
53
|
# Raised when Twitter returns the HTTP status code 404
|
|
36
|
-
NotFound
|
|
54
|
+
class NotFound < ClientError
|
|
55
|
+
end # steep:ignore IncompatibleAssignment
|
|
37
56
|
|
|
38
57
|
# Raised when Twitter returns the HTTP status code 406
|
|
39
|
-
NotAcceptable
|
|
58
|
+
class NotAcceptable < ClientError
|
|
59
|
+
end # steep:ignore IncompatibleAssignment
|
|
40
60
|
|
|
41
61
|
# Raised when Twitter returns the HTTP status code 422
|
|
42
|
-
UnprocessableEntity
|
|
62
|
+
class UnprocessableEntity < ClientError
|
|
63
|
+
end # steep:ignore IncompatibleAssignment
|
|
43
64
|
|
|
44
65
|
# Raised when Twitter returns the HTTP status code 429
|
|
45
|
-
TooManyRequests
|
|
66
|
+
class TooManyRequests < ClientError
|
|
67
|
+
end # steep:ignore IncompatibleAssignment
|
|
46
68
|
|
|
47
69
|
# Raised when Twitter returns a 5xx HTTP status code
|
|
48
|
-
ServerError = Class.new(self)
|
|
70
|
+
ServerError = Class.new(self) # steep:ignore IncompatibleAssignment
|
|
49
71
|
|
|
50
72
|
# Raised when Twitter returns the HTTP status code 500
|
|
51
|
-
InternalServerError
|
|
73
|
+
class InternalServerError < ServerError
|
|
74
|
+
end # steep:ignore IncompatibleAssignment
|
|
52
75
|
|
|
53
76
|
# Raised when Twitter returns the HTTP status code 502
|
|
54
|
-
BadGateway
|
|
77
|
+
class BadGateway < ServerError
|
|
78
|
+
end # steep:ignore IncompatibleAssignment
|
|
55
79
|
|
|
56
80
|
# Raised when Twitter returns the HTTP status code 503
|
|
57
|
-
ServiceUnavailable
|
|
81
|
+
class ServiceUnavailable < ServerError
|
|
82
|
+
end # steep:ignore IncompatibleAssignment
|
|
58
83
|
|
|
59
84
|
# Raised when Twitter returns the HTTP status code 504
|
|
60
|
-
GatewayTimeout
|
|
85
|
+
class GatewayTimeout < ServerError
|
|
86
|
+
end # steep:ignore IncompatibleAssignment
|
|
61
87
|
|
|
62
88
|
# Raised when Twitter returns a media related error
|
|
63
|
-
MediaError = Class.new(self)
|
|
89
|
+
MediaError = Class.new(self) # steep:ignore IncompatibleAssignment
|
|
64
90
|
|
|
65
91
|
# Raised when Twitter returns an InvalidMedia error
|
|
66
|
-
InvalidMedia
|
|
92
|
+
class InvalidMedia < MediaError
|
|
93
|
+
end # steep:ignore IncompatibleAssignment
|
|
67
94
|
|
|
68
95
|
# Raised when Twitter returns a media InternalError error
|
|
69
|
-
MediaInternalError
|
|
96
|
+
class MediaInternalError < MediaError
|
|
97
|
+
end # steep:ignore IncompatibleAssignment
|
|
70
98
|
|
|
71
99
|
# Raised when Twitter returns an UnsupportedMedia error
|
|
72
|
-
UnsupportedMedia
|
|
100
|
+
class UnsupportedMedia < MediaError
|
|
101
|
+
end # steep:ignore IncompatibleAssignment
|
|
73
102
|
|
|
74
103
|
# Raised when an operation subject to timeout takes too long
|
|
75
|
-
TimeoutError = Class.new(self)
|
|
104
|
+
TimeoutError = Class.new(self) # steep:ignore IncompatibleAssignment
|
|
76
105
|
|
|
106
|
+
# Maps HTTP status codes to error classes
|
|
77
107
|
ERRORS = {
|
|
78
108
|
400 => Twitter::Error::BadRequest,
|
|
79
109
|
401 => Twitter::Error::Unauthorized,
|
|
@@ -87,9 +117,10 @@ module Twitter
|
|
|
87
117
|
500 => Twitter::Error::InternalServerError,
|
|
88
118
|
502 => Twitter::Error::BadGateway,
|
|
89
119
|
503 => Twitter::Error::ServiceUnavailable,
|
|
90
|
-
504 => Twitter::Error::GatewayTimeout
|
|
120
|
+
504 => Twitter::Error::GatewayTimeout
|
|
91
121
|
}.freeze
|
|
92
122
|
|
|
123
|
+
# Maps forbidden message patterns to error classes
|
|
93
124
|
FORBIDDEN_MESSAGES = proc do |message|
|
|
94
125
|
case message
|
|
95
126
|
when /(?=.*status).*duplicate/i
|
|
@@ -106,57 +137,89 @@ module Twitter
|
|
|
106
137
|
end
|
|
107
138
|
end
|
|
108
139
|
|
|
140
|
+
# Maps media error names to error classes
|
|
109
141
|
MEDIA_ERRORS = {
|
|
110
142
|
"InternalError" => Twitter::Error::MediaInternalError,
|
|
111
143
|
"InvalidMedia" => Twitter::Error::InvalidMedia,
|
|
112
|
-
"UnsupportedMedia" => Twitter::Error::UnsupportedMedia
|
|
144
|
+
"UnsupportedMedia" => Twitter::Error::UnsupportedMedia
|
|
113
145
|
}.freeze
|
|
114
146
|
|
|
115
|
-
#
|
|
147
|
+
# Twitter API error codes
|
|
148
|
+
# @see https://developer.twitter.com/en/docs/basics/response-codes
|
|
116
149
|
module Code
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
150
|
+
# Authentication problem error code
|
|
151
|
+
AUTHENTICATION_PROBLEM = 32
|
|
152
|
+
# Resource not found error code
|
|
153
|
+
RESOURCE_NOT_FOUND = 34
|
|
154
|
+
# Suspended account error code
|
|
155
|
+
SUSPENDED_ACCOUNT = 64
|
|
156
|
+
# Deprecated call error code
|
|
157
|
+
DEPRECATED_CALL = 68
|
|
158
|
+
# Rate limit exceeded error code
|
|
159
|
+
RATE_LIMIT_EXCEEDED = 88
|
|
160
|
+
# Invalid or expired token error code
|
|
161
|
+
INVALID_OR_EXPIRED_TOKEN = 89
|
|
162
|
+
# SSL required error code
|
|
163
|
+
SSL_REQUIRED = 92
|
|
164
|
+
# Unable to verify credentials error code
|
|
165
|
+
UNABLE_TO_VERIFY_CREDENTIALS = 99
|
|
166
|
+
# Over capacity error code
|
|
167
|
+
OVER_CAPACITY = 130
|
|
168
|
+
# Internal error code
|
|
169
|
+
INTERNAL_ERROR = 131
|
|
170
|
+
# OAuth timestamp out of range error code
|
|
127
171
|
OAUTH_TIMESTAMP_OUT_OF_RANGE = 135
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
172
|
+
# Already favorited error code
|
|
173
|
+
ALREADY_FAVORITED = 139
|
|
174
|
+
# Follow already requested error code
|
|
175
|
+
FOLLOW_ALREADY_REQUESTED = 160
|
|
176
|
+
# Follow limit exceeded error code
|
|
177
|
+
FOLLOW_LIMIT_EXCEEDED = 161
|
|
178
|
+
# Protected status error code
|
|
179
|
+
PROTECTED_STATUS = 179
|
|
180
|
+
# Over update limit error code
|
|
181
|
+
OVER_UPDATE_LIMIT = 185
|
|
182
|
+
# Duplicate status error code
|
|
183
|
+
DUPLICATE_STATUS = 187
|
|
184
|
+
# Bad authentication data error code
|
|
185
|
+
BAD_AUTHENTICATION_DATA = 215
|
|
186
|
+
# Spam error code
|
|
187
|
+
SPAM = 226
|
|
188
|
+
# Login verification needed error code
|
|
189
|
+
LOGIN_VERIFICATION_NEEDED = 231
|
|
190
|
+
# Endpoint retired error code
|
|
191
|
+
ENDPOINT_RETIRED = 251
|
|
192
|
+
# Cannot write error code
|
|
193
|
+
CANNOT_WRITE = 261
|
|
194
|
+
# Cannot mute error code
|
|
195
|
+
CANNOT_MUTE = 271
|
|
196
|
+
# Cannot unmute error code
|
|
197
|
+
CANNOT_UNMUTE = 272
|
|
141
198
|
end
|
|
142
199
|
|
|
143
200
|
class << self
|
|
144
201
|
include Twitter::Utils
|
|
145
202
|
|
|
146
|
-
#
|
|
203
|
+
# Creates a new error from an HTTP response
|
|
147
204
|
#
|
|
148
|
-
# @
|
|
149
|
-
# @
|
|
205
|
+
# @api public
|
|
206
|
+
# @example
|
|
207
|
+
# Twitter::Error.from_response(body, headers)
|
|
208
|
+
# @param body [String] The response body
|
|
209
|
+
# @param headers [Hash] The response headers
|
|
150
210
|
# @return [Twitter::Error]
|
|
151
211
|
def from_response(body, headers)
|
|
152
212
|
message, code = parse_error(body)
|
|
153
213
|
new(message, headers, code)
|
|
154
214
|
end
|
|
155
215
|
|
|
156
|
-
#
|
|
216
|
+
# Creates a new error from a media error hash
|
|
157
217
|
#
|
|
158
|
-
# @
|
|
159
|
-
# @
|
|
218
|
+
# @api public
|
|
219
|
+
# @example
|
|
220
|
+
# Twitter::Error.from_processing_response(error, headers)
|
|
221
|
+
# @param error [Hash] The error hash from the response
|
|
222
|
+
# @param headers [Hash] The response headers
|
|
160
223
|
# @return [Twitter::MediaError]
|
|
161
224
|
def from_processing_response(error, headers)
|
|
162
225
|
klass = MEDIA_ERRORS[error[:name]] || self
|
|
@@ -165,37 +228,50 @@ module Twitter
|
|
|
165
228
|
klass.new(message, headers, code)
|
|
166
229
|
end
|
|
167
230
|
|
|
168
|
-
|
|
231
|
+
private
|
|
169
232
|
|
|
233
|
+
# Parses an error from the response body
|
|
234
|
+
#
|
|
235
|
+
# @api private
|
|
236
|
+
# @param body [Hash, nil] The response body
|
|
237
|
+
# @return [Array]
|
|
170
238
|
def parse_error(body)
|
|
171
239
|
if body.nil? || body.empty?
|
|
172
240
|
["", nil]
|
|
173
241
|
elsif body[:error]
|
|
174
|
-
[body
|
|
242
|
+
[body.fetch(:error), nil]
|
|
175
243
|
elsif body[:errors]
|
|
176
244
|
extract_message_from_errors(body)
|
|
177
245
|
end
|
|
178
246
|
end
|
|
179
247
|
|
|
248
|
+
# Extracts error message from errors array
|
|
249
|
+
#
|
|
250
|
+
# @api private
|
|
251
|
+
# @param body [Hash] The response body with errors
|
|
252
|
+
# @return [Array]
|
|
180
253
|
def extract_message_from_errors(body)
|
|
181
254
|
first = Array(body[:errors]).first
|
|
182
255
|
if first.is_a?(Hash)
|
|
183
256
|
[first[:message].chomp, first[:code]]
|
|
184
257
|
else
|
|
185
|
-
[first.chomp, nil]
|
|
258
|
+
[first.chomp, nil] # steep:ignore NoMethod
|
|
186
259
|
end
|
|
187
260
|
end
|
|
188
261
|
end
|
|
189
262
|
|
|
190
263
|
# Initializes a new Error object
|
|
191
264
|
#
|
|
192
|
-
# @
|
|
193
|
-
# @
|
|
194
|
-
#
|
|
265
|
+
# @api public
|
|
266
|
+
# @example
|
|
267
|
+
# Twitter::Error.new("Something went wrong", {}, 123)
|
|
268
|
+
# @param message [Exception, String] The error message
|
|
269
|
+
# @param rate_limit [Hash] The rate limit headers
|
|
270
|
+
# @param code [Integer] The error code
|
|
195
271
|
# @return [Twitter::Error]
|
|
196
272
|
def initialize(message = "", rate_limit = {}, code = nil)
|
|
197
273
|
super(message)
|
|
198
|
-
@rate_limit =
|
|
274
|
+
@rate_limit = RateLimit.new(rate_limit)
|
|
199
275
|
@code = code
|
|
200
276
|
end
|
|
201
277
|
end
|
data/lib/twitter/factory.rb
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
module Twitter
|
|
2
|
+
# Factory for creating Twitter objects based on type
|
|
2
3
|
class Factory
|
|
3
4
|
class << self
|
|
4
|
-
#
|
|
5
|
+
# Constructs a new object based on type
|
|
5
6
|
#
|
|
6
|
-
# @
|
|
7
|
-
# @
|
|
8
|
-
#
|
|
9
|
-
# @
|
|
7
|
+
# @api public
|
|
8
|
+
# @example
|
|
9
|
+
# Twitter::Factory.new(:type, Twitter::Geo, attrs)
|
|
10
|
+
# @param method [Symbol] The key to look up the type
|
|
11
|
+
# @param klass [Class] The base class for the type
|
|
12
|
+
# @param attrs [Hash] The attributes hash
|
|
13
|
+
# @raise [IndexError] Error raised when argument is missing a key
|
|
10
14
|
# @return [Twitter::Base]
|
|
11
15
|
def new(method, klass, attrs = {})
|
|
12
16
|
type = attrs.fetch(method.to_sym)
|
data/lib/twitter/geo/point.rb
CHANGED
|
@@ -2,19 +2,51 @@ require "twitter/geo"
|
|
|
2
2
|
|
|
3
3
|
module Twitter
|
|
4
4
|
class Geo
|
|
5
|
+
# Represents a geographic point with latitude and longitude
|
|
5
6
|
class Point < Twitter::Geo
|
|
6
|
-
#
|
|
7
|
+
# Returns the latitude of this point
|
|
8
|
+
#
|
|
9
|
+
# @api public
|
|
10
|
+
# @example
|
|
11
|
+
# point.latitude
|
|
12
|
+
# @return [Float]
|
|
7
13
|
def latitude
|
|
8
14
|
coordinates[0]
|
|
9
15
|
end
|
|
10
|
-
alias lat latitude
|
|
11
16
|
|
|
12
|
-
#
|
|
17
|
+
# @!method lat
|
|
18
|
+
# Returns the latitude of this point
|
|
19
|
+
# @api public
|
|
20
|
+
# @example
|
|
21
|
+
# point.lat
|
|
22
|
+
# @return [Float]
|
|
23
|
+
alias_method :lat, :latitude
|
|
24
|
+
|
|
25
|
+
# Returns the longitude of this point
|
|
26
|
+
#
|
|
27
|
+
# @api public
|
|
28
|
+
# @example
|
|
29
|
+
# point.longitude
|
|
30
|
+
# @return [Float]
|
|
13
31
|
def longitude
|
|
14
32
|
coordinates[1]
|
|
15
33
|
end
|
|
16
|
-
|
|
17
|
-
|
|
34
|
+
|
|
35
|
+
# @!method long
|
|
36
|
+
# Returns the longitude of this point
|
|
37
|
+
# @api public
|
|
38
|
+
# @example
|
|
39
|
+
# point.long
|
|
40
|
+
# @return [Float]
|
|
41
|
+
alias_method :long, :longitude
|
|
42
|
+
|
|
43
|
+
# @!method lng
|
|
44
|
+
# Returns the longitude of this point
|
|
45
|
+
# @api public
|
|
46
|
+
# @example
|
|
47
|
+
# point.lng
|
|
48
|
+
# @return [Float]
|
|
49
|
+
alias_method :lng, :longitude
|
|
18
50
|
end
|
|
19
51
|
end
|
|
20
52
|
end
|
data/lib/twitter/geo/polygon.rb
CHANGED
data/lib/twitter/geo.rb
CHANGED
|
@@ -2,10 +2,24 @@ require "equalizer"
|
|
|
2
2
|
require "twitter/base"
|
|
3
3
|
|
|
4
4
|
module Twitter
|
|
5
|
-
|
|
5
|
+
# Represents geographic information
|
|
6
|
+
class Geo < Base
|
|
6
7
|
include Equalizer.new(:coordinates)
|
|
8
|
+
|
|
9
|
+
# The coordinates of this geographic location
|
|
10
|
+
#
|
|
11
|
+
# @api public
|
|
12
|
+
# @example
|
|
13
|
+
# geo.coordinates
|
|
7
14
|
# @return [Array<Float>]
|
|
8
15
|
attr_reader :coordinates
|
|
9
|
-
|
|
16
|
+
|
|
17
|
+
# @!method coords
|
|
18
|
+
# The coordinates of this geographic location
|
|
19
|
+
# @api public
|
|
20
|
+
# @example
|
|
21
|
+
# geo.coords
|
|
22
|
+
# @return [Array<Float>]
|
|
23
|
+
alias_method :coords, :coordinates
|
|
10
24
|
end
|
|
11
25
|
end
|
data/lib/twitter/geo_factory.rb
CHANGED
|
@@ -3,12 +3,16 @@ require "twitter/geo/point"
|
|
|
3
3
|
require "twitter/geo/polygon"
|
|
4
4
|
|
|
5
5
|
module Twitter
|
|
6
|
+
# Factory for creating geo objects based on type
|
|
6
7
|
class GeoFactory < Twitter::Factory
|
|
7
8
|
class << self
|
|
8
|
-
#
|
|
9
|
+
# Constructs a new geo object
|
|
9
10
|
#
|
|
10
|
-
# @
|
|
11
|
-
# @
|
|
11
|
+
# @api public
|
|
12
|
+
# @example
|
|
13
|
+
# Twitter::GeoFactory.new(type: "Point", coordinates: [1.0, 2.0])
|
|
14
|
+
# @param attrs [Hash] The attributes hash with a :type key
|
|
15
|
+
# @raise [IndexError] Error raised when argument is missing a :type key
|
|
12
16
|
# @return [Twitter::Geo]
|
|
13
17
|
def new(attrs = {})
|
|
14
18
|
super(:type, Geo, attrs)
|
data/lib/twitter/geo_results.rb
CHANGED
|
@@ -2,25 +2,56 @@ require "twitter/enumerable"
|
|
|
2
2
|
require "twitter/utils"
|
|
3
3
|
|
|
4
4
|
module Twitter
|
|
5
|
+
# Represents a collection of geo search results
|
|
5
6
|
class GeoResults
|
|
6
|
-
include
|
|
7
|
-
include
|
|
7
|
+
include Enumerable
|
|
8
|
+
include Utils
|
|
9
|
+
|
|
10
|
+
# The raw attributes hash
|
|
11
|
+
#
|
|
12
|
+
# @api public
|
|
13
|
+
# @example
|
|
14
|
+
# results.attrs
|
|
8
15
|
# @return [Hash]
|
|
9
16
|
attr_reader :attrs
|
|
10
|
-
|
|
11
|
-
|
|
17
|
+
|
|
18
|
+
# @!method to_h
|
|
19
|
+
# Returns the attributes as a hash
|
|
20
|
+
# @api public
|
|
21
|
+
# @example
|
|
22
|
+
# results.to_h
|
|
23
|
+
# @return [Hash]
|
|
24
|
+
alias_method :to_h, :attrs
|
|
25
|
+
|
|
26
|
+
# @!method to_hash
|
|
27
|
+
# Returns the attributes as a hash
|
|
28
|
+
# @api public
|
|
29
|
+
# @example
|
|
30
|
+
# results.to_hash
|
|
31
|
+
# @return [Hash]
|
|
32
|
+
alias_method :to_hash, :to_h
|
|
12
33
|
|
|
13
34
|
# Initializes a new GeoResults object
|
|
14
35
|
#
|
|
15
|
-
# @
|
|
36
|
+
# @api public
|
|
37
|
+
# @example
|
|
38
|
+
# Twitter::GeoResults.new(result: {places: []})
|
|
39
|
+
# @param attrs [Hash] The attributes hash from the API response
|
|
16
40
|
# @return [Twitter::GeoResults]
|
|
17
|
-
def initialize(attrs =
|
|
18
|
-
@attrs = attrs
|
|
19
|
-
|
|
41
|
+
def initialize(attrs = nil)
|
|
42
|
+
@attrs = attrs || {}
|
|
43
|
+
empty_hash = {} # : Hash[Symbol, untyped]
|
|
44
|
+
empty_array = [] # : Array[untyped]
|
|
45
|
+
@collection = @attrs.fetch(:result, empty_hash).fetch(:places, empty_array).collect do |place| # steep:ignore ArgumentTypeMismatch
|
|
20
46
|
Place.new(place)
|
|
21
47
|
end
|
|
22
48
|
end
|
|
23
49
|
|
|
50
|
+
# Returns the token for pagination
|
|
51
|
+
#
|
|
52
|
+
# @api public
|
|
53
|
+
# @example
|
|
54
|
+
# results.token
|
|
24
55
|
# @return [String]
|
|
25
56
|
def token
|
|
26
57
|
@attrs[:token]
|
data/lib/twitter/headers.rb
CHANGED
|
@@ -1,30 +1,59 @@
|
|
|
1
|
-
require "
|
|
1
|
+
require "uri"
|
|
2
2
|
require "base64"
|
|
3
3
|
require "simple_oauth"
|
|
4
4
|
|
|
5
5
|
module Twitter
|
|
6
|
+
# Builds HTTP headers for Twitter API requests
|
|
6
7
|
class Headers
|
|
8
|
+
# Initializes a new Headers object
|
|
9
|
+
#
|
|
10
|
+
# @api public
|
|
11
|
+
# @example
|
|
12
|
+
# Twitter::Headers.new(client, :get, "https://api.twitter.com")
|
|
13
|
+
# @param client [Twitter::Client] The client making the request
|
|
14
|
+
# @param request_method [Symbol] The HTTP request method
|
|
15
|
+
# @param url [String] The request URL
|
|
16
|
+
# @param options [Hash] Additional options
|
|
17
|
+
# @return [Twitter::Headers]
|
|
7
18
|
def initialize(client, request_method, url, options = {})
|
|
8
19
|
@client = client
|
|
9
|
-
@request_method = request_method
|
|
10
|
-
@uri =
|
|
20
|
+
@request_method = request_method
|
|
21
|
+
@uri = URI.parse(url)
|
|
11
22
|
@bearer_token_request = options.delete(:bearer_token_request)
|
|
12
23
|
@options = options
|
|
13
24
|
end
|
|
14
25
|
|
|
26
|
+
# Check if this is a bearer token request
|
|
27
|
+
#
|
|
28
|
+
# @api public
|
|
29
|
+
# @example
|
|
30
|
+
# headers.bearer_token_request? # => false
|
|
31
|
+
# @return [Boolean]
|
|
15
32
|
def bearer_token_request?
|
|
16
33
|
!!@bearer_token_request
|
|
17
34
|
end
|
|
18
35
|
|
|
36
|
+
# Generate OAuth authentication header
|
|
37
|
+
#
|
|
38
|
+
# @api public
|
|
39
|
+
# @example
|
|
40
|
+
# headers.oauth_auth_header # => #<SimpleOAuth::Header>
|
|
41
|
+
# @return [SimpleOAuth::Header]
|
|
19
42
|
def oauth_auth_header
|
|
20
|
-
SimpleOAuth::Header.new(@request_method, @uri, @options, @client.credentials.merge(ignore_extra_keys: true))
|
|
43
|
+
SimpleOAuth::Header.new(@request_method, @uri.to_s, @options, @client.credentials.merge(ignore_extra_keys: true))
|
|
21
44
|
end
|
|
22
45
|
|
|
46
|
+
# Build the request headers hash
|
|
47
|
+
#
|
|
48
|
+
# @api public
|
|
49
|
+
# @example
|
|
50
|
+
# headers.request_headers # => {user_agent: "...", authorization: "..."}
|
|
51
|
+
# @return [Hash]
|
|
23
52
|
def request_headers
|
|
24
|
-
headers = {}
|
|
53
|
+
headers = {} # : Hash[Symbol, String]
|
|
25
54
|
headers[:user_agent] = @client.user_agent
|
|
26
55
|
if bearer_token_request?
|
|
27
|
-
headers[:accept]
|
|
56
|
+
headers[:accept] = "*/*"
|
|
28
57
|
headers[:authorization] = bearer_token_credentials_auth_header
|
|
29
58
|
else
|
|
30
59
|
headers[:authorization] = auth_header
|
|
@@ -32,8 +61,12 @@ module Twitter
|
|
|
32
61
|
headers
|
|
33
62
|
end
|
|
34
63
|
|
|
35
|
-
|
|
64
|
+
private
|
|
36
65
|
|
|
66
|
+
# Generate the appropriate auth header based on credentials
|
|
67
|
+
#
|
|
68
|
+
# @api private
|
|
69
|
+
# @return [String]
|
|
37
70
|
def auth_header
|
|
38
71
|
if @client.user_token?
|
|
39
72
|
oauth_auth_header.to_s
|
|
@@ -43,6 +76,9 @@ module Twitter
|
|
|
43
76
|
end
|
|
44
77
|
end
|
|
45
78
|
|
|
79
|
+
# Generate a bearer auth header
|
|
80
|
+
#
|
|
81
|
+
# @api private
|
|
46
82
|
# @return [String]
|
|
47
83
|
def bearer_auth_header
|
|
48
84
|
"Bearer #{@client.bearer_token}"
|
|
@@ -50,6 +86,7 @@ module Twitter
|
|
|
50
86
|
|
|
51
87
|
# Generates authentication header for a bearer token request
|
|
52
88
|
#
|
|
89
|
+
# @api private
|
|
53
90
|
# @return [String]
|
|
54
91
|
def bearer_token_credentials_auth_header
|
|
55
92
|
"Basic #{Base64.strict_encode64("#{@client.consumer_key}:#{@client.consumer_secret}")}"
|