twitter 5.5.1 → 5.6.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.
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