twitter 5.5.1 → 5.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG.md +12 -0
  5. data/README.md +8 -10
  6. data/lib/twitter/base.rb +4 -2
  7. data/lib/twitter/client.rb +7 -5
  8. data/lib/twitter/configuration.rb +1 -1
  9. data/lib/twitter/cursor.rb +18 -17
  10. data/lib/twitter/entities.rb +27 -1
  11. data/lib/twitter/error.rb +1 -1
  12. data/lib/twitter/error/request_timeout.rb +10 -0
  13. data/lib/twitter/geo_results.rb +5 -3
  14. data/lib/twitter/media/photo.rb +1 -1
  15. data/lib/twitter/null_object.rb +8 -20
  16. data/lib/twitter/profile_banner.rb +1 -1
  17. data/lib/twitter/request.rb +47 -0
  18. data/lib/twitter/rest/api/direct_messages.rb +7 -5
  19. data/lib/twitter/rest/api/favorites.rb +7 -7
  20. data/lib/twitter/rest/api/friends_and_followers.rb +11 -9
  21. data/lib/twitter/rest/api/help.rb +4 -3
  22. data/lib/twitter/rest/api/lists.rb +9 -7
  23. data/lib/twitter/rest/api/oauth.rb +11 -5
  24. data/lib/twitter/rest/api/places_and_geo.rb +6 -5
  25. data/lib/twitter/rest/api/saved_searches.rb +8 -6
  26. data/lib/twitter/rest/api/search.rb +4 -10
  27. data/lib/twitter/rest/api/spam_reporting.rb +1 -0
  28. data/lib/twitter/rest/api/suggested_users.rb +4 -3
  29. data/lib/twitter/rest/api/timelines.rb +5 -4
  30. data/lib/twitter/rest/api/trends.rb +5 -4
  31. data/lib/twitter/rest/api/tweets.rb +19 -24
  32. data/lib/twitter/rest/api/users.rb +17 -16
  33. data/lib/twitter/rest/api/utils.rb +45 -73
  34. data/lib/twitter/rest/client.rb +34 -34
  35. data/lib/twitter/rest/request/multipart_with_file.rb +2 -0
  36. data/lib/twitter/rest/response/parse_json.rb +2 -0
  37. data/lib/twitter/rest/response/raise_error.rb +2 -0
  38. data/lib/twitter/search_results.rb +28 -60
  39. data/lib/twitter/streaming/client.rb +4 -4
  40. data/lib/twitter/suggestion.rb +1 -1
  41. data/lib/twitter/trend_results.rb +6 -4
  42. data/lib/twitter/tweet.rb +3 -3
  43. data/lib/twitter/user.rb +1 -1
  44. data/lib/twitter/utils.rb +18 -3
  45. data/lib/twitter/version.rb +2 -2
  46. data/spec/helper.rb +1 -1
  47. data/spec/twitter/error_spec.rb +1 -1
  48. data/spec/twitter/geo_factory_spec.rb +1 -1
  49. data/spec/twitter/identifiable_spec.rb +1 -1
  50. data/spec/twitter/media_factory_spec.rb +1 -1
  51. data/spec/twitter/rest/api/favorites_spec.rb +2 -2
  52. data/spec/twitter/rest/api/tweets_spec.rb +4 -4
  53. data/spec/twitter/rest/client_spec.rb +13 -25
  54. data/spec/twitter/tweet_spec.rb +69 -0
  55. data/twitter.gemspec +2 -1
  56. metadata +23 -15
  57. metadata.gz.sig +0 -0
  58. data/spec/twitter/null_object_spec.rb +0 -90
@@ -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 => 5,
64
- :timeout => 10,
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::Builder]
74
+ # @return [Faraday::RackBuilder]
73
75
  def middleware
74
- @middleware ||= Faraday::Builder.new do |builder|
76
+ @middleware ||= Faraday::RackBuilder.new do |faraday|
75
77
  # Convert file uploads to Faraday::UploadIO objects
76
- builder.use Twitter::REST::Request::MultipartWithFile
77
- # Checks for files in the payload
78
- builder.use Faraday::Request::Multipart
79
- # Convert request params to "www-form-urlencoded"
80
- builder.use Faraday::Request::UrlEncoded
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
- builder.use Twitter::REST::Response::RaiseError
84
+ faraday.response :raise_error
83
85
  # Parse JSON response bodies
84
- builder.use Twitter::REST::Response::ParseJson
85
- # Set Faraday's HTTP adapter
86
- builder.adapter Faraday.default_adapter
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) # rubocop:disable ParameterLists
122
+ def request(method, path, params = {}, signature_params = params)
131
123
  response = connection.send(method.to_sym, path, params) do |request|
