twitter 5.0.0.rc.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG.md +7 -1
  3. data/CONTRIBUTING.md +13 -15
  4. data/README.md +53 -33
  5. data/Rakefile +6 -0
  6. data/lib/twitter/arguments.rb +3 -0
  7. data/lib/twitter/base.rb +88 -89
  8. data/lib/twitter/client.rb +5 -41
  9. data/lib/twitter/configuration.rb +4 -5
  10. data/lib/twitter/core_ext/kernel.rb +5 -1
  11. data/lib/twitter/creatable.rb +6 -1
  12. data/lib/twitter/cursor.rb +16 -12
  13. data/lib/twitter/entity/uri.rb +2 -1
  14. data/lib/twitter/enumerable.rb +1 -1
  15. data/lib/twitter/error.rb +42 -39
  16. data/lib/twitter/factory.rb +12 -5
  17. data/lib/twitter/geo.rb +2 -7
  18. data/lib/twitter/geo_factory.rb +11 -7
  19. data/lib/twitter/geo_results.rb +12 -8
  20. data/lib/twitter/identity.rb +4 -12
  21. data/lib/twitter/list.rb +6 -3
  22. data/lib/twitter/media/photo.rb +5 -3
  23. data/lib/twitter/media_factory.rb +11 -7
  24. data/lib/twitter/null_object.rb +4 -3
  25. data/lib/twitter/place.rb +10 -16
  26. data/lib/twitter/profile_banner.rb +4 -5
  27. data/lib/twitter/rate_limit.rb +3 -0
  28. data/lib/twitter/relationship.rb +0 -9
  29. data/lib/twitter/rest/api/direct_messages.rb +9 -6
  30. data/lib/twitter/rest/api/favorites.rb +6 -11
  31. data/lib/twitter/rest/api/friends_and_followers.rb +6 -9
  32. data/lib/twitter/rest/api/lists.rb +27 -20
  33. data/lib/twitter/rest/api/oauth.rb +17 -0
  34. data/lib/twitter/rest/api/places_and_geo.rb +0 -18
  35. data/lib/twitter/rest/api/saved_searches.rb +6 -4
  36. data/lib/twitter/rest/api/suggested_users.rb +2 -2
  37. data/lib/twitter/rest/api/tweets.rb +7 -9
  38. data/lib/twitter/rest/api/users.rb +6 -6
  39. data/lib/twitter/rest/api/utils.rb +44 -17
  40. data/lib/twitter/rest/client.rb +25 -43
  41. data/lib/twitter/rest/response/parse_error_json.rb +15 -0
  42. data/lib/twitter/rest/response/parse_json.rb +5 -1
  43. data/lib/twitter/search_results.rb +12 -8
  44. data/lib/twitter/size.rb +2 -15
  45. data/lib/twitter/streaming/client.rb +23 -11
  46. data/lib/twitter/streaming/event.rb +35 -0
  47. data/lib/twitter/streaming/friend_list.rb +13 -0
  48. data/lib/twitter/streaming/message_parser.rb +18 -0
  49. data/lib/twitter/streaming/response.rb +4 -0
  50. data/lib/twitter/suggestion.rb +5 -10
  51. data/lib/twitter/token.rb +3 -1
  52. data/lib/twitter/trend.rb +2 -7
  53. data/lib/twitter/trend_results.rb +20 -14
  54. data/lib/twitter/tweet.rb +18 -23
  55. data/lib/twitter/user.rb +34 -19
  56. data/lib/twitter/version.rb +1 -1
  57. data/spec/fixtures/request_token.txt +6 -0
  58. data/spec/fixtures/track_streaming_user.json +5 -0
  59. data/spec/twitter/base_spec.rb +0 -16
  60. data/spec/twitter/basic_user_spec.rb +3 -3
  61. data/spec/twitter/cursor_spec.rb +4 -4
  62. data/spec/twitter/direct_message_spec.rb +9 -9
  63. data/spec/twitter/entity/uri_spec.rb +12 -11
  64. data/spec/twitter/geo/point_spec.rb +5 -5
  65. data/spec/twitter/geo/polygon_spec.rb +5 -5
  66. data/spec/twitter/geo_factory_spec.rb +2 -2
  67. data/spec/twitter/geo_spec.rb +6 -6
  68. data/spec/twitter/identifiable_spec.rb +5 -5
  69. data/spec/twitter/list_spec.rb +7 -7
  70. data/spec/twitter/media/photo_spec.rb +19 -18
  71. data/spec/twitter/media_factory_spec.rb +2 -2
  72. data/spec/twitter/null_object_spec.rb +7 -6
  73. data/spec/twitter/oembed_spec.rb +6 -6
  74. data/spec/twitter/place_spec.rb +37 -37
  75. data/spec/twitter/rate_limit_spec.rb +0 -17
  76. data/spec/twitter/relationship_spec.rb +4 -12
  77. data/spec/twitter/rest/api/direct_messages_spec.rb +8 -8
  78. data/spec/twitter/rest/api/friends_and_followers_spec.rb +50 -120
  79. data/spec/twitter/rest/api/geo_spec.rb +0 -14
  80. data/spec/twitter/rest/api/lists_spec.rb +39 -39
  81. data/spec/twitter/rest/api/oauth_spec.rb +15 -4
  82. data/spec/twitter/rest/api/saved_searches_spec.rb +6 -6
  83. data/spec/twitter/rest/api/tweets_spec.rb +6 -6
  84. data/spec/twitter/rest/api/users_spec.rb +4 -4
  85. data/spec/twitter/rest/client_spec.rb +9 -9
  86. data/spec/twitter/saved_search_spec.rb +5 -5
  87. data/spec/twitter/search_results_spec.rb +3 -3
  88. data/spec/twitter/settings_spec.rb +2 -2
  89. data/spec/twitter/size_spec.rb +5 -15
  90. data/spec/twitter/source_user_spec.rb +3 -3
  91. data/spec/twitter/streaming/client_spec.rb +33 -16
  92. data/spec/twitter/streaming/event_spec.rb +45 -0
  93. data/spec/twitter/suggestion_spec.rb +5 -15
  94. data/spec/twitter/target_user_spec.rb +3 -3
  95. data/spec/twitter/token_spec.rb +2 -2
  96. data/spec/twitter/trend_results_spec.rb +6 -6
  97. data/spec/twitter/trend_spec.rb +7 -17
  98. data/spec/twitter/tweet_spec.rb +31 -25
  99. data/spec/twitter/user_spec.rb +16 -16
  100. data/twitter.gemspec +5 -2
  101. metadata +67 -15
  102. metadata.gz.sig +0 -0
