twitter 5.0.0.rc.1 → 5.0.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 (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