diff --git a/lib/faraday/multipart.rb b/lib/faraday/multipart.rb index 89c8a0c7f..fe790a10e 100644 --- a/lib/faraday/multipart.rb +++ b/lib/faraday/multipart.rb @@ -1,3 +1,5 @@ +require 'faraday' + module Faraday class Request::Multipart < Faraday::Middleware def call(env) diff --git a/lib/faraday/oauth.rb b/lib/faraday/oauth.rb index 190f0cd5b..c452d554b 100644 --- a/lib/faraday/oauth.rb +++ b/lib/faraday/oauth.rb @@ -1,3 +1,6 @@ +require 'faraday' +require 'simple_oauth' + module Faraday class Request::OAuth < Faraday::Middleware def call(env) diff --git a/lib/faraday/raise_http_4xx.rb b/lib/faraday/raise_http_4xx.rb index a5054f386..689e9a4d8 100644 --- a/lib/faraday/raise_http_4xx.rb +++ b/lib/faraday/raise_http_4xx.rb @@ -1,3 +1,5 @@ +require 'faraday' + module Faraday class Response::RaiseHttp4xx < Response::Middleware def self.register_on_complete(env) diff --git a/lib/faraday/raise_http_5xx.rb b/lib/faraday/raise_http_5xx.rb index a4b89a473..28d123b09 100644 --- a/lib/faraday/raise_http_5xx.rb +++ b/lib/faraday/raise_http_5xx.rb @@ -1,3 +1,5 @@ +require 'faraday' + module Faraday class Response::RaiseHttp5xx < Response::Middleware def self.register_on_complete(env) diff --git a/lib/twitter.rb b/lib/twitter.rb index 3bab83591..b4e10ff1a 100644 --- a/lib/twitter.rb +++ b/lib/twitter.rb @@ -1,197 +1,20 @@ -require 'addressable/uri' -require 'faraday' -require 'faraday_middleware' -require 'faraday/multipart' -require 'faraday/oauth' -require 'faraday/raise_http_4xx' -require 'faraday/raise_http_5xx' -require 'forwardable' -require 'simple_oauth' require 'twitter/version' +require 'twitter/error' +require 'twitter/client' +require 'twitter/configuration' module Twitter - extend SingleForwardable - def_delegators :client, :public_timeline, :user, :profile_image, :suggestions, :retweeted_to_user, :retweeted_by_user, :status, :friend_ids, :follower_ids, :timeline, :lists_subscribed, :list_timeline, :retweets, :friends, :followers, :rate_limit_status, :tos, :privacy - - class << self - attr_accessor :consumer_key, :consumer_secret, :access_key, :access_secret - def client; Twitter::Unauthenticated.new end - - # config/initializers/twitter.rb (for instance) - # - # Twitter.configure do |config| - # config.consumer_key = 'ctoken' - # config.consumer_secret = 'csecret' - # config.access_key = 'atoken' - # config.access_secret = 'asecret' - # end - def configure - yield self - true - end + def self.client(options={}) + Twitter::Client.new(options) end - module ConfigHelper - def adapter - @adapter ||= default_adapter - end - - def adapter=(value) - @adapter = value - end - - def default_adapter - Faraday.default_adapter.freeze - end - - def api_endpoint - @api_endpoint ||= default_api_endpoint - end - - def api_endpoint=(value) - @api_endpoint = Addressable::URI.heuristic_parse(value).to_s - end - - def default_api_endpoint - Addressable::URI.heuristic_parse("api.twitter.com/#{api_version}").to_s.freeze - end - - def api_version - @api_version ||= default_api_version - end - - def api_version=(value) - @api_version = value - end - - def default_api_version - 1.freeze - end - - def format - @format ||= default_format - end - - def format=(value) - @format = value - end - - def default_format - 'json'.freeze - end - - def protocol - @protocol ||= default_protocol - end - - def protocol=(value) - @protocol = value - end - - def default_protocol - 'https'.freeze - end - - def user_agent - @user_agent ||= default_user_agent - end - - def user_agent=(value) - @user_agent = value - end - - def default_user_agent - "Twitter Ruby Gem/#{Twitter::VERSION}".freeze - end - end - - extend ConfigHelper - - module ConnectionHelper - def connection - base_connection do |builder| - builder.use Faraday::Response::RaiseHttp5xx - builder.use Faraday::Response::Parse - builder.use Faraday::Response::RaiseHttp4xx - builder.use Faraday::Response::Mashify - end - end - - def connection_with_unparsed_response - base_connection do |builder| - builder.use Faraday::Response::RaiseHttp5xx - builder.use Faraday::Response::RaiseHttp4xx - end - end - - def base_connection(&block) - headers = {:user_agent => self.class.user_agent} - ssl = {:verify => false} - oauth = {:consumer_key => @consumer_key, :consumer_secret => @consumer_secret, :token => @access_key, :token_secret => @access_secret} - Faraday::Connection.new(:url => self.class.api_endpoint, :headers => headers, :ssl => ssl) do |connection| - connection.scheme = self.class.protocol - connection.use Faraday::Request::Multipart - connection.use Faraday::Request::OAuth, oauth - connection.adapter(self.class.adapter) - yield connection if block_given? - end - end - end - - module RequestHelper - def perform_get(path, options={}) - connection.get do |request| - request.url(path, options) - end.body - end - - def perform_post(path, options={}) - connection.post do |request| - request.path = path - request.body = options - end.body - end - - def perform_put(path, options={}) - connection.put do |request| - request.path = path - request.body = options - end.body - end - - def perform_delete(path, options={}) - connection.delete do |request| - request.url(path, options) - end.body - end - end - - class BadRequest < StandardError; end - class Unauthorized < StandardError; end - class Forbidden < StandardError; end - class NotFound < StandardError; end - class NotAcceptable < StandardError; end - class InternalServerError < StandardError; end - class BadGateway < StandardError; end - class ServiceUnavailable < StandardError; end - - class EnhanceYourCalm < StandardError - def initialize(message, http_headers) - @http_headers = Hash[http_headers] - super message - end - - # Returns number of seconds the application should wait before requesting data from the Search API again. - def retry_after - retry_after = @http_headers["retry-after"] || @http_headers["Retry-After"] - retry_after.to_i + def self.method_missing(method, *args, &block) + begin + client.__send__(method, *args, &block) + rescue NoMethodError + super end end + extend Configuration end - -require 'twitter/authenticated' -require 'twitter/geo' -require 'twitter/search' -require 'twitter/trends' -require 'twitter/unauthenticated' diff --git a/lib/twitter/authenticated.rb b/lib/twitter/authenticated.rb deleted file mode 100644 index cbc212d36..000000000 --- a/lib/twitter/authenticated.rb +++ /dev/null @@ -1,483 +0,0 @@ -module Twitter - class Authenticated - extend ConfigHelper - include ConnectionHelper - include RequestHelper - attr_reader :access_key, :access_secret, :consumer_key, :consumer_secret - - def initialize(options={}) - @consumer_key = options[:consumer_key] || Twitter.consumer_key - @consumer_secret = options[:consumer_secret] || Twitter.consumer_secret - @access_key = options[:access_key] || Twitter.access_key - @access_secret = options[:access_secret] || Twitter.access_secret - @adapter = options[:adapter] || Twitter.adapter - @api_endpoint = options[:api_endpoint] || Twitter.api_endpoint - @api_version = options[:api_version] || Twitter.api_version - @format = options[:format] || Twitter.format - @protocol = options[:protocol] || Twitter.protocol - @user_agent = options[:user_agent] || Twitter.user_agent - end - - def public_timeline(options={}) - perform_get("statuses/public_timeline.#{self.class.format}", options) - end - - # Options: since_id, max_id, count, page - def home_timeline(options={}) - perform_get("statuses/home_timeline.#{self.class.format}", options) - end - - # Options: since_id, max_id, count, page, since - def friends_timeline(options={}) - perform_get("statuses/friends_timeline.#{self.class.format}", options) - end - - # Options: id, user_id, screen_name, since_id, max_id, page, since, count - def user_timeline(options={}) - perform_get("statuses/user_timeline.#{self.class.format}", options) - end - - def retweeted_to_user(user_id_or_screen_name, options={}) - case user_id_or_screen_name - when Fixnum - options.merge!({:user_id => user_id_or_screen_name}) - when String - options.merge!({:screen_name => user_id_or_screen_name}) - end - perform_get("statuses/retweeted_to_user.#{self.class.format}", options) - end - - def retweeted_by_user(user_id_or_screen_name, options={}) - case user_id_or_screen_name - when Fixnum - options.merge!({:user_id => user_id_or_screen_name}) - when String - options.merge!({:screen_name => user_id_or_screen_name}) - end - perform_get("statuses/retweeted_by_user.#{self.class.format}", options) - end - - def status(id, options={}) - perform_get("statuses/show/#{id}.#{self.class.format}", options) - end - - # Options: in_reply_to_status_id - def update(status, options={}) - perform_post("statuses/update.#{self.class.format}", {:status => status}.merge(options)) - end - - # Options: trim_user, include_entities - def status_destroy(id, options={}) - perform_delete("statuses/destroy/#{id}.#{self.class.format}", options) - end - - # Options: trim_user, include_entities - def retweet(id, options={}) - perform_post("statuses/retweet/#{id}.#{self.class.format}", options) - end - - # Options: count - def retweets(id, options={}) - perform_get("statuses/retweets/#{id}.#{self.class.format}", options) - end - - # Options: since_id, max_id, count, page - def mentions(options={}) - perform_get("statuses/mentions.#{self.class.format}", options) - end - - # Options: since_id, max_id, count, page - def retweeted_by_me(options={}) - perform_get("statuses/retweeted_by_me.#{self.class.format}", options) - end - - # Options: since_id, max_id, count, page - def retweeted_to_me(options={}) - perform_get("statuses/retweeted_to_me.#{self.class.format}", options) - end - - # Options: since_id, max_id, count, page - def retweets_of_me(options={}) - perform_get("statuses/retweets_of_me.#{self.class.format}", options) - end - - # options: count, page, ids_only - def retweeters_of(id, options={}) - ids_only = !!(options.delete(:ids_only)) - perform_get("statuses/#{id}/retweeted_by#{"/ids" if ids_only}.#{self.class.format}", options) - end - - # Options: id, user_id, screen_name, page - def friends(options={}) - perform_get("statuses/friends.#{self.class.format}", options) - end - - # Options: id, user_id, screen_name, page - def followers(options={}) - perform_get("statuses/followers.#{self.class.format}", options) - end - - def user(user_id_or_screen_name, options={}) - case user_id_or_screen_name - when Fixnum - options.merge!({:user_id => user_id_or_screen_name}) - when String - options.merge!({:screen_name => user_id_or_screen_name}) - end - perform_get("users/show.#{self.class.format}", options) - end - - def profile_image(screen_name, options={}) - connection_with_unparsed_response.get do |request| - request.url("users/profile_image/#{screen_name}.#{self.class.format}", options) - end.headers["location"] - end - - def users(user_ids_or_screen_names, options={}) - merge_users_into_options!(Array(user_ids_or_screen_names), options) - perform_get("users/lookup.#{self.class.format}", options) - end - - # Options: page, per_page - def user_search(query, options={}) - perform_get("users/search.#{self.class.format}", {:q => query}.merge(options)) - end - - def direct_message(id, options={}) - perform_get("direct_messages/show/#{id}.#{self.class.format}", options) - end - - # Options: since, since_id, page - def direct_messages(options={}) - perform_get("direct_messages.#{self.class.format}", options) - end - - # Options: since, since_id, page - def direct_messages_sent(options={}) - perform_get("direct_messages/sent.#{self.class.format}", options) - end - - def direct_message_create(user_id_or_screen_name, text, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - options[:text] = text - perform_post("direct_messages/new.#{self.class.format}", options) - end - - def direct_message_destroy(id, options={}) - perform_delete("direct_messages/destroy/#{id}.#{self.class.format}", options) - end - - def friendship(options={}) - perform_get("friendships/show.#{self.class.format}", options) - end - alias :friendship_show :friendship - - def friendships(user_ids_or_screen_names, options={}) - merge_users_into_options!(Array(user_ids_or_screen_names), options) - perform_get("friendships/lookup.#{self.class.format}", options) - end - - def friendship_create(user_id_or_screen_name, follow=false, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - options[:follow] = follow if follow - perform_post("friendships/create.#{self.class.format}", options) - end - - def friendship_update(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_post("friendships/update.#{self.class.format}", options) - end - - def friendship_destroy(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_delete("friendships/destroy.#{self.class.format}", options) - end - - def friendship_exists?(user_id_or_screen_name_a, user_id_or_screen_name_b) - response = perform_get("friendships/exists.#{self.class.format}", {:user_a => user_id_or_screen_name_a, :user_b => user_id_or_screen_name_b}) - case self.class.format.to_s - when 'xml' - !%w(0 false).include?(response.friends) - else - response - end - end - - # Options: id, user_id, screen_name - def friend_ids(options={}) - perform_get("friends/ids.#{self.class.format}", options) - end - - # Options: id, user_id, screen_name - def follower_ids(options={}) - perform_get("followers/ids.#{self.class.format}", options) - end - - def verify_credentials(options={}) - perform_get("account/verify_credentials.#{self.class.format}", options) - end - - # Device must be sms, im or none - def update_delivery_device(device, options={}) - options[:device] = device - perform_post("account/update_delivery_device.#{self.class.format}", options) - end - - # One or more of the following must be present: - # profile_background_color, profile_text_color, profile_link_color, - # profile_sidebar_fill_color, profile_sidebar_border_color - def update_profile_colors(options={}) - perform_post("account/update_profile_colors.#{self.class.format}", options) - end - - # file should respond to #read and #path - def update_profile_image(file) - perform_post("account/update_profile_image.#{self.class.format}", :image => file) - end - - # file should respond to #read and #path - def update_profile_background(file, tile = false) - perform_post("account/update_profile_background_image.#{self.class.format}", :image => file, :tile => tile) - end - - # One or more of the following must be present: - # name, email, url, location, description - def update_profile(options={}) - perform_post("account/update_profile.#{self.class.format}", options) - end - - def totals(options={}) - perform_get("account/totals.#{self.class.format}", options) - end - - def settings(options={}) - perform_get("account/settings.#{self.class.format}", options) - end - - # Options: id, page - def favorites(options={}) - perform_get("favorites.#{self.class.format}", options) - end - - def favorite_create(id, options={}) - perform_post("favorites/create/#{id}.#{self.class.format}", options) - end - - def favorite_destroy(id, options={}) - perform_delete("favorites/destroy/#{id}.#{self.class.format}", options) - end - - def enable_notifications(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_post("notifications/follow.#{self.class.format}", options) - end - - def disable_notifications(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_post("notifications/leave.#{self.class.format}", options) - end - - def block(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_post("blocks/create.#{self.class.format}", options) - end - - def unblock(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_delete("blocks/destroy.#{self.class.format}", options) - end - - def report_spam(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_post("report_spam.#{self.class.format}", options) - end - - def list_create(list_owner_screen_name, name, options={}) - options[:name] = name - perform_post("#{list_owner_screen_name}/lists.#{self.class.format}", options) - end - - def list_update(list_owner_screen_name, slug, options={}) - perform_put("#{list_owner_screen_name}/lists/#{slug}.#{self.class.format}", options) - end - - def list_delete(list_owner_screen_name, slug, options={}) - perform_delete("#{list_owner_screen_name}/lists/#{slug}.#{self.class.format}", options) - end - - def list(list_owner_screen_name, slug, options={}) - perform_get("#{list_owner_screen_name}/lists/#{slug}.#{self.class.format}", options) - end - - def lists_subscribed(options={}) - perform_get("lists/all.#{self.class.format}", options) - end - - def lists(list_owner_screen_name=nil, options={}) - path = case list_owner_screen_name - when nil - "lists.#{self.class.format}" - when Hash - options = list_owner_screen_name - "lists.#{self.class.format}" - else - "#{list_owner_screen_name}/lists.#{self.class.format}" - end - perform_get(path, options) - end - - def suggestions(category_slug=nil, options={}) - path = case category_slug - when nil - "users/suggestions.#{self.class.format}" - when Hash - options = category_slug - "users/suggestions.#{self.class.format}" - else - "users/suggestions/#{category_slug}.#{self.class.format}" - end - perform_get(path, options) - end - - # :per_page = max number of statues to get at once - # :page = which page of tweets you wish to get - def list_timeline(list_owner_screen_name, slug, options={}) - perform_get("#{list_owner_screen_name}/lists/#{slug}/statuses.#{self.class.format}", options) - end - - def memberships(list_owner_screen_name, options={}) - perform_get("#{list_owner_screen_name}/lists/memberships.#{self.class.format}", options) - end - - def subscriptions(list_owner_screen_name, options={}) - perform_get("#{list_owner_screen_name}/lists/subscriptions.#{self.class.format}", options) - end - - def list_members(list_owner_screen_name, slug, options={}) - perform_get("#{list_owner_screen_name}/#{slug}/members.#{self.class.format}", options) - end - - def list_add_member(list_owner_screen_name, slug, new_id, options={}) - options[:id] = new_id - perform_post("#{list_owner_screen_name}/#{slug}/members.#{self.class.format}", options) - end - - def list_remove_member(list_owner_screen_name, slug, id, options={}) - options[:id] = id - perform_delete("#{list_owner_screen_name}/#{slug}/members.#{self.class.format}", options) - end - - def is_list_member?(list_owner_screen_name, slug, id, options={}) - begin - perform_get("#{list_owner_screen_name}/#{slug}/members/#{id}.#{self.class.format}", options) - true - rescue Twitter::NotFound - false - end - end - - def list_subscribers(list_owner_screen_name, slug, options={}) - perform_get("#{list_owner_screen_name}/#{slug}/subscribers.#{self.class.format}", options) - end - - def list_subscribe(list_owner_screen_name, slug, options={}) - perform_post("#{list_owner_screen_name}/#{slug}/subscribers.#{self.class.format}", options) - end - - def list_unsubscribe(list_owner_screen_name, slug, options={}) - perform_delete("#{list_owner_screen_name}/#{slug}/subscribers.#{self.class.format}", options) - end - - def blocked_ids(options={}) - perform_get("blocks/blocking/ids.#{self.class.format}", options) - end - - def blocking(options={}) - perform_get("blocks/blocking.#{self.class.format}", options) - end - - def saved_searches(options={}) - perform_get("saved_searches.#{self.class.format}", options) - end - - def saved_search(id, options={}) - perform_get("saved_searches/show/#{id}.#{self.class.format}", options) - end - - def saved_search_create(query) - options = query.is_a?(Hash) ? query : {:query => query} - perform_post("saved_searches/create.#{self.class.format}", options) - end - - def saved_search_destroy(id, options={}) - perform_delete("saved_searches/destroy/#{id}.#{self.class.format}", options) - end - - def related_results(id, options={}) - perform_get("related_results/show/#{id}.#{self.class.format}", options) - end - - def rate_limit_status(options={}) - perform_get("account/rate_limit_status.#{self.class.format}", options) - end - - def friendships_outgoing(options={}) - perform_get("friendships/outgoing.#{self.class.format}", options) - end - - def friendships_incoming(options={}) - perform_get("friendships/incoming.#{self.class.format}", options) - end - - def list_add_members(list_owner_screen_name, slug, new_ids, options={}) - merge_users_into_options!(Array(new_ids), options) - perform_post("#{list_owner_screen_name}/#{slug}/create_all.#{self.class.format}", options) - end - - def is_subscriber?(list_owner_screen_name, slug, id, options={}) - begin - perform_get("#{list_owner_screen_name}/#{slug}/subscribers/#{id}.#{self.class.format}", options) - true - rescue Twitter::NotFound - false - end - end - - def block_exists?(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - begin - perform_get("blocks/exists.#{self.class.format}", options) - true - rescue Twitter::NotFound - false - end - end - - private - - def merge_user_into_options!(user_id_or_screen_name, options={}) - case user_id_or_screen_name - when Fixnum - options[:user_id] = user_id_or_screen_name - when String - options[:screen_name] = user_id_or_screen_name - end - options - end - - def merge_users_into_options!(user_ids_or_screen_names, options={}) - user_ids, screen_names = [], [] - user_ids_or_screen_names.flatten.each do |user_id_or_screen_name| - case user_id_or_screen_name - when Fixnum - user_ids << user_id_or_screen_name - when String - screen_names << user_id_or_screen_name - end - end - options[:user_id] = user_ids.join(",") unless user_ids.empty? - options[:screen_name] = screen_names.join(",") unless screen_names.empty? - end - - end -end diff --git a/lib/twitter/client.rb b/lib/twitter/client.rb new file mode 100644 index 000000000..c1d8716e2 --- /dev/null +++ b/lib/twitter/client.rb @@ -0,0 +1,48 @@ +Dir[File.expand_path('../client/*.rb', __FILE__)].each{|f| require f } + +module Twitter + class Client + attr_reader :access_key, :access_secret, :consumer_key, :consumer_secret + attr_reader :adapter, :endpoint, :format, :user_agent + + def initialize(options={}) + options = Twitter.options.merge(options) + + @access_key = options[:access_key] + @access_secret = options[:access_secret] + @consumer_key = options[:consumer_key] + @consumer_secret = options[:consumer_secret] + + @adapter = options[:adapter] + @endpoint = options[:endpoint] + @format = options[:format] + @user_agent = options[:user_agent] + end + + include Connection + include Request + include Authentication + include Utils + + include Timeline + include Tweets + include User + include Trends + include LocalTrends + include List + include ListMembers + include ListSubscribers + include DirectMessages + include Friendship + include FriendsAndFollowers + include Account + include Favorites + include Notification + include Block + include SpamReporting + include SavedSearches + include Geo + include Legal + include Help + end +end diff --git a/lib/twitter/client/account.rb b/lib/twitter/client/account.rb new file mode 100644 index 000000000..99e311c05 --- /dev/null +++ b/lib/twitter/client/account.rb @@ -0,0 +1,45 @@ +module Twitter + class Client + module Account + def verify_credentials(options={}) + authenticate! + get('account/verify_credentials', options) + end + + def rate_limit_status(options={}) + authenticate + get('account/rate_limit_status', options) + end + + def end_session(options={}) + authenticate! + post('account/end_session', options) + end + + def update_delivery_device(device, options={}) + authenticate! + post('account/update_delivery_device', options.merge(:device => device)) + end + + def update_profile_colors(options={}) + authenticate! + post('account/update_profile_colors', options) + end + + def update_profile_image(file, options={}) + authenticate! + post('account/update_profile_image', options.merge(:image => file)) + end + + def update_profile_background(file, options={}) + authenticate! + perform_post('account/update_profile_background_image', options.merge(:image => file)) + end + + def update_profile(options={}) + authenticate! + post('account/update_profile', options) + end + end + end +end diff --git a/lib/twitter/client/authentication.rb b/lib/twitter/client/authentication.rb new file mode 100644 index 000000000..bf9a45bb9 --- /dev/null +++ b/lib/twitter/client/authentication.rb @@ -0,0 +1,57 @@ +module Twitter + class Client + module Authentication + private + def authenticate!(&block) + raise Twitter::Unauthorized, 'Authentication is required.' unless authenticated? + authenticate(&block) + end + + def authenticate + @authenticate = authenticated? + if block_given? + begin + @persist_authenticate = true + yield + ensure + reset_authenticate + end + end + end + + def authenticated? + [consumer_key, consumer_secret, access_key, access_secret].all? + end + + def reset_authenticate + @authenticate = nil + @persist_authenticate = nil + end + + def authenticate? + !!@authenticate + end + + def persist_authenticate? + !!@persist_authenticate + end + + def authentication + { + :consumer_key => consumer_key, + :consumer_secret => consumer_secret, + :token => access_key, + :token_secret => access_secret + } + end + + def request(*args) + begin + super + ensure + reset_authenticate unless persist_authenticate? + end + end + end + end +end diff --git a/lib/twitter/client/block.rb b/lib/twitter/client/block.rb new file mode 100644 index 000000000..211c112ec --- /dev/null +++ b/lib/twitter/client/block.rb @@ -0,0 +1,38 @@ +module Twitter + class Client + module Block + def block(user, options={}) + authenticate! + merge_user_into_options!(user, options) + post('blocks/create', options) + end + + def unblock(user, options={}) + authenticate! + merge_user_into_options!(user, options) + delete('blocks/destroy', options) + end + + def block_exists?(user, options={}) + authenticate! + merge_user_into_options!(user, options) + begin + get('blocks/exists', options) + true + rescue Twitter::NotFound + false + end + end + + def blocking(options={}) + authenticate! + get('blocks/blocking', options) + end + + def blocked_ids(options={}) + authenticate! + get('blocks/blocking/ids', options) + end + end + end +end diff --git a/lib/twitter/client/connection.rb b/lib/twitter/client/connection.rb new file mode 100644 index 000000000..ae36317f8 --- /dev/null +++ b/lib/twitter/client/connection.rb @@ -0,0 +1,33 @@ +require 'faraday' +require 'faraday_middleware' + +require 'faraday/multipart' +require 'faraday/oauth' +require 'faraday/raise_http_4xx' +require 'faraday/raise_http_5xx' + +module Twitter + class Client + module Connection + private + + def connection(raw=false) + options = { + :headers => {:user_agent => user_agent}, + :ssl => {:verify => false}, + :url => endpoint + } + + Faraday::Connection.new(options) do |builder| + builder.use Faraday::Request::Multipart + builder.use Faraday::Request::OAuth, authentication if authenticate? + builder.adapter(adapter) + builder.use Faraday::Response::RaiseHttp5xx + builder.use Faraday::Response::Parse unless raw + builder.use Faraday::Response::RaiseHttp4xx + builder.use Faraday::Response::Mashify unless raw + end + end + end + end +end diff --git a/lib/twitter/client/direct_messages.rb b/lib/twitter/client/direct_messages.rb new file mode 100644 index 000000000..d540a24db --- /dev/null +++ b/lib/twitter/client/direct_messages.rb @@ -0,0 +1,25 @@ +module Twitter + class Client + module DirectMessages + def direct_messages(options={}) + authenticate! + get('direct_messages', options) + end + + def direct_messages_sent(options={}) + authenticate! + get('direct_messages/sent', options) + end + + def direct_message_create(user, text, options={}) + authenticate! + merge_user_into_options!(user, options) + post('direct_messages/new', options.merge(:text => text)) + end + + def direct_message_destroy(id, options={}) + delete("direct_messages/destroy/#{id}", options) + end + end + end +end diff --git a/lib/twitter/client/favorites.rb b/lib/twitter/client/favorites.rb new file mode 100644 index 000000000..14f6c9998 --- /dev/null +++ b/lib/twitter/client/favorites.rb @@ -0,0 +1,22 @@ +module Twitter + class Client + module Favorites + def favorites(*args) + authenticate! + options = args.last.is_a?(Hash) ? args.pop : {} + user = args.first + get(['favorites', user].compact.join('/'), options) + end + + def favorite_create(id, options={}) + authenticate! + post("favorites/create/#{id}", options) + end + + def favorite_destroy(id, options={}) + authenticate! + delete("favorites/destroy/#{id}", options) + end + end + end +end diff --git a/lib/twitter/client/freinds_and_followers.rb b/lib/twitter/client/freinds_and_followers.rb new file mode 100644 index 000000000..bdaa63811 --- /dev/null +++ b/lib/twitter/client/freinds_and_followers.rb @@ -0,0 +1,15 @@ +module Twitter + class Client + module FriendsAndFollowers + def friend_ids(user, options={}) + merge_user_into_options!(user, options) + get('friends/ids', options) + end + + def follower_ids(user, options={}) + merge_user_into_options!(user, options) + get('followers/ids', options) + end + end + end +end diff --git a/lib/twitter/client/friendship.rb b/lib/twitter/client/friendship.rb new file mode 100644 index 000000000..5ca7cc8d8 --- /dev/null +++ b/lib/twitter/client/friendship.rb @@ -0,0 +1,41 @@ +module Twitter + class Client + module Friendship + def friendship_create(user, *args) + authenticate! + merge_user_into_options!(user, options) + options = args.last.is_a?(Hash) ? args.pop : {} + follow = args.first || false + post('friendships/create', options.merge(:follow => follow)) + end + + def friendship_destroy(user, options={}) + authenticate! + merge_user_into_options!(user, options) + delete('friendships/destroy', options) + end + + def friendship_exists?(user_a, user_b, options={}) + authenticate + response = get('friendships/exists', options.merge(:user_a => user_a, :user_b => user_b)) + format == :xml ? !%w(0 false).include?(response.friends) : response + end + + def friendship(options={}) + get('friendships/show', options) + end + + alias :friendship_show :friendship + + def friendships_incoming(options={}) + authenticate! + get('friendships/incoming', options) + end + + def friendships_outgoing(options={}) + authenticate! + get('friendships/outgoing', options) + end + end + end +end diff --git a/lib/twitter/client/geo.rb b/lib/twitter/client/geo.rb new file mode 100644 index 000000000..33e23a009 --- /dev/null +++ b/lib/twitter/client/geo.rb @@ -0,0 +1,26 @@ +module Twitter + class Client + module Geo + def geo_search(options={}) + get('geo/search', options) + end + + def similar_places(options={}) + get('geo/similar_places', options) + end + + def reverse_geocode(options={}) + get('geo/reverse_geocode', options) + end + + def place(id, options={}) + get("geo/id/#{id}", options) + end + + def create_place(options={}) + authenticate! + post('geo/place', options) + end + end + end +end diff --git a/lib/twitter/client/help.rb b/lib/twitter/client/help.rb new file mode 100644 index 000000000..620a36ef4 --- /dev/null +++ b/lib/twitter/client/help.rb @@ -0,0 +1,9 @@ +module Twitter + class Client + module Help + def test(options={}) + get('help/test', options) + end + end + end +end diff --git a/lib/twitter/client/legal.rb b/lib/twitter/client/legal.rb new file mode 100644 index 000000000..8c5cc47c1 --- /dev/null +++ b/lib/twitter/client/legal.rb @@ -0,0 +1,13 @@ +module Twitter + class Client + module Legal + def tos(options={}) + get('legal/tos', options) + end + + def privacy(options={}) + get('legal/privacy', options) + end + end + end +end diff --git a/lib/twitter/client/list.rb b/lib/twitter/client/list.rb new file mode 100644 index 000000000..16c7d195f --- /dev/null +++ b/lib/twitter/client/list.rb @@ -0,0 +1,49 @@ +module Twitter + class Client + module List + def list_create(screen_name, name, options={}) + post("#{screen_name}/lists", options.merge(:name => name)) + end + + def list_update(screen_name, name, options={}) + put("#{screen_name}/lists/#{name}", options) + end + + def lists(*args) + options = args.last.is_a?(Hash) ? args.pop : {} + screen_name = args.first + if screen_name + get("#{screen_name}/lists", options) + else + authenticate! do + get('lists', options) + end + end + end + + def list(screen_name, name, options={}) + get("#{screen_name}/lists/#{name}", options) + end + + def list_delete(screen_name, name, options={}) + delete("#{screen_name}/lists/#{name}", options) + end + + def list_timeline(screen_name, name, options={}) + get("#{screen_name}/lists/#{name}/statuses", options) + end + + def memberships(screen_name, options={}) + authenticate! do + get("#{screen_name}/lists/memberships", options) + end + end + + def subscriptions(screen_name, options={}) + authenticate! do + get("#{screen_name}/lists/subscriptions", options) + end + end + end + end +end diff --git a/lib/twitter/client/list_members.rb b/lib/twitter/client/list_members.rb new file mode 100644 index 000000000..99a793b68 --- /dev/null +++ b/lib/twitter/client/list_members.rb @@ -0,0 +1,31 @@ +module Twitter + class Client + module ListMembers + def list_members(screen_name, slug, options={}) + get("#{screen_name}/#{slug}/members", options) + end + + def list_add_member(screen_name, slug, user_id, options={}) + post("#{screen_name}/#{slug}/members", options.merge(:id => user_id)) + end + + def list_add_members(screen_name, slug, users, options={}) + merge_users_into_options!(Array(users), options) + post("#{screen_name}/#{slug}/create_all", options) + end + + def list_remove_member(screen_name, slug, user_id, options={}) + delete("#{screen_name}/#{slug}/members", options.merge(:id => user_id)) + end + + def is_list_member?(screen_name, slug, user_id, options={}) + begin + get("#{screen_name}/#{slug}/members/#{user_id}", options) + true + rescue Twitter::NotFound + false + end + end + end + end +end diff --git a/lib/twitter/client/list_subscribers.rb b/lib/twitter/client/list_subscribers.rb new file mode 100644 index 000000000..45080be4a --- /dev/null +++ b/lib/twitter/client/list_subscribers.rb @@ -0,0 +1,30 @@ +module Twitter + class Client + module ListSubscribers + def list_subscribers(screen_name, slug, options={}) + get("#{screen_name}/#{slug}/subscribers", options) + end + + def list_subscribe(screen_name, slug, options={}) + authenticate! do + post("#{screen_name}/#{slug}/subscribers", options) + end + end + + def list_unsubscribe(screen_name, slug, options={}) + authenticate! do + delete("#{screen_name}/#{slug}/subscribers", options) + end + end + + def is_subscriber?(screen_name, slug, user_id, options={}) + begin + get("#{screen_name}/#{slug}/subscribers/#{user_id}", options) + true + rescue Twitter::NotFound + false + end + end + end + end +end diff --git a/lib/twitter/client/local_trends.rb b/lib/twitter/client/local_trends.rb new file mode 100644 index 000000000..35ee4cfca --- /dev/null +++ b/lib/twitter/client/local_trends.rb @@ -0,0 +1,13 @@ +module Twitter + class Client + module LocalTrends + def trend_locations(options={}) + get('trends/available', options) + end + + def local_trends(woeid=1, options={}) + get("trends/#{woeid}", options) + end + end + end +end diff --git a/lib/twitter/client/notification.rb b/lib/twitter/client/notification.rb new file mode 100644 index 000000000..dcd062d1b --- /dev/null +++ b/lib/twitter/client/notification.rb @@ -0,0 +1,17 @@ +module Twitter + class Client + module Notification + def enable_notifications(user, options={}) + authenticate! + merge_user_into_options!(user, options) + post('notifications/follow', options) + end + + def disable_notifications(user, options={}) + authenticate! + merge_user_into_options!(user, options) + post('notifications/leave', options) + end + end + end +end diff --git a/lib/twitter/client/request.rb b/lib/twitter/client/request.rb new file mode 100644 index 000000000..e1e7d63eb --- /dev/null +++ b/lib/twitter/client/request.rb @@ -0,0 +1,40 @@ +module Twitter + class Client + module Request + def get(path, options={}, raw=false) + request(:get, path, options, raw) + end + + def post(path, options={}, raw=false) + request(:post, path, options, raw) + end + + def put(path, options={}, raw=false) + request(:put, path, options, raw) + end + + def delete(path, options={}, raw=false) + request(:delete, path, options, raw) + end + + private + + def request(method, path, options, raw) + response = connection(raw).__send__(method) do |request| + case method + when :get, :delete + request.url(formatted_path(path), options) + when :post, :put + request.path = formatted_path(path) + request.body = options + end + end + raw ? response : response.body + end + + def formatted_path(path) + [path, format].compact.join('.') + end + end + end +end diff --git a/lib/twitter/client/saved_searches.rb b/lib/twitter/client/saved_searches.rb new file mode 100644 index 000000000..0fc348c14 --- /dev/null +++ b/lib/twitter/client/saved_searches.rb @@ -0,0 +1,25 @@ +module Twitter + class Client + module SavedSearches + def saved_searches(options={}) + authenticate! + get('saved_searches', options) + end + + def saved_search(id, options={}) + authenticate! + get("saved_searches/show/#{id}", options) + end + + def saved_search_create(query, options={}) + authenticate! + post('saved_searches/create', options.merge(:query => query)) + end + + def saved_search_destroy(id, options={}) + authenticate! + delete("saved_searches/destroy/#{id}", options) + end + end + end +end diff --git a/lib/twitter/client/spam_reporting.rb b/lib/twitter/client/spam_reporting.rb new file mode 100644 index 000000000..b088fae42 --- /dev/null +++ b/lib/twitter/client/spam_reporting.rb @@ -0,0 +1,11 @@ +module Twitter + class Client + module SpamReporting + def report_spam(user, options={}) + authenticate! + merge_user_into_options!(user, options) + post('report_spam', options) + end + end + end +end diff --git a/lib/twitter/client/timeline.rb b/lib/twitter/client/timeline.rb new file mode 100644 index 000000000..996bba09e --- /dev/null +++ b/lib/twitter/client/timeline.rb @@ -0,0 +1,51 @@ +module Twitter + class Client + module Timeline + def public_timeline(options={}) + get('statuses/public_timeline', options) + end + + def home_timeline(options={}) + authenticate! do + get('statuses/home_timeline', options) + end + end + + def friends_timeline(options={}) + authenticate! do + get('statuses/friends_timeline', options) + end + end + + def user_timeline(options={}) + authenticate do + get('statuses/user_timeline', options) + end + end + + def mentions(options={}) + authenticate! do + get('statuses/mentions', options) + end + end + + def retweeted_by_me(options={}) + authenticate! do + get('statuses/retweeted_by_me', options) + end + end + + def retweeted_to_me(options={}) + authenticate! do + get('statuses/retweeted_to_me', options) + end + end + + def retweets_of_me(options={}) + authenticate! do + get('statuses/retweets_of_me', options) + end + end + end + end +end diff --git a/lib/twitter/client/trends.rb b/lib/twitter/client/trends.rb new file mode 100644 index 000000000..9a8c8f2df --- /dev/null +++ b/lib/twitter/client/trends.rb @@ -0,0 +1,21 @@ +module Twitter + class Client + module Trends + def trends(options={}) + get('trends', options) + end + + def current_trends(options={}) + get('trends/current', options) + end + + def daily_trends(date=Time.now, options={}) + get('trends/daily', options.merge(:date => date.strftime('%Y-%m-%d'))) + end + + def weekly_trends(date=Time.now, options={}) + get('trends/daily', options.merge(:date => date.strftime('%Y-%m-%d'))) + end + end + end +end diff --git a/lib/twitter/client/tweets.rb b/lib/twitter/client/tweets.rb new file mode 100644 index 000000000..12fd04a13 --- /dev/null +++ b/lib/twitter/client/tweets.rb @@ -0,0 +1,38 @@ +module Twitter + class Client + module Tweets + def status(id, options={}) + authenticate do + get("statuses/show/#{id}", options) + end + end + + def update(status, options={}) + authenticate! do + post('statuses/update', options.merge(:status => status)) + end + end + + def status_destroy(id, options={}) + authenticate! do + delete("statuses/destroy/#{id}", options) + end + end + + def retweet(id, options={}) + authenticate! do + post("statuses/retweet/#{id}", options) + end + end + + def retweets(id, options={}) + get("statuses/retweets/#{id}", options) + end + + def retweeters_of(id, options={}) + ids_only = !!options.delete(:ids_only) + get("statuses/#{id}/retweeted_by#{'/ids' if ids_only}", options) + end + end + end +end diff --git a/lib/twitter/client/user.rb b/lib/twitter/client/user.rb new file mode 100644 index 000000000..ab7b09fd4 --- /dev/null +++ b/lib/twitter/client/user.rb @@ -0,0 +1,55 @@ +module Twitter + class Client + module User + def user(user, options={}) + merge_user_into_options!(user, options) + get('users/show', options) + end + + def users(users, options={}) + merge_users_into_options!(Array(users), options) + get('users/lookup', options) + end + + def user_search(query, options={}) + get('users/search', options.merge(:q => query)) + end + + def suggestions(*args) + options = args.last.is_a?(Hash) ? args.pop : {} + category = args.first + get(['users/suggestions', category].compact.join('/'), options) + end + + def profile_image(screen_name, options={}) + get("users/profile_image/#{screen_name}", options, true).headers['location'] + end + + def friends(*args) + options = args.last.is_a?(Hash) ? args.pop : {} + user = args.first + if user + merge_user_into_options!(user, options) + get('statuses/friends', options) + else + authenticate! do + get('statuses/friends', options) + end + end + end + + def followers(*args) + options = args.last.is_a?(Hash) ? args.pop : {} + user = args.first + if user + merge_user_into_options!(user, options) + get('statuses/followers', options) + else + authenticate! do + get('statuses/followers', options) + end + end + end + end + end +end diff --git a/lib/twitter/client/utils.rb b/lib/twitter/client/utils.rb new file mode 100644 index 000000000..2cfd19adf --- /dev/null +++ b/lib/twitter/client/utils.rb @@ -0,0 +1,32 @@ +module Twitter + class Client + module Utils + private + + def merge_user_into_options!(user_id_or_screen_name, options={}) + case user_id_or_screen_name + when Fixnum, /^\d+$/ + options[:user_id] = user_id_or_screen_name.to_i + when String + options[:screen_name] = user_id_or_screen_name + end + options + end + + def merge_users_into_options!(user_ids_or_screen_names, options={}) + user_ids, screen_names = [], [] + user_ids_or_screen_names.flatten.each do |user_id_or_screen_name| + case user_id_or_screen_name + when Fixnum, /^\d+$/ + user_ids << user_id_or_screen_name.to_i + when String + screen_names << user_id_or_screen_name + end + end + options[:user_id] = user_ids.join(',') unless user_ids.empty? + options[:screen_name] = screen_names.join(',') unless screen_names.empty? + options + end + end + end +end diff --git a/lib/twitter/configuration.rb b/lib/twitter/configuration.rb new file mode 100644 index 000000000..835991670 --- /dev/null +++ b/lib/twitter/configuration.rb @@ -0,0 +1,32 @@ +require 'twitter/version' +require 'faraday' + +module Twitter + module Configuration + DEFAULT_ADAPTER = Faraday.default_adapter + DEFAULT_ENDPOINT = 'https://api.twitter.com/1' + DEFAULT_FORMAT = 'json' + DEFAULT_USER_AGENT = "Twitter Ruby Gem #{Twitter::VERSION}" + + def configure + yield self + end + + def options + @options ||= { + :adapter => DEFAULT_ADAPTER, + :endpoint => DEFAULT_ENDPOINT, + :format => DEFAULT_FORMAT, + :user_agent => DEFAULT_USER_AGENT + } + end + + def method_missing(symbol, *args) + if (method = symbol.to_s).sub!(/\=$/, '') + options[method.to_sym] = args.first + else + options.fetch(method.to_sym, super) + end + end + end +end diff --git a/lib/twitter/error.rb b/lib/twitter/error.rb new file mode 100644 index 000000000..c840fb879 --- /dev/null +++ b/lib/twitter/error.rb @@ -0,0 +1,23 @@ +module Twitter + class Error < StandardError; end + + class BadGateway < Error; end + class BadRequest < Error; end + class Forbidden < Error; end + class InternalServerError < Error; end + class NotAcceptable < Error; end + class NotFound < Error; end + class ServiceUnavailable < Error; end + class Unauthorized < Error; end + + class EnhanceYourCalm < Error + def initialize(message, http_headers) + @http_headers = Hash[http_headers] + super message + end + + def retry_after + @http_headers.values_at('retry-after', 'Retry-After').first.to_i + end + end +end diff --git a/lib/twitter/geo.rb b/lib/twitter/geo.rb deleted file mode 100644 index 9bf9113a2..000000000 --- a/lib/twitter/geo.rb +++ /dev/null @@ -1,107 +0,0 @@ -module Twitter - - # Handles the Twitter Geo API - # - # @see http://dev.twitter.com/pages/geo_dev_guidelines Geo Developer Guidelines - class Geo - extend ConfigHelper - include ConnectionHelper - include RequestHelper - attr_reader :access_key, :access_secret, :consumer_key, :consumer_secret - - # Creates a new instance of the geo client - # - # @option options [String] :api_endpoint an alternative API endpoint such as Apigee - def initialize(options={}) - @consumer_key = options[:consumer_key] || Twitter.consumer_key - @consumer_secret = options[:consumer_secret] || Twitter.consumer_secret - @access_key = options[:access_key] || Twitter.access_key - @access_secret = options[:access_secret] || Twitter.access_secret - @adapter = options[:adapter] || Twitter.adapter - @api_endpoint = options[:api_endpoint] || Twitter.api_endpoint - @api_version = options[:api_version] || Twitter.api_version - @format = Twitter.default_format - @protocol = options[:protocol] || Twitter.protocol - @user_agent = options[:user_agent] || Twitter.user_agent - end - - # Returns all the information about a known place - # - # @param place_id [String] the place key, found using - # @see http://dev.twitter.com/doc/get/geo/id/:place_id - # @see Geo#reverse_geocode place_id can be found via Geo#reverse_geocode - # @return place info - # @authenticated false - # @rate_limited true - def place(place_id) - perform_get("geo/id/#{place_id}.#{self.class.format}") - end - - # Search for places that can be attached to a statuses/update - # - # @option options [Float] lat The latitude to search around. -90 to 90 - # @option options [Float] long The longitude to search around. -180 to 180 - # @option options [String] query Free-form text to match against while executing a geo-based query, best suited for finding nearby locations by name. - # @option options [String] ip An IP address. Used when attempting to fix geolocation based off of the user's IP address. - # @option options [String] granularity ('city') This is the minimal granularity of place types to return and must be one of: "poi", "neighborhood", "city", "admin" or "country". Default: "city" - # @option options [String] accuracy A hint on the "region" in which to search. - # @option options [String] max_results A hint as to the number of results to return. - # @option options [String] attribute Filter by Place Attributes: e.g. attribute:street_address - # @return search results - # @see http://dev.twitter.com/doc/get/geo/search - # @authenticated false - # @rate_limited true - def search(options={}) - perform_get("geo/search.#{self.class.format}", options) - end - - # Given a latitude and a longitude, searches for up to - # 20 places that can be used as a place_id when updating a status. - # - # @option options [Float] lat The latitude to search around. -90 to 90 - # @option options [Float] long The longitude to search around. -180 to 180 - # @option options [String] granularity ('city') This is the minimal granularity of place types to return and must be one of: "poi", "neighborhood", "city", "admin" or "country". Default: "city" - # @option options [String] accuracy A hint on the "region" in which to search. - # @option options [String] max_results A hint as to the number of results to return. - # @return search results - # @authenticated false - # @rate_limited true - def reverse_geocode(options={}) - perform_get("geo/reverse_geocode.#{self.class.format}", options) - end - - # Locates places near the given coordinates which are similar in name. - # - # @option options [Float] lat The latitude to search around. -90 to 90 - # @option options [Float] long The longitude to search around. -180 to 180 - # @option options [String] name The name a place is known as - # @option options [String] contained_within place_id which you would like to restrict the search results to - # @option options [String] attribute Filter by Place Attributes: e.g. attribute:street_address - # @return search results - # @see http://dev.twitter.com/doc/get/geo/similar_places - # @see Geo#reverse_geocode place_id can be found via Geo#reverse_geocode - # @authenticated false - # @rate_limited true - def similar_places(options={}) - perform_get("geo/similar_places.#{self.class.format}", options) - end - - # Creates a new place at the given latitude and longitude - # - # @option options [Float] lat The latitude to search around. -90 to 90 - # @option options [Float] long The longitude to search around. -180 to 180 - # @option options [String] name The name a place is known as - # @option options [String] contained_within place_id which you would like to restrict the search results to - # @option options [String] attribute Filter by Place Attributes: e.g. attribute:street_address - # @option options [String] token The token returned from #similar_places - # @return place info - # @see http://dev.twitter.com/doc/post/geo/place - # @see Geo#similar_places token can be retrieved via Geo#similar_places - # @authenticated true - # @rate_limited true - def create_place(options={}) - perform_post("geo/place.#{self.class.format}", options) - end - - end -end diff --git a/lib/twitter/trends.rb b/lib/twitter/trends.rb deleted file mode 100644 index 7e4445cff..000000000 --- a/lib/twitter/trends.rb +++ /dev/null @@ -1,89 +0,0 @@ -module Twitter - - # Handles the Twitter trends API - class Trends - extend ConfigHelper - include ConnectionHelper - include RequestHelper - attr_reader :access_key, :access_secret, :consumer_key, :consumer_secret - - def initialize(options={}) - @consumer_key = options[:consumer_key] || Twitter.consumer_key - @consumer_secret = options[:consumer_secret] || Twitter.consumer_secret - @access_key = options[:access_key] || Twitter.access_key - @access_secret = options[:access_secret] || Twitter.access_secret - @adapter = options[:adapter] || Twitter.adapter - @api_endpoint = options[:api_endpoint] || Twitter.api_endpoint - @api_version = options[:api_version] || Twitter.api_version - @format = Twitter.default_format - @protocol = options[:protocol] || Twitter.protocol - @user_agent = options[:user_agent] || Twitter.user_agent - end - - # @group Global trends - # - # Returns the current top 10 trending topics on Twitter - # - # @option options [String] exclude Supplying 'hashtags' will remove all hashtags from the trends list - # @return trends info - # @see http://dev.twitter.com/doc/get/trends/current - # @authenticated false - # @rate_limited true - def current(options={}) - perform_get("trends/current.#{self.class.format}", options) - end - - # Returns the top 20 trending topics for each hour in a given day - # - # @option options [String] date Date for which to show trends in YYYY-MM-DD format - # @option options [String] exclude Supplying 'hashtags' will remove all hashtags from the trends list - # @return trends info or 404 if date is out of range - # @see http://dev.twitter.com/doc/get/trends/daily - # @authenticated false - # @rate_limited true - def daily(options={}) - perform_get("trends/daily.#{self.class.format}", options) - end - - # Returns the top 30 trending topics for each hour for a given week - # - # @option options [String] date Beginning of week for which to show trends in YYYY-MM-DD format - # @option options [String] exclude Supplying 'hashtags' will remove all hashtags from the trends list - # @return trends info or 404 if date is out of range - # @see http://dev.twitter.com/doc/get/trends/weekly - # @authenticated false - # @rate_limited true - def weekly(options={}) - perform_get("trends/weekly.#{self.class.format}", options) - end - - # @group Local trends - # - # Returns the locations for which Twitter has trending topic information - # - # @option options [Float] lat The latitude to search around. -90 to 90 - # @option options [Float] long The longitude to search around. -180 to 180 - # @return [Hashie::Mash] Locations for which trends are available - # @see http://dev.twitter.com/doc/get/trends/available - # @see http://developer.yahoo.com/geo/geoplanet/ Yahoo! WOEID info - # @authenticated false - # @rate_limited true - def available(options={}) - perform_get("trends/available.#{self.class.format}", options) - end - - # Returns the top 10 trending topics for a specific WOEID, - # if trending information is available for it. - # - # @param woeid - # @return [Hashie::Mash] Trends for the specified location - # @see http://dev.twitter.com/doc/get/trends/:woeid - # @see http://developer.yahoo.com/geo/geoplanet/ Yahoo! WOEID info - # @authenticated false - # @rate_limited true - def for_location(woeid) - perform_get("trends/#{woeid}.#{self.class.format}") - end - - end -end diff --git a/lib/twitter/unauthenticated.rb b/lib/twitter/unauthenticated.rb deleted file mode 100644 index c4e257e3c..000000000 --- a/lib/twitter/unauthenticated.rb +++ /dev/null @@ -1,123 +0,0 @@ -module Twitter - class Unauthenticated - extend ConfigHelper - include ConnectionHelper - include RequestHelper - - def initialize(options={}) - @adapter = options[:adapter] || Twitter.adapter - @api_endpoint = options[:api_endpoint] || Twitter.api_endpoint - @api_version = options[:api_version] || Twitter.api_version - @format = options[:format] || Twitter.format - @protocol = options[:protocol] || Twitter.protocol - @user_agent = options[:user_agent] || Twitter.user_agent - end - - def public_timeline(options={}) - perform_get("statuses/public_timeline.#{self.class.format}", options) - end - - def user(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_get("users/show.#{self.class.format}", options) - end - - def profile_image(screen_name, options={}) - connection_with_unparsed_response.get do |request| - request.url("users/profile_image/#{screen_name}.#{self.class.format}", options) - end.headers["location"] - end - - def suggestions(category_slug=nil, options={}) - path = case category_slug - when nil - "users/suggestions.#{self.class.format}" - when Hash - options = category_slug - "users/suggestions.#{self.class.format}" - else - "users/suggestions/#{category_slug}.#{self.class.format}" - end - perform_get(path, options) - end - - def retweeted_to_user(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_get("statuses/retweeted_to_user.#{self.class.format}", options) - end - - def retweeted_by_user(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_get("statuses/retweeted_by_user.#{self.class.format}", options) - end - - def status(id, options={}) - perform_get("statuses/show/#{id}.#{self.class.format}", options) - end - - def friend_ids(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_get("friends/ids.#{self.class.format}", options) - end - - def follower_ids(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_get("followers/ids.#{self.class.format}", options) - end - - def timeline(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_get("statuses/user_timeline.#{self.class.format}", options) - end - - def lists_subscribed(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_get("lists/all.#{self.class.format}", options) - end - - # :per_page = max number of statues to get at once - # :page = which page of tweets you wish to get - def list_timeline(list_owner_screen_name, slug, options={}) - perform_get("#{list_owner_screen_name}/lists/#{slug}/statuses.#{self.class.format}", options) - end - - def retweets(id, options={}) - perform_get("statuses/retweets/#{id}.#{self.class.format}", options) - end - - def friends(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_get("statuses/friends.#{self.class.format}", options) - end - - def followers(user_id_or_screen_name, options={}) - merge_user_into_options!(user_id_or_screen_name, options) - perform_get("statuses/followers.#{self.class.format}", options) - end - - def rate_limit_status(options={}) - perform_get("account/rate_limit_status.#{self.class.format}", options) - end - - def tos - perform_get("legal/tos.#{self.class.format}") - end - - def privacy - perform_get("legal/privacy.#{self.class.format}") - end - - private - - def merge_user_into_options!(user_id_or_screen_name, options={}) - case user_id_or_screen_name - when Fixnum - options[:user_id] = user_id_or_screen_name - when String - options[:screen_name] = user_id_or_screen_name - end - options - end - - end -end diff --git a/lib/twitter/version.rb b/lib/twitter/version.rb index 7830f01fe..43e8d48ac 100644 --- a/lib/twitter/version.rb +++ b/lib/twitter/version.rb @@ -1,3 +1,3 @@ module Twitter - VERSION = "1.0.0.rc.2".freeze + VERSION = '1.0.0.rc.2' end