@@ -1,5 +1,6 @@
1
1
  require 'twitter/rest/api/utils'
2
2
  require 'twitter/token'
3
+ require 'twitter/rest/response/parse_error_json'
3
4
 
4
5
  module Twitter
5
6
  module REST
@@ -39,6 +40,22 @@ module Twitter
39
40
  object_from_response(Twitter::Token, :post, "/oauth2/invalidate_token", :access_token => access_token)
40
41
  end
41
42
 
43
+ # Allows a registered application to revoke an issued OAuth 2 Bearer Token by presenting its client credentials.
44
+ #
45
+ # @see https://dev.twitter.com/docs/api/1.1/post/oauth2/invalidate_token
46
+ # @rate_limited No
47
+ # @authentication Required
48
+ # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
49
+ # @return [String] The token string.
50
+ def reverse_token
51
+ conn = connection.dup
52
+ conn.builder.swap(4, Twitter::REST::Response::ParseErrorJson)
53
+ response = conn.post('/oauth/request_token?x_auth_mode=reverse_auth') do |request|
54
+ request.headers[:authorization] = oauth_auth_header(:post, 'https://api.twitter.com/oauth/request_token', :x_auth_mode => 'reverse_auth').to_s
55
+ end
56
+ response.body
57
+ end
58
+
42
59
  end
43
60
  end
44
61
  end
@@ -80,24 +80,6 @@ module Twitter
80
80
  end
81
81
  alias places_similar similar_places
82
82
 
