Permalink
Browse files

Add Twitter::RateLimit class

Progress toward #268.
  • Loading branch information...
1 parent 2b37b6a commit 4c63a7378305df791b6fbcd3d3beb83ccd360f95 @sferik committed Jun 23, 2012
Showing with 598 additions and 481 deletions.
  1. +16 −10 README.md
  2. +1 −1 lib/twitter/action/favorite.rb
  3. +2 −2 lib/twitter/action/follow.rb
  4. +3 −3 lib/twitter/action/list_member_added.rb
  5. +3 −3 lib/twitter/action/mention.rb
  6. +2 −2 lib/twitter/action/reply.rb
  7. +2 −2 lib/twitter/action/retweet.rb
  8. +1 −1 lib/twitter/action/status.rb
  9. +3 −4 lib/twitter/action_factory.rb
  10. +23 −7 lib/twitter/base.rb
  11. +265 −220 lib/twitter/client.rb
  12. +3 −2 lib/twitter/configurable.rb
  13. +1 −1 lib/twitter/configuration.rb
  14. +36 −7 lib/twitter/cursor.rb
  15. +2 −2 lib/twitter/direct_message.rb
  16. +12 −31 lib/twitter/error.rb
  17. +3 −3 lib/twitter/error/server_error.rb
  18. +3 −4 lib/twitter/geo_factory.rb
  19. +6 −7 lib/twitter/identifiable.rb
  20. +1 −1 lib/twitter/list.rb
  21. +3 −4 lib/twitter/media_factory.rb
  22. +1 −1 lib/twitter/photo.rb
  23. +57 −0 lib/twitter/rate_limit.rb
  24. +13 −2 lib/twitter/relationship.rb
  25. +5 −8 lib/twitter/requestable.rb
  26. +1 −1 lib/twitter/response/parse_json.rb
  27. +3 −1 lib/twitter/search_results.rb
  28. +1 −1 lib/twitter/settings.rb
  29. +12 −13 lib/twitter/status.rb
  30. +1 −1 lib/twitter/suggestion.rb
  31. +1 −1 lib/twitter/user.rb
  32. +1 −1 spec/twitter/action_factory_spec.rb
  33. +1 −1 spec/twitter/base_spec.rb
  34. +2 −2 spec/twitter/client/activity_spec.rb
  35. +0 −45 spec/twitter/client/users_spec.rb
  36. +1 −1 spec/twitter/client_spec.rb
  37. +4 −4 spec/twitter/cursor_spec.rb
  38. +0 −66 spec/twitter/error_spec.rb
  39. +1 −1 spec/twitter/geo_factory_spec.rb
  40. +1 −1 spec/twitter/media_factory_spec.rb
  41. +2 −0 spec/twitter/polygon_spec.rb
  42. +74 −0 spec/twitter/rate_limit_spec.rb
  43. +2 −2 spec/twitter/relationship_spec.rb
  44. +22 −10 spec/twitter/status_spec.rb
  45. +1 −1 spec/twitter_spec.rb