132
- bearer_token_request = params.delete(:bearer_token_request)
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
- raise Twitter::Error.new(error) # rubocop:disable RaiseArgs
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) # rubocop:disable ParameterLists
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
@@ -36,3 +36,5 @@ module Twitter
36
36
  end
37
37
  end
38
38
  end
39
+
40
+ Faraday::Request.register_middleware :multipart_with_file => Twitter::REST::Request::MultipartWithFile
@@ -29,3 +29,5 @@ module Twitter
29
29
  end
30
30
  end
31
31
  end
32
+
33
+ Faraday::Response.register_middleware :parse_json => Twitter::REST::Response::ParseJson
@@ -24,3 +24,5 @@ module Twitter
24
24
  end
25
25
  end
26
26
  end
27
+
28
+ Faraday::Response.register_middleware :raise_error => Twitter::REST::Response::RaiseError
@@ -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
- alias_method :to_hash, :attrs
9
- alias_method :to_hsh, :attrs
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 client [Twitter::REST::Client]
16
- # @param path [String]
19
+ # @param request [Twitter::Request]
17
20
  # @return [Twitter::SearchResults]
18
- def from_response(response, client, request_method, path, options) # rubocop:disable ParameterLists
19
- new(response[:body], client, request_method, path, options)
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 client [Twitter::REST::Client]
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, client, request_method, path, options = {}) # rubocop:disable ParameterLists
32
- @client = client
33
- @request_method = request_method.to_sym
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
- !next_results?
44
+ !next_page?
45
45
  end
46
46
 
47
47
  # @return [Boolean]
48
- def next_results?
49
- !!(@attrs[:search_metadata] && @attrs[:search_metadata][:next_results])
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 next_results
59
- if next_results?
60
- query_string = strip_first_character(@attrs[:search_metadata][:next_results])
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]).map do |tweet|
72
+ Array(@attrs[:statuses]).collect do |tweet|
75
73
  @collection << Tweet.new(tweet)
76
74
  end
77
- end
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
- symbolize_keys(Faraday::Utils.parse_nested_query(query_string))
108
- end
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 = {}, &block)
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, &block) # rubocop:disable ParameterLists
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
- block.call(item)
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.map do |param, value|
115
+ params.collect do |param, value|
116
116
  [param, URI.encode(value)].join('=')
117
117
  end.sort.join('&')
118
118
  end
@@ -8,7 +8,7 @@ module Twitter
8
8
 
9
9
  # @return [Array<Twitter::User>]
10
10
  def users
11
- Array(@attrs[:users]).map do |user|
11
+ Array(@attrs[:users]).collect do |user|
12
12
  User.new(user)
13
13
  end
14
14
  end
@@ -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
- alias_method :to_hash, :attrs
14
- alias_method :to_hsh, :attrs
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]).map do |trend|
34
+ @collection = Array(@attrs[:trends]).collect do |trend|
33
35
  Trend.new(trend)
34
36
  end
35
37
  end
@@ -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
- alias_method :favorites_count, :favorite_count
14
- alias_method :favoriters_count, :favorite_count
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
- alias_method :retweeters_count, :retweet_count
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
@@ -34,7 +34,7 @@ module Twitter
34
34
 
35
35
  # @return [Array<Twitter::Entity::URI>]
36
36
  def description_uris
37
- Array(@attrs[:entities][:description][:urls]).map do |entity|
37
+ Array(@attrs[:entities][:description][:urls]).collect do |entity|
38
38
  Entity::URI.new(entity)
39
39
  end
40
40
  end
@@ -1,13 +1,28 @@
1
1
  module Twitter
2
2
  module Utils
3
- module_function
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.map { |object| yield object }
21
+ enumerable.collect { |object| yield object }
8
22
  else
9
- enumerable.map { |object| Thread.new { yield object } }.map(&:value)
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
@@ -1,8 +1,8 @@
1
1
  module Twitter
2
2
  class Version
3
3
  MAJOR = 5
4
- MINOR = 5
5
- PATCH = 1
4
+ MINOR = 6
5
+ PATCH = 0
6
6
  PRE = nil
7
7
 
8
8
  class << self
@@ -8,7 +8,7 @@ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
8
8
 
9
9
  SimpleCov.start do
10
10
  add_filter '/spec/'
11
- minimum_coverage(99.35)
11
+ minimum_coverage(99.42)
12
12
  end
13
13
 
14
14
  require 'twitter'
@@ -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 exception
39
+ expect { @client.user_timeline('sferik') }.to raise_error(exception)
40
40
  end
41
41
  end
42
42
  end