83
- # Creates a new place at the given latitude and longitude
84
- #
85
- # @see https://dev.twitter.com/docs/api/1.1/post/geo/place
86
- # @rate_limited Yes
87
- # @authentication Requires user context
88
- # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
89
- # @param options [Hash] A customizable set of options.
90
- # @option options [String] :name The name a place is known as.
91
- # @option options [String] :contained_within This is the place_id which you would like to restrict the search results to. Setting this value means only places within the given place_id will be found.
92
- # @option options [String] :token The token found in the response from {Twitter::REST::API::PlacesAndGeo#places_similar}.
93
- # @option options [Float] :lat The latitude to search around. This option will be ignored unless it is inside the range -90.0 to +90.0 (North is positive) inclusive. It will also be ignored if there isn't a corresponding :long option.
94
- # @option options [Float] :long The longitude to search around. The valid range for longitude is -180.0 to +180.0 (East is positive) inclusive. This option will be ignored if outside that range, if it is not a number, if geo_enabled is disabled, or if there not a corresponding :lat option.
95
- # @option options [String] :"attribute:street_address" This option searches for places which have this given street address. There are other well-known and application-specific attributes available. Custom attributes are also permitted.
96
- # @return [Twitter::Place] The created place.
97
- def place_create(options={})
98
- object_from_response(Twitter::Place, :post, "/1.1/geo/place.json", options)
99
- end
100
-
101
83
  end
102
84
  end
103
85
  end
@@ -61,9 +61,10 @@ module Twitter
61
61
  # @return [Twitter::SavedSearch] The created saved search.
62
62
  # @param query [String] The query of the search the user would like to save.
63
63
  # @param options [Hash] A customizable set of options.
64
- def saved_search_create(query, options={})
64
+ def create_saved_search(query, options={})
65
65
  object_from_response(Twitter::SavedSearch, :post, "/1.1/saved_searches/create.json", options.merge(:query => query))
66
66
  end
67
+ deprecate_alias :saved_search_create, :create_saved_search
67
68
 
68
69
  # Destroys saved searches for the authenticated user
69
70
  #
@@ -73,17 +74,18 @@ module Twitter
73
74
  # @authentication Requires user context
74
75
  # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
75
76
  # @return [Array<Twitter::SavedSearch>] The deleted saved searches.
76
- # @overload saved_search_destroy(*ids)
77
+ # @overload destroy_saved_search(*ids)
77
78
  # @param ids [Enumerable<Integer>] A collection of saved search IDs.
78
- # @overload saved_search_destroy(*ids, options)
79
+ # @overload destroy_saved_search(*ids, options)
79
80
  # @param ids [Enumerable<Integer>] A collection of saved search IDs.
80
81
  # @param options [Hash] A customizable set of options.
81
- def saved_search_destroy(*args)
82
+ def destroy_saved_search(*args)
82
83
  arguments = Twitter::Arguments.new(args)
83
84
  arguments.flatten.threaded_map do |id|
84
85
  object_from_response(Twitter::SavedSearch, :post, "/1.1/saved_searches/destroy/#{id}.json", arguments.options)
85
86
  end
86
87
  end
88
+ deprecate_alias :saved_search_destroy, :destroy_saved_search
87
89
 
88
90
  end
89
91
  end
@@ -26,8 +26,8 @@ module Twitter
26
26
  # @param options [Hash] A customizable set of options.
27
27
  def suggestions(*args)
28
28
  arguments = Twitter::Arguments.new(args)
29
- if slug = arguments.pop
30
- object_from_response(Twitter::Suggestion, :get, "/1.1/users/suggestions/#{slug}.json", arguments.options)
29
+ if arguments.last
30
+ object_from_response(Twitter::Suggestion, :get, "/1.1/users/suggestions/#{arguments.pop}.json", arguments.options)
31
31
  else
32
32
  objects_from_response(Twitter::Suggestion, :get, "/1.1/users/suggestions.json", arguments.options)
33
33
  end
@@ -43,11 +43,7 @@ module Twitter
43
43
  def retweeters_of(tweet, options={})
44
44
  ids_only = !!options.delete(:ids_only)
45
45
  retweeters = retweets(tweet, options).map(&:user)
46
- if ids_only
47
- retweeters.map(&:id)
48
- else
49
- retweeters
50
- end
46
+ ids_only ? retweeters.map(&:id) : retweeters
51
47
  end
52
48
 
53
49
  # Returns a Tweet
@@ -91,16 +87,18 @@ module Twitter
91
87
  # @authentication Requires user context
92
88
  # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
93
89
  # @return [Array<Twitter::Tweet>] The deleted Tweets.
94
- # @overload status_destroy(*tweets)
90
+ # @overload destroy_status(*tweets)
95
91
  # @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
96
- # @overload status_destroy(*tweets, options)
92
+ # @overload destroy_status(*tweets, options)
97
93
  # @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
98
94
  # @param options [Hash] A customizable set of options.
99
95
  # @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
100
- def status_destroy(*args)
96
+ def destroy_status(*args)
101
97
  threaded_tweets_from_response(:post, "/1.1/statuses/destroy", args)
