# The Twitter4R API provides a nicer Ruby object API to work with # instead of coding around the REST API. # Module to encapsule the Twitter4R API. module Twitter # Mixin module for classes that need to have a constructor similar to # Rails' models, where a Hash is provided to set attributes # appropriately. # # To define a class that uses this mixin, use the following code: # class FilmActor # include ClassUtilMixin # end module ClassUtilMixin #:nodoc: def self.included(base) #:nodoc: base.send(:include, InstanceMethods) end # Instance methods defined for Twitter::ModelMixin module. module InstanceMethods #:nodoc: # Constructor/initializer that takes a hash of parameters that # will initialize *members* or instance attributes to the # values given. For example, # # class FilmActor # include Twitter::ClassUtilMixin # attr_accessor :name # end # # class Production # include Twitter::ClassUtilMixin # attr_accessor :title, :year, :actors # end # # # Favorite actress... # jodhi = FilmActor.new(:name => "Jodhi May") # jodhi.name # => "Jodhi May" # # # Favorite actor... # robert = FilmActor.new(:name => "Robert Lindsay") # robert.name # => "Robert Lindsay" # # # Jane is also an excellent pick...gotta love her accent! # jane = FilmActor.new(name => "Jane Horrocks") # jane.name # => "Jane Horrocks" # # # Witty BBC series... # mrs_pritchard = Production.new(:title => "The Amazing Mrs. Pritchard", # :year => 2005, # :actors => [jodhi, jane]) # mrs_pritchard.title # => "The Amazing Mrs. Pritchard" # mrs_pritchard.year # => 2005 # mrs_pritchard.actors # => [#, # ] # # Any Ros Pritchard's out there to save us from the Tony Blair # # and Gordon Brown *New Labour* debacle? You've got my vote! # # jericho = Production.new(:title => "Jericho", # :year => 2005, # :actors => [robert]) # jericho.title # => "Jericho" # jericho.year # => 2005 # jericho.actors # => [#] # # Assuming class FilmActor includes # Twitter::ClassUtilMixin in the class definition # and has an attribute of name, then that instance # attribute will be set to "Jodhi May" for the actress # object during object initialization (aka construction for # you Java heads). def initialize(params = {}) params.each do |key,val| self.send("#{key}=", val) if self.respond_to? key end self.send(:init) if self.respond_to? :init end protected # Helper method to provide an easy and terse way to require # a block is provided to a method. def require_block(block_given) raise ArgumentError, "Must provide a block" unless block_given end end end # ClassUtilMixin # Exception API base class raised when there is an error encountered upon # querying or posting to the remote Twitter REST API. # # To consume and query any RESTError raised by Twitter4R: # begin # # Do something with your instance of Twitter::Client. # # Maybe something like: # timeline = twitter.timeline_for(:public) # rescue RESTError => re # puts re.code, re.message, re.uri # end # Which on the code raising a RESTError will output something like: # 404 # Resource Not Found # /i_am_crap.json class RESTError < RuntimeError class << self @@REGISTRY = {} def registry @@REGISTRY end def register(status_code) @@REGISTRY[status_code] = self end end include ClassUtilMixin @@ATTRIBUTES = [:code, :message, :uri, :error] attr_accessor :code, :message, :uri, :error # Returns string in following format: # "HTTP #{@code}: #{@message} at #{@uri}" # For example, # "HTTP 404: Resource Not Found at /i_am_crap.json # >This is the error message sent back by the Twitter.com API" def to_s "HTTP #{@code}: #{@message} at #{@uri}" end end # RESTError # Runtime error leaf class raised when Twitter.com API has no new results # to return from the last query. HTTP code: 304 (aka Not Modified). # # To handle specifically you would do the following: # begin # timeline = twitter.timeline_for(:friends, :since => tweet) # rescue NotModifiedError => nme # timeline = [] # end class NotModifiedError < RESTError; register('304'); end # Runtime error leaf class raised when client has reached rate limits. # HTTP code: 400 (aka Bad Request). # # To handle specifically you would do the following: # begin # timeline = twitter.timeline_for(:friends, :since => tweet) # rescue RateLimitError => rlre # # do something here... # end class RateLimitError < RESTError; register('400'); end # Runtime error leaf class raised when user and/or client credentials # are missing or invalid. # HTTP code: 401 (aka Unauthorized). # # To handle specifically you would do the following: # begin # timeline = twitter.timeline_for(:friends, :since => tweet) # rescue UnauthorizedError => uae # # do something to prompt for valid credentials to user here. # end class UnauthorizedError < RESTError; register('401'); end # Runtime error leaf class raised when update limit reached. # HTTP code: 403 (aka Forbidden). # # To handle specifically you would do the following: # begin # timeline = twitter.timeline_for(:friends, :since => tweet) # rescue ForbiddenError => fe # # do something to notify user that update limit has been reached # end class ForbiddenError < RESTError; register('403'); end # Runtime error leaf class raised when a resource requested was not found. # HTTP code: 404 (aka Not Found). # # To handle specifically you would do the following: # begin # timeline = twitter.timeline_for(:friends, :since => tweet) # rescue NotFoundError => nfe # # do something to notify user that resource was not found. # end class NotFoundError < RESTError; register('404'); end # Runtime error leaf class raised when the format specified in the request # is not understood by the Twitter.com API. # HTTP code: 406 (aka Not Acceptable). # # To handle specifically you would do the following: # begin # timeline = twitter.timeline_for(:friends, :since => tweet) # rescue NotAcceptableError => nae # # # end class NotAcceptableError < RESTError; register('406'); end # Runtime error leaf class raised when search rate limit reached. # HTTP code: 420. # # To handle specifically you would do the following: # begin # timeline = twitter.timeline_for(:friends, :since => tweet) # rescue SearchRateLimitError => nme # # # end class SearchRateLimitError < RESTError; register('420'); end # Runtime error leaf class raised when Twitter.com API is borked for # an unknown reason. # HTTP code: 500 (aka Internal Server Error). # # To handle specifically you would do the following: # begin # timeline = twitter.timeline_for(:friends, :since => tweet) # rescue InternalServerError => ise # # do something to notify user that an unknown internal server error # # has arisen. # end class InternalServerError < RESTError; register('500'); end # Runtime error leaf class raised when Twitter.com servers are being # upgraded. # HTTP code: 502 (aka Bad Gateway). # # To handle specifically you would do the following: # begin # timeline = twitter.timeline_for(:friends, :since => tweet) # rescue BadGatewayError => bge # # # end class BadGatewayError < RESTError; register('502'); end # Runtime error leaf class raised when Twitter.com servers are unable # to respond to the current load. # HTTP code: 502 (aka Service Unavailable). # # To handle specifically you would do the following: # begin # timeline = twitter.timeline_for(:friends, :since => tweet) # rescue ServiceUnavailableError => sue # # # end class ServiceUnavailableError < RESTError; register('503'); end end