View
@@ -38,9 +38,7 @@ wiki][apps]!
[apps]: https://github.com/jnunemaker/twitter/wiki/apps
## What's new in version 3?
-
### Methods
-
The following methods now accept multiple users or ids as arguments and return
arrays:
@@ -57,6 +55,8 @@ better performance than calling these methods multiple times in serial.
The `Twitter::Client#direct_messages` method has been renamed to
`Twitter::Client#direct_messages_received`.
+The `Twitter::Client#profile_image` method has been removed.
+
Additionally, the `Twitter::Client#follow` method now checks to make sure the
user isn't already being followed. If you don't wish to perform that check
(which does require an extra HTTP request), you can use the new
@@ -78,11 +78,7 @@ object.
The `Twitter::Status#expanded_urls` method has been removed. Use
`Twitter::Status#urls` instead.
-Support for API gateways via `gateway` configuration has been also removed.
-This functionality may be replicated by inserting custom Faraday middleware.
-
### Configuration
-
The Faraday middleware stack is now fully configurable and is exposed as a
`Faraday::Builder` which can be manipulated in place:
@@ -107,14 +103,16 @@ The adapter can also be configured as part of the middleware stack:
builder.adapter :some_other_adapter
})
+Support for API gateways via `gateway` configuration has removed. This
+functionality may be replicated by inserting custom Faraday middleware.
+
The `proxy` and `user_agent` configuration have also been removed. These can be
set via the `connection_options` configuration.
Twitter.connection_options[:proxy] = 'http://erik:sekret@proxy.example.com:8080'
Twitter.connection_options[:headers][:user_agent] = 'Custom User Agent'
### Authentication
-
This library now attempts to pull credentials from `ENV` if they are not
otherwise specified. In `bash`:
@@ -124,7 +122,6 @@ otherwise specified. In `bash`:
export TWITTER_OAUTH_TOKEN_SECRET=YOUR_OAUTH_TOKEN_SECRET
### Identity Map
-
This version introduces an identity map, which ensures that the same objects
only get initialized once:
@@ -134,7 +131,6 @@ only get initialized once:
false.)
### Errors
-
Any Faraday client errors are captured and re-raised as a
`Twitter::Error::ClientError`, so there's no longer a need to separately rescue
`Faraday::Error::ClientError`.
@@ -144,8 +140,18 @@ API requests are made via api.twitter.com, which does not return HTTP 420. When
you hit your rate limit, Twitter returns HTTP 400, which raises a
`Twitter::Error::BadRequest`.
-### Additional notes
+All `Twitter::Error.ratelimit` methods (including `Twitter::Error.retry_at`)
+have been replaced by the `Twitter::RateLimit` singleton class. After making
+any request, you can check the `Twitter::RateLimit` object for your current
+rate limit status.
+
+ rate_limit = Twitter::RateLimit.instance
+ rate_limit.limit #=> 150
+ rate_limit.remaining #=> 149
+ rate_limit.reset_at #=> 2012-06-23 20:04:36 -0700
+ rate_limit.reset_in #=> 3540 (seconds)
+### Additional notes
This will be the last major version of this library to support Ruby 1.8.
Requiring Ruby 1.9 will allow us to remove [various][each_with_object]
[hacks][singleton_class] put in place to maintain Ruby 1.8 compatibility.
@@ -10,7 +10,7 @@ class Favorite < Twitter::Action::Status
# @return [Array<Twitter::Status>]
def targets
@targets = Array(@attrs['targets']).map do |status|
- Twitter::Status.get_or_new(status)
+ Twitter::Status.fetch_or_new(status)
end
end
@@ -13,7 +13,7 @@ class Follow < Twitter::Base
# @return [Array<Twitter::User>]
def sources
@sources = Array(@attrs['sources']).map do |user|
- Twitter::User.get_or_new(user)
+ Twitter::User.fetch_or_new(user)
end
end
@@ -22,7 +22,7 @@ def sources
# @return [Array<Twitter::User>]
def targets
@targets = Array(@attrs['targets']).map do |user|
- Twitter::User.get_or_new(user)
+ Twitter::User.fetch_or_new(user)
end
end
@@ -14,7 +14,7 @@ class ListMemberAdded < Twitter::Base
# @return [Array<Twitter::User>]
def sources
@sources = Array(@attrs['sources']).map do |user|
- Twitter::User.get_or_new(user)
+ Twitter::User.fetch_or_new(user)
end
end
@@ -23,7 +23,7 @@ def sources
# @return [Array<Twitter::List>]
def target_objects
@target_objects = Array(@attrs['target_objects']).map do |list|
- Twitter::List.get_or_new(list)
+ Twitter::List.fetch_or_new(list)
end
end
@@ -32,7 +32,7 @@ def target_objects
# @return [Array<Twitter::User>]
def targets
@targets = Array(@attrs['targets']).map do |user|
- Twitter::User.get_or_new(user)
+ Twitter::User.fetch_or_new(user)
end
end
@@ -14,7 +14,7 @@ class Mention < Twitter::Base
# @return [Array<Twitter::User>]
def sources
@sources = Array(@attrs['sources']).map do |user|
- Twitter::User.get_or_new(user)
+ Twitter::User.fetch_or_new(user)
end
end
@@ -30,7 +30,7 @@ def source
# @return [Array<Twitter::Status>]
def target_objects
@target_objects = Array(@attrs['target_objects']).map do |status|
- Twitter::Status.get_or_new(status)
+ Twitter::Status.fetch_or_new(status)
end
end
@@ -39,7 +39,7 @@ def target_objects
# @return [Array<Twitter::User>]
def targets
@targets = Array(@attrs['targets']).map do |user|
- Twitter::User.get_or_new(user)
+ Twitter::User.fetch_or_new(user)
end
end
@@ -9,7 +9,7 @@ class Reply < Twitter::Action::Status
# @return [Array<Twitter::Status>]
def target_objects
@target_objects = Array(@attrs['target_objects']).map do |status|
- Twitter::Status.get_or_new(status)
+ Twitter::Status.fetch_or_new(status)
end
end
@@ -18,7 +18,7 @@ def target_objects
# @return [Array<Twitter::Status>]
def targets
@targets = Array(@attrs['targets']).map do |status|
- Twitter::Status.get_or_new(status)
+ Twitter::Status.fetch_or_new(status)
end
end
@@ -9,7 +9,7 @@ class Retweet < Twitter::Action::Status
# @return [Array<Twitter::Status>]
def target_objects
@target_objects = Array(@attrs['target_objects']).map do |status|
- Twitter::Status.get_or_new(status)
+ Twitter::Status.fetch_or_new(status)
end
end
@@ -18,7 +18,7 @@ def target_objects
# @return [Array<Twitter::User>]
def targets
@targets = Array(@attrs['targets']).map do |user|
- Twitter::User.get_or_new(user)
+ Twitter::User.fetch_or_new(user)
end
end
@@ -12,7 +12,7 @@ class Status < Twitter::Base
# @return [Array<Twitter::User>]
def sources
@sources = Array(@attrs['sources']).map do |user|
- Twitter::User.get_or_new(user)
+ Twitter::User.fetch_or_new(user)
end
end
@@ -15,10 +15,9 @@ class ActionFactory
# @param attrs [Hash]
# @raise [ArgumentError] Error raised when supplied argument is missing an 'action' key.
# @return [Twitter::Action::Favorite, Twitter::Action::Follow, Twitter::Action::ListMemberAdded, Twitter::Action::Mention, Twitter::Action::Reply, Twitter::Action::Retweet]
- def self.new(action={})
- type = action.delete('action')
- if type
- Twitter::Action.const_get(camelize(type).to_sym).get_or_new(action)
+ def self.new(attrs={})
+ if type = attrs.delete('action')
+ Twitter::Action.const_get(camelize(type).to_sym).fetch_or_new(attrs)
else
raise ArgumentError, "argument must have an 'action' key"
end
View
@@ -1,8 +1,10 @@
require 'twitter/identity_map'
+require 'twitter/rate_limit'
module Twitter
class Base
- attr_accessor :attrs
+ attr_reader :attrs
+ alias body attrs
alias to_hash attrs
@@identity_map = IdentityMap.new
@@ -23,21 +25,27 @@ def self.attr_reader(*attrs)
end
end
- def self.get(attrs={})
+ def self.fetch(attrs)
@@identity_map[self] ||= {}
@@identity_map[self][Marshal.dump(attrs)]
end
- def self.get_or_new(attrs={})
- self.get(attrs) || self.new(attrs)
+ def self.from_response(response={})
+ self.fetch(response[:body]) || self.new(response[:body], response[:response_headers])
+ end
+
+ def self.fetch_or_new(attrs={})
+ self.fetch(attrs) || self.new(attrs)
end
# Initializes a new object
#
# @param attrs [Hash]
+ # @param response_headers [Hash]
# @return [Twitter::Base]
- def initialize(attrs={})
+ def initialize(attrs={}, response_headers={})
self.update(attrs)
+ self.update_rate_limit(response_headers) unless response_headers.empty?
@@identity_map[self.class] ||= {}
@@identity_map[self.class][Marshal.dump(attrs)] = self
end
@@ -46,7 +54,7 @@ def initialize(attrs={})
#
# @param method [String, Symbol] Message to send to the object
def [](method)
- self.__send__(method.to_sym)
+ self.send(method.to_sym)
rescue NoMethodError
nil
end
@@ -57,9 +65,17 @@ def [](method)
# @return [Twitter::Base]
def update(attrs)
@attrs ||= {}
- @attrs.merge!(attrs)
+ @attrs.update(attrs)
self
end
+ # Update the RateLimit object
+ #
+ # @param response_headers [Hash]
+ # @return [Twitter::RateLimit]
+ def update_rate_limit(response_headers)
+ Twitter::RateLimit.instance.update(response_headers)
+ end
+
end
end
Oops, something went wrong.

0 comments on commit 4c63a73

Please sign in to comment.