102
98
  end
103
- alias tweet_destroy status_destroy
99
+ alias destroy_tweet destroy_status
100
+ deprecate_alias :status_destroy, :destroy_status
101
+ deprecate_alias :tweet_destroy, :destroy_status
104
102
 
105
103
  # Updates the authenticating user's status
106
104
  #
@@ -31,11 +31,10 @@ module Twitter
31
31
  # @option options [String] :lang The language which Twitter should render in for this user. The language must be specified by the appropriate two letter ISO 639-1 representation. Currently supported languages are provided by {https://dev.twitter.com/docs/api/1.1/get/help/languages GET help/languages}.
32
32
  def settings(options={})
33
33
  request_method = options.size.zero? ? :get : :post
34
- settings = object_from_response(Twitter::Settings, request_method, "/1.1/account/settings.json", options)
34
+ response = send(request_method.to_sym, "/1.1/account/settings.json", options)
35
35
  # https://dev.twitter.com/issues/59
36
- trend_location = Array(settings.attrs[:trend_location]).first
37
- settings.update(:trend_location => trend_location)
38
- settings
36
+ response.update(:trend_location => Array(response[:trend_location]).first)
37
+ Twitter::Settings.from_response(response)
39
38
  end
40
39
 
41
40
  # Returns the requesting user if authentication was successful, otherwise raises {Twitter::Error::Unauthorized}
@@ -253,8 +252,8 @@ module Twitter
253
252
  # @option options [Boolean, String, Integer] :skip_status Do not include user's Tweets when set to true, 't' or 1.
254
253
  def user(*args)
255
254
  arguments = Twitter::Arguments.new(args)
256
- if user = arguments.pop
257
- merge_user!(arguments.options, user)
255
+ if arguments.last
256
+ merge_user!(arguments.options, arguments.pop)
258
257
  object_from_response(Twitter::User, :get, "/1.1/users/show.json", arguments.options)
259
258
  else
260
259
  verify_credentials(arguments.options)
@@ -338,6 +337,7 @@ module Twitter
338
337
  def remove_profile_banner(options={})
339
338
  post("/1.1/account/remove_profile_banner.json", options)[:body]
340
339
  end
340
+ deprecate_alias :profile_banner_remove, :remove_profile_banner
341
341
 
342
342
  # Updates the authenticating user's profile banner image
343
343
  #
@@ -7,10 +7,30 @@ module Twitter
7
7
  module REST
8
8
  module API
9
9
  module Utils
10
-
11
10
  DEFAULT_CURSOR = -1
12
11
  URI_SUBSTRING = "://"
13
12
 
13
+ class << self
14
+
15
+ def included(base)
16
+ base.extend(ClassMethods)
17
+ end
18
+
19
+ end
20
+
21
+ module ClassMethods
22
+
23
+ private
24
+
25
+ def deprecate_alias(new_name, old_name)
26
+ define_method(new_name) do |*args, &block|
27
+ warn "#{Kernel.caller.first}: [DEPRECATION] ##{new_name} it deprecated. Use ##{old_name} instead."
28
+ send(old_name, *args, &block)
29
+ end
30
+ end
31
+
32
+ end
33
+
14
34
  private
15
35
 
16
36
  # Take a URI string or Twitter::Identity object and return its ID
@@ -23,7 +43,7 @@ module Twitter
23
43
  object
24
44
  when ::String
25
45
  object.split("/").last.to_i
26
- when ::URI
46
+ when URI
27
47
  object.path.split("/").last.to_i
28
48
  when Twitter::Identity
29
49
  object.id
@@ -129,11 +149,8 @@ module Twitter
129
149
  end
130
150
 
131
151
  def handle_forbidden_error(klass, error)
132
- if error.message == klass::MESSAGE
133
- raise klass.new
134
- else
135
- raise error
136
- end
152
+ error = error.message == klass::MESSAGE ? klass.new : error
153
+ raise error
137
154
  end
138
155
 
139
156
  def merge_default_cursor!(options)
@@ -161,18 +178,23 @@ module Twitter
161
178
  def merge_user!(hash, user, prefix=nil)
162
179
  case user
163
180
  when Integer
164
- hash[[prefix, "user_id"].compact.join("_").to_sym] = user
181
+ set_compound_key("user_id", user, hash, prefix)
165
182
  when String
166
183
  if user[URI_SUBSTRING]
