twitter 5.5.1 → 5.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CHANGELOG.md +12 -0
- data/README.md +8 -10
- data/lib/twitter/base.rb +4 -2
- data/lib/twitter/client.rb +7 -5
- data/lib/twitter/configuration.rb +1 -1
- data/lib/twitter/cursor.rb +18 -17
- data/lib/twitter/entities.rb +27 -1
- data/lib/twitter/error.rb +1 -1
- data/lib/twitter/error/request_timeout.rb +10 -0
- data/lib/twitter/geo_results.rb +5 -3
- data/lib/twitter/media/photo.rb +1 -1
- data/lib/twitter/null_object.rb +8 -20
- data/lib/twitter/profile_banner.rb +1 -1
- data/lib/twitter/request.rb +47 -0
- data/lib/twitter/rest/api/direct_messages.rb +7 -5
- data/lib/twitter/rest/api/favorites.rb +7 -7
- data/lib/twitter/rest/api/friends_and_followers.rb +11 -9
- data/lib/twitter/rest/api/help.rb +4 -3
- data/lib/twitter/rest/api/lists.rb +9 -7
- data/lib/twitter/rest/api/oauth.rb +11 -5
- data/lib/twitter/rest/api/places_and_geo.rb +6 -5
- data/lib/twitter/rest/api/saved_searches.rb +8 -6
- data/lib/twitter/rest/api/search.rb +4 -10
- data/lib/twitter/rest/api/spam_reporting.rb +1 -0
- data/lib/twitter/rest/api/suggested_users.rb +4 -3
- data/lib/twitter/rest/api/timelines.rb +5 -4
- data/lib/twitter/rest/api/trends.rb +5 -4
- data/lib/twitter/rest/api/tweets.rb +19 -24
- data/lib/twitter/rest/api/users.rb +17 -16
- data/lib/twitter/rest/api/utils.rb +45 -73
- data/lib/twitter/rest/client.rb +34 -34
- data/lib/twitter/rest/request/multipart_with_file.rb +2 -0
- data/lib/twitter/rest/response/parse_json.rb +2 -0
- data/lib/twitter/rest/response/raise_error.rb +2 -0
- data/lib/twitter/search_results.rb +28 -60
- data/lib/twitter/streaming/client.rb +4 -4
- data/lib/twitter/suggestion.rb +1 -1
- data/lib/twitter/trend_results.rb +6 -4
- data/lib/twitter/tweet.rb +3 -3
- data/lib/twitter/user.rb +1 -1
- data/lib/twitter/utils.rb +18 -3
- data/lib/twitter/version.rb +2 -2
- data/spec/helper.rb +1 -1
- data/spec/twitter/error_spec.rb +1 -1
- data/spec/twitter/geo_factory_spec.rb +1 -1
- data/spec/twitter/identifiable_spec.rb +1 -1
- data/spec/twitter/media_factory_spec.rb +1 -1
- data/spec/twitter/rest/api/favorites_spec.rb +2 -2
- data/spec/twitter/rest/api/tweets_spec.rb +4 -4
- data/spec/twitter/rest/client_spec.rb +13 -25
- data/spec/twitter/tweet_spec.rb +69 -0
- data/twitter.gemspec +2 -1
- metadata +23 -15
- metadata.gz.sig +0 -0
- data/spec/twitter/null_object_spec.rb +0 -90
data/lib/twitter/rest/client.rb
CHANGED
@@ -2,9 +2,11 @@ require 'base64'
|
|
2
2
|
require 'faraday'
|
3
3
|
require 'faraday/request/multipart'
|
4
4
|
require 'json'
|
5
|
+
require 'timeout'
|
5
6
|
require 'twitter/client'
|
6
7
|
require 'twitter/error'
|
7
8
|
require 'twitter/error/configuration_error'
|
9
|
+
require 'twitter/error/request_timeout'
|
8
10
|
require 'twitter/rest/api/direct_messages'
|
9
11
|
require 'twitter/rest/api/favorites'
|
10
12
|
require 'twitter/rest/api/friends_and_followers'
|
@@ -60,8 +62,8 @@ module Twitter
|
|
60
62
|
:user_agent => user_agent,
|
61
63
|
},
|
62
64
|
:request => {
|
63
|
-
:open_timeout =>
|
64
|
-
:timeout =>
|
65
|
+
:open_timeout => 10,
|
66
|
+
:timeout => 30,
|
65
67
|
},
|
66
68
|
}
|
67
69
|
end
|
@@ -69,29 +71,24 @@ module Twitter
|
|
69
71
|
# @note Faraday's middleware stack implementation is comparable to that of Rack middleware. The order of middleware is important: the first middleware on the list wraps all others, while the last middleware is the innermost one.
|
70
72
|
# @see https://github.com/technoweenie/faraday#advanced-middleware-usage
|
71
73
|
# @see http://mislav.uniqpath.com/2011/07/faraday-advanced-http/
|
72
|
-
# @return [Faraday::
|
74
|
+
# @return [Faraday::RackBuilder]
|
73
75
|
def middleware
|
74
|
-
@middleware ||= Faraday::
|
76
|
+
@middleware ||= Faraday::RackBuilder.new do |faraday|
|
75
77
|
# Convert file uploads to Faraday::UploadIO objects
|
76
|
-
|
77
|
-
# Checks for files in the payload
|
78
|
-
|
79
|
-
#
|
80
|
-
|
78
|
+
faraday.request :multipart_with_file
|
79
|
+
# Checks for files in the payload, otherwise leaves everything untouched
|
80
|
+
faraday.request :multipart
|
81
|
+
# Encodes as "application/x-www-form-urlencoded" if not already encoded
|
82
|
+
faraday.request :url_encoded
|
81
83
|
# Handle error responses
|
82
|
-
|
84
|
+
faraday.response :raise_error
|
83
85
|
# Parse JSON response bodies
|
84
|
-
|
85
|
-
# Set
|
86
|
-
|
86
|
+
faraday.response :parse_json
|
87
|
+
# Set default HTTP adapter
|
88
|
+
faraday.adapter :net_http
|
87
89
|
end
|
88
90
|
end
|
89
91
|
|
90
|
-
# Perform an HTTP DELETE request
|
91
|
-
def delete(path, params = {})
|
92
|
-
request(:delete, path, params)
|
93
|
-
end
|
94
|
-
|
95
92
|
# Perform an HTTP GET request
|
96
93
|
def get(path, params = {})
|
97
94
|
request(:get, path, params)
|
@@ -103,11 +100,6 @@ module Twitter
|
|
103
100
|
request(:post, path, params, signature_params)
|
104
101
|
end
|
105
102
|
|
106
|
-
# Perform an HTTP PUT request
|
107
|
-
def put(path, params = {})
|
108
|
-
request(:put, path, params)
|
109
|
-
end
|
110
|
-
|
111
103
|
# @return [Boolean]
|
112
104
|
def bearer_token?
|
113
105
|
!!bearer_token
|
@@ -127,23 +119,31 @@ module Twitter
|
|
127
119
|
@connection ||= Faraday.new(ENDPOINT, connection_options)
|
128
120
|
end
|
129
121
|
|
130
|
-
def request(method, path, params = {}, signature_params = params)
|
122
|
+
def request(method, path, params = {}, signature_params = params)
|
131
123
|
response = connection.send(method.to_sym, path, params) do |request|
|
132
|
-
|
133
|
-
if bearer_token_request
|
134
|
-
request.headers[:accept] = '*/*' # It is important we set this, otherwise we get an error.
|
135
|
-
request.headers[:authorization] = bearer_token_credentials_auth_header
|
136
|
-
request.headers[:content_type] = 'application/x-www-form-urlencoded; charset=UTF-8'
|
137
|
-
else
|
138
|
-
request.headers[:authorization] = auth_token(method, path, params, signature_params)
|
139
|
-
end
|
124
|
+
request.headers.update(request_headers(method, path, params, signature_params))
|
140
125
|
end
|
141
126
|
response.env
|
127
|
+
rescue Faraday::Error::TimeoutError, Timeout::Error => error
|
128
|
+
raise(Twitter::Error::RequestTimeout.new(error))
|
142
129
|
rescue Faraday::Error::ClientError, JSON::ParserError => error
|
143
|
-
|
130
|
+
fail(Twitter::Error.new(error))
|
131
|
+
end
|
132
|
+
|
133
|
+
def request_headers(method, path, params = {}, signature_params = params)
|
134
|
+
bearer_token_request = params.delete(:bearer_token_request)
|
135
|
+
headers = {}
|
136
|
+
if bearer_token_request
|
137
|
+
headers[:accept] = '*/*'
|
138
|
+
headers[:authorization] = bearer_token_credentials_auth_header
|
139
|
+
headers[:content_type] = 'application/x-www-form-urlencoded; charset=UTF-8'
|
140
|
+
else
|
141
|
+
headers[:authorization] = auth_token(method, path, params, signature_params)
|
142
|
+
end
|
143
|
+
headers
|
144
144
|
end
|
145
145
|
|
146
|
-
def auth_token(method, path, params = {}, signature_params = params)
|
146
|
+
def auth_token(method, path, params = {}, signature_params = params)
|
147
147
|
if !user_token?
|
148
148
|
@bearer_token = token unless bearer_token?
|
149
149
|
bearer_auth_header
|
@@ -1,38 +1,38 @@
|
|
1
|
+
require 'cgi'
|
1
2
|
require 'twitter/enumerable'
|
3
|
+
require 'twitter/utils'
|
4
|
+
require 'uri'
|
2
5
|
|
3
6
|
module Twitter
|
4
7
|
class SearchResults
|
5
8
|
include Twitter::Enumerable
|
9
|
+
include Twitter::Utils
|
6
10
|
attr_reader :attrs
|
7
11
|
alias_method :to_h, :attrs
|
8
|
-
|
9
|
-
|
12
|
+
deprecate_alias :to_hash, :to_h
|
13
|
+
deprecate_alias :to_hsh, :to_h
|
10
14
|
|
11
15
|
class << self
|
12
16
|
# Construct a new SearchResults object from a response hash
|
13
17
|
#
|
14
18
|
# @param response [Hash]
|
15
|
-
# @param
|
16
|
-
# @param path [String]
|
19
|
+
# @param request [Twitter::Request]
|
17
20
|
# @return [Twitter::SearchResults]
|
18
|
-
def from_response(response,
|
19
|
-
new(response[:body],
|
21
|
+
def from_response(response, request)
|
22
|
+
new(response[:body], request)
|
20
23
|
end
|
21
24
|
end
|
22
25
|
|
23
26
|
# Initializes a new SearchResults object
|
24
27
|
#
|
25
28
|
# @param attrs [Hash]
|
26
|
-
# @param
|
27
|
-
# @param request_method [String, Symbol]
|
28
|
-
# @param path [String]
|
29
|
-
# @param options [Hash]
|
29
|
+
# @param request [Twitter::Request]
|
30
30
|
# @return [Twitter::SearchResults]
|
31
|
-
def initialize(attrs,
|
32
|
-
@client = client
|
33
|
-
@request_method =
|
34
|
-
@path = path
|
35
|
-
@options = options
|
31
|
+
def initialize(attrs, request)
|
32
|
+
@client = request.client
|
33
|
+
@request_method = request.verb
|
34
|
+
@path = request.path
|
35
|
+
@options = request.options
|
36
36
|
@collection = []
|
37
37
|
self.attrs = attrs
|
38
38
|
end
|
@@ -41,60 +41,38 @@ module Twitter
|
|
41
41
|
|
42
42
|
# @return [Boolean]
|
43
43
|
def last?
|
44
|
-
!
|
44
|
+
!next_page?
|
45
45
|
end
|
46
46
|
|
47
47
|
# @return [Boolean]
|
48
|
-
def
|
49
|
-
|
48
|
+
def next_page?
|
49
|
+
!!@attrs[:search_metadata][:next_results] unless @attrs[:search_metadata].nil?
|
50
50
|
end
|
51
|
-
alias_method :next_page?, :next_results?
|
52
|
-
alias_method :next?, :next_results?
|
53
51
|
|
54
52
|
# Returns a Hash of query parameters for the next result in the search
|
55
53
|
#
|
56
54
|
# @note Returned Hash can be merged into the previous search options list to easily access the next page.
|
57
55
|
# @return [Hash] The parameters needed to fetch the next page.
|
58
|
-
def
|
59
|
-
if
|
60
|
-
|
61
|
-
query_string_to_hash(query_string)
|
56
|
+
def next_page
|
57
|
+
if next_page?
|
58
|
+
query_string_to_hash(@attrs[:search_metadata][:next_results])
|
62
59
|
end
|
63
60
|
end
|
64
|
-
alias_method :next_page, :next_results
|
65
|
-
alias_method :next, :next_results
|
66
61
|
|
62
|
+
# @return [Hash]
|
67
63
|
def fetch_next_page
|
68
64
|
response = @client.send(@request_method, @path, next_page)
|
69
65
|
self.attrs = response[:body]
|
70
66
|
end
|
71
67
|
|
68
|
+
# @param attrs [Hash]
|
69
|
+
# @return [Hash]
|
72
70
|
def attrs=(attrs)
|
73
71
|
@attrs = attrs
|
74
|
-
Array(@attrs[:statuses]).
|
72
|
+
Array(@attrs[:statuses]).collect do |tweet|
|
75
73
|
@collection << Tweet.new(tweet)
|
76
74
|
end
|
77
|
-
|
78
|
-
|
79
|
-
# Returns the string with the first character removed
|
80
|
-
#
|
81
|
-
# @param string [String]
|
82
|
-
# @return [String] A copy of string without the first character.
|
83
|
-
# @example Returns the query string with the question mark removed
|
84
|
-
# strip_first_character("?foo=bar&baz=qux") #=> "foo=bar&baz=qux"
|
85
|
-
def strip_first_character(string)
|
86
|
-
strip_first_character!(string.dup)
|
87
|
-
end
|
88
|
-
|
89
|
-
# Removes the first character from a string
|
90
|
-
#
|
91
|
-
# @param string [String]
|
92
|
-
# @return [String] The string without the first character.
|
93
|
-
# @example Remove the first character from a query string
|
94
|
-
# strip_first_character!("?foo=bar&baz=qux") #=> "foo=bar&baz=qux"
|
95
|
-
def strip_first_character!(string)
|
96
|
-
string[0] = ''
|
97
|
-
string
|
75
|
+
@attrs
|
98
76
|
end
|
99
77
|
|
100
78
|
# Converts query string to a hash
|
@@ -104,18 +82,8 @@ module Twitter
|
|
104
82
|
# @example Convert query string to a hash
|
105
83
|
# query_string_to_hash("foo=bar&baz=qux") #=> {:foo=>"bar", :baz=>"qux"}
|
106
84
|
def query_string_to_hash(query_string)
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
# Converts hash's keys to symbols
|
111
|
-
#
|
112
|
-
# @note Does not support nested hashes.
|
113
|
-
# @param hash [Hash]
|
114
|
-
# @return [Hash] The hash with symbols as keys.
|
115
|
-
# @example Convert hash's keys to symbols
|
116
|
-
# symbolize_keys({"foo"=>"bar", "baz"=>"qux"}) #=> {:foo=>"bar", :baz=>"qux"}
|
117
|
-
def symbolize_keys(hash)
|
118
|
-
Hash[hash.map { |key, value| [key.to_sym, value] }]
|
85
|
+
query = CGI.parse(URI.parse(query_string).query)
|
86
|
+
Hash[query.collect { |key, value| [key.to_sym, value.first] }]
|
119
87
|
end
|
120
88
|
end
|
121
89
|
end
|
@@ -13,7 +13,7 @@ module Twitter
|
|
13
13
|
# Initializes a new Client object
|
14
14
|
#
|
15
15
|
# @return [Twitter::Streaming::Client]
|
16
|
-
def initialize(options = {}
|
16
|
+
def initialize(options = {})
|
17
17
|
super
|
18
18
|
@connection = Streaming::Connection.new
|
19
19
|
end
|
@@ -99,20 +99,20 @@ module Twitter
|
|
99
99
|
|
100
100
|
private
|
101
101
|
|
102
|
-
def request(method, uri, params
|
102
|
+
def request(method, uri, params)
|
103
103
|
before_request.call
|
104
104
|
headers = default_headers.merge(:authorization => oauth_auth_header(method, uri, params).to_s)
|
105
105
|
request = HTTP::Request.new(method, uri + '?' + to_url_params(params), headers)
|
106
106
|
response = Streaming::Response.new do |data|
|
107
107
|
if item = Streaming::MessageParser.parse(data) # rubocop:disable AssignmentInCondition, IfUnlessModifier
|
108
|
-
|
108
|
+
yield(item)
|
109
109
|
end
|
110
110
|
end
|
111
111
|
@connection.stream(request, response)
|
112
112
|
end
|
113
113
|
|
114
114
|
def to_url_params(params)
|
115
|
-
params.
|
115
|
+
params.collect do |param, value|
|
116
116
|
[param, URI.encode(value)].join('=')
|
117
117
|
end.sort.join('&')
|
118
118
|
end
|
data/lib/twitter/suggestion.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
|
+
require 'memoizable'
|
1
2
|
require 'twitter/creatable'
|
2
3
|
require 'twitter/enumerable'
|
3
|
-
require 'memoizable'
|
4
4
|
require 'twitter/null_object'
|
5
|
+
require 'twitter/utils'
|
5
6
|
|
6
7
|
module Twitter
|
7
8
|
class TrendResults
|
8
9
|
include Twitter::Creatable
|
9
10
|
include Twitter::Enumerable
|
11
|
+
include Twitter::Utils
|
10
12
|
include Memoizable
|
11
13
|
attr_reader :attrs
|
12
14
|
alias_method :to_h, :attrs
|
13
|
-
|
14
|
-
|
15
|
+
deprecate_alias :to_hash, :to_h
|
16
|
+
deprecate_alias :to_hsh, :to_h
|
15
17
|
|
16
18
|
class << self
|
17
19
|
# Construct a new TrendResults object from a response hash
|
@@ -29,7 +31,7 @@ module Twitter
|
|
29
31
|
# @return [Twitter::TrendResults]
|
30
32
|
def initialize(attrs = {})
|
31
33
|
@attrs = attrs
|
32
|
-
@collection = Array(@attrs[:trends]).
|
34
|
+
@collection = Array(@attrs[:trends]).collect do |trend|
|
33
35
|
Trend.new(trend)
|
34
36
|
end
|
35
37
|
end
|
data/lib/twitter/tweet.rb
CHANGED
@@ -10,11 +10,11 @@ module Twitter
|
|
10
10
|
:in_reply_to_screen_name, :in_reply_to_attrs_id,
|
11
11
|
:in_reply_to_status_id, :in_reply_to_user_id, :lang,
|
12
12
|
:retweet_count, :retweeted, :source, :text, :truncated
|
13
|
-
|
14
|
-
|
13
|
+
deprecate_alias :favorites_count, :favorite_count
|
14
|
+
deprecate_alias :favoriters_count, :favorite_count
|
15
15
|
alias_method :in_reply_to_tweet_id, :in_reply_to_status_id
|
16
16
|
alias_method :reply?, :in_reply_to_status_id?
|
17
|
-
|
17
|
+
deprecate_alias :retweeters_count, :retweet_count
|
18
18
|
object_attr_reader :GeoFactory, :geo
|
19
19
|
object_attr_reader :Metadata, :metadata
|
20
20
|
object_attr_reader :Place, :place
|
data/lib/twitter/user.rb
CHANGED
data/lib/twitter/utils.rb
CHANGED
@@ -1,13 +1,28 @@
|
|
1
1
|
module Twitter
|
2
2
|
module Utils
|
3
|
-
|
3
|
+
class << self
|
4
|
+
def included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def deprecate_alias(new_name, old_name)
|
11
|
+
define_method(new_name) do |*args, &block|
|
12
|
+
warn "#{Kernel.caller.first}: [DEPRECATION] ##{new_name} is deprecated. Use ##{old_name} instead."
|
13
|
+
send(old_name, *args, &block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
4
18
|
def parallel_map(enumerable)
|
5
19
|
# Don't bother spawning a new thread if there's only one item
|
6
20
|
if enumerable.count == 1
|
7
|
-
enumerable.
|
21
|
+
enumerable.collect { |object| yield object }
|
8
22
|
else
|
9
|
-
enumerable.
|
23
|
+
enumerable.collect { |object| Thread.new { yield object } }.collect(&:value)
|
10
24
|
end
|
11
25
|
end
|
26
|
+
module_function :parallel_map
|
12
27
|
end
|
13
28
|
end
|
data/lib/twitter/version.rb
CHANGED
data/spec/helper.rb
CHANGED
data/spec/twitter/error_spec.rb
CHANGED
@@ -36,7 +36,7 @@ describe Twitter::Error do
|
|
36
36
|
stub_get('/1.1/statuses/user_timeline.json').with(:query => {:screen_name => 'sferik'}).to_return(:status => status, :body => body_message)
|
37
37
|
end
|
38
38
|
it "raises #{exception.name}" do
|
39
|
-
expect { @client.user_timeline('sferik') }.to raise_error
|
39
|
+
expect { @client.user_timeline('sferik') }.to raise_error(exception)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|