167
- hash[[prefix, "screen_name"].compact.join("_").to_sym] = user.split("/").last
184
+ set_compound_key("screen_name", user.split("/").last, hash, prefix)
168
185
  else
169
- hash[[prefix, "screen_name"].compact.join("_").to_sym] = user
186
+ set_compound_key("screen_name", user, hash, prefix)
170
187
  end
171
- when ::URI
172
- hash[[prefix, "screen_name"].compact.join("_").to_sym] = user.path.split("/").last
188
+ when URI
189
+ set_compound_key("screen_name", user.path.split("/").last, hash, prefix)
173
190
  when Twitter::User
174
- hash[[prefix, "user_id"].compact.join("_").to_sym] = user.id
191
+ set_compound_key("user_id", user.id, hash, prefix)
175
192
  end
193
+ end
194
+
195
+ def set_compound_key(key, value, hash, prefix=nil)
196
+ compound_key = [prefix, key].compact.join("_").to_sym
197
+ hash[compound_key] = value
176
198
  hash
177
199
  end
178
200
 
@@ -191,6 +213,13 @@ module Twitter
191
213
  # @param users [Enumerable<Integer, String, URI, Twitter::User>] A collection of Twitter user IDs, screen_names, URIs, or objects.
192
214
  # @return [Hash]
193
215
  def merge_users!(hash, users)
216
+ user_ids, screen_names = collect_user_ids_and_screen_names(users)
217
+ hash[:user_id] = user_ids.join(',') unless user_ids.empty?
218
+ hash[:screen_name] = screen_names.join(',') unless screen_names.empty?
219
+ hash
220
+ end
221
+
222
+ def collect_user_ids_and_screen_names(users)
194
223
  user_ids, screen_names = [], []
195
224
  users.flatten.each do |user|
196
225
  case user
@@ -202,15 +231,13 @@ module Twitter
202
231
  else
203
232
  screen_names << user
204
233
  end
205
- when ::URI
234
+ when URI
206
235
  screen_names << user.path.split("/").last
207
236
  when Twitter::User
208
237
  user_ids << user.id
209
238
  end
210
239
  end
211
- hash[:user_id] = user_ids.join(',') unless user_ids.empty?
212
- hash[:screen_name] = screen_names.join(',') unless screen_names.empty?
213
- hash
240
+ [user_ids, screen_names]
214
241
  end
215
242
 
216
243
  end
@@ -48,22 +48,12 @@ module Twitter
48
48
  include Twitter::REST::API::Tweets
49
49
  include Twitter::REST::API::Undocumented
50
50
  include Twitter::REST::API::Users
51
-
52
- attr_writer :bearer_token, :connection_options, :middleware
53
-
51
+ attr_accessor :bearer_token
52
+ attr_writer :connection_options, :middleware
54
53
  ENDPOINT = 'https://api.twitter.com'
55
54
 
56
- # @return [String]
57
- def bearer_token
58
- if instance_variable_defined?(:@bearer_token)
59
- @bearer_token
60
- else
61
- ENV['TWITTER_BEARER_TOKEN']
62
- end
63
- end
64
-
65
55
  def connection_options
66
- {
56
+ @connection_options ||= {
67
57
  :builder => middleware,
68
58
  :headers => {
69
59
  :accept => 'application/json',
@@ -130,39 +120,36 @@ module Twitter
130
120
 
131
121
  private
132
122
 
133
- # Returns a proc that can be used to setup the Faraday::Request headers
123
+ # Returns a Faraday::Connection object
134
124
  #
135
- # @param method [Symbol]
136
- # @param path [String]
137
- # @param params [Hash]
138
- # @return [Proc]
139
- def request_setup(method, path, params, signature_params)
140
- Proc.new do |request|
141
- if params.delete(:bearer_token_request)
125
+ # @return [Faraday::Connection]
126
+ def connection
127
+ @connection ||= Faraday.new(ENDPOINT, connection_options)
128
+ end
129
+
130
+ def request(method, path, params={}, signature_params=params)
131
+ 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.
142
135
  request.headers[:authorization] = bearer_token_credentials_auth_header
143
136
  request.headers[:content_type] = 'application/x-www-form-urlencoded; charset=UTF-8'
144
- request.headers[:accept] = '*/*' # It is important we set this, otherwise we get an error.
145
- elsif params.delete(:app_auth) || !user_token?
146
- @bearer_token = token unless bearer_token?
147
- request.headers[:authorization] = bearer_auth_header
148
137
  else
149
- request.headers[:authorization] = oauth_auth_header(method, ENDPOINT + path, signature_params).to_s
138
+ request.headers[:authorization] = auth_token(method, path, params, signature_params)
150
139
  end
151
140
  end
152
- end
153
-
154
- def request(method, path, params={}, signature_params=params)
155
- request_setup = request_setup(method, path, params, signature_params)
156
- connection.send(method.to_sym, path, params, &request_setup).env
141
+ response.env
157
142
  rescue Faraday::Error::ClientError, JSON::ParserError
158
143
  raise Twitter::Error
159
144
  end
160
145
 
161
- # Returns a Faraday::Connection object
162
- #
163
- # @return [Faraday::Connection]
164
- def connection
165
- @connection ||= Faraday.new(ENDPOINT, connection_options)
146
+ def auth_token(method, path, params={}, signature_params=params)
147
+ if !user_token?
148
+ @bearer_token = token unless bearer_token?
149
+ bearer_auth_header
150
+ else
151
+ oauth_auth_header(method, ENDPOINT + path, signature_params).to_s
152
+ end
166
153
  end
167
154
 
168
155
  # Generates authentication header for a bearer token request
@@ -174,15 +161,10 @@ module Twitter
174
161
  end
175
162
 
176
163
  def bearer_auth_header
177
- if bearer_token.is_a?(Twitter::Token) && bearer_token.bearer?
178
- "Bearer #{bearer_token.access_token}"
179
- else
180
- "Bearer #{bearer_token}"
181
- end
164
+ token = bearer_token.is_a?(Twitter::Token) && bearer_token.bearer? ? bearer_token.access_token : bearer_token
165
+ "Bearer #{token}"
182
166
  end
183
167
 
184
- private
185
-
186
168
  # Base64.strict_encode64 is not available on Ruby 1.8.7
187
169
  def strict_encode64(str)
188
170
  Base64.encode64(str).gsub("\n", "")
@@ -0,0 +1,15 @@
1
+ require 'twitter/rest/response/parse_json'
2
+
3
+ module Twitter
4
+ module REST
5
+ module Response
6
+ class ParseErrorJson < Twitter::REST::Response::ParseJson
7
+
8
+ def unparsable_status_codes
9
+ super + [200]
10
+ end
11
+
12
+ end
13
+ end
14
+ end
15
+ end
@@ -17,10 +17,14 @@ module Twitter
17
17
 
18
18
  def on_complete(env)
19
19
  if respond_to?(:parse)
20
- env[:body] = parse(env[:body]) unless [204, 301, 302, 304].include?(env[:status])
20
+ env[:body] = parse(env[:body]) unless unparsable_status_codes.include?(env[:status])
21
21
  end
22
22
  end
23
23
 
24
+ def unparsable_status_codes
25
+ [204, 301, 302, 304]
26
+ end
27
+
24
28
  end
25
29
  end
26
30
  end
@@ -8,12 +8,16 @@ module Twitter
8
8
  alias to_hash attrs
9
9
  alias to_hsh attrs
10
10
 
11
- # Construct a new SearchResults object from a response hash
12
- #
13
- # @param response [Hash]
14
- # @return [Twitter::Base]
15
- def self.from_response(response={})
16
- new(response[:body])
11
+ class << self
12
+
13
+ # Construct a new SearchResults object from a response hash
14
+ #
15
+ # @param response [Hash]
16
+ # @return [Twitter::Base]
17
+ def from_response(response={})
18
+ new(response[:body])
19
+ end
20
+
17
21
  end
18
22
 
19
23
  # Initializes a new SearchResults object
@@ -23,7 +27,7 @@ module Twitter
23
27
  def initialize(attrs={})
24
28
  @attrs = attrs
25
29
  @collection = Array(@attrs[:statuses]).map do |tweet|
26
- Twitter::Tweet.new(tweet)
30
+ Tweet.new(tweet)
27
31
  end
28
32
  end
29
33
 
@@ -61,7 +65,7 @@ module Twitter
61
65
 
62
66
  # @return [Boolean]
63
67
  def next_results?
64
- !@attrs[:search_metadata][:next_results].nil? if @attrs[:search_metadata]
68
+ !!(@attrs[:search_metadata] && @attrs[:search_metadata][:next_results])
65
69
  end
66
70
  alias next_page? next_results?
67
71