# -*- coding: utf-8 -*-require 'rubygems'require 'oauth'require 'cgi'require 'uri'require 'net/http'require 'json'# RubyTwit beta by NV# (The MIT License)## Copyright c 2010 NV## Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:## The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.## THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # This program uses Rubytter.# (The MIT License)## Copyright c 2008-2010 jugyo## Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:## The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.## THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Net::HTTP.version_1_2class RubyTwit # Exception Class class TwitterAPIError < StandardError attr_reader :code def initialize(message, response = nil) super(message) @response = response end end # Constants DEFAULT_ENDPOINT = 'http://api.twitter.com/1/' # Attributes attr_reader :access_token attr_reader :endpoint attr_reader :proxy_endpoint # New def initialize(access_token, endpoint = DEFAULT_ENDPOINT, proxy_endpoint = nil) @access_token = access_token @endpoint = endpoint if proxy_endpoint.nil? then @proxy_endpoint = endpoint else @proxy_endpoint = proxy_endpoint end end # Twitter API def self.api_settings # method name path for API http method " update_status statuses/update post remove_status statuses/destroy/%s delete public_timeline statuses/public_timeline home_timeline statuses/home_timeline friends_timeline statuses/friends_timeline replies statuses/replies mentions statuses/mentions user_timeline statuses/user_timeline/%s show statuses/show/%s friends statuses/friends/%s followers statuses/followers/%s retweet statuses/retweet/%s post retweets statuses/retweets/%s retweeted_by_me statuses/retweeted_by_me retweeted_to_me statuses/retweeted_to_me retweets_of_me statuses/retweets_of_me user users/show/%s direct_messages direct_messages sent_direct_messages direct_messages/sent send_direct_message direct_messages/new post remove_direct_message direct_messages/destroy/%s delete follow friendships/create/%s post leave friendships/destroy/%s delete friendship_exists friendships/exists followers_ids followers/ids/%s friends_ids friends/ids/%s favorites favorites/%s favorite favorites/create/%s post remove_favorite favorites/destroy/%s delete verify_credentials account/verify_credentials get end_session account/end_session post update_delivery_device account/update_delivery_device post update_profile_colors account/update_profile_colors post limit_status account/rate_limit_status update_profile account/update_profile post enable_notification notifications/follow/%s post disable_notification notifications/leave/%s post block blocks/create/%s post unblock blocks/destroy/%s delete block_exists blocks/exists/%s get blocking blocks/blocking get blocking_ids blocks/blocking/ids get saved_searches saved_searches get saved_search saved_searches/show/%s get create_saved_search saved_searches/create post remove_saved_search saved_searches/destroy/%s delete create_list %s/lists post update_list %s/lists/%s put delete_list %s/lists/%s delete lists %s/lists lists_followers %s/lists/memberships list_statuses %s/lists/%s/statuses list %s/lists/%s list_members %s/%s/members add_member_to_list %s/%s/members post remove_member_from_list %s/%s/members delete list_following %s/%s/subscribers follow_list %s/%s/subscribers post remove_list %s/%s/subscribers delete ".strip.split("\n").map{|line| line.strip.split(/\s+/)} end api_settings.each do |array| method, path, http_method = *array http_method ||= 'get' if /%s/ =~ path eval <<-EOS def #{method}(*args) params = args.last.kind_of?(Hash) ? args.pop : {} path = '#{path}' % args path.sub!(/\\/\\z/, '') #{http_method}(path, params) end EOS else eval <<-EOS def #{method}(params = {}) #{http_method}('#{path}', params) end EOS end end alias_method :__create_list, :create_list def create_list(name, params = {}) __create_list(params.merge({:name => name})) end alias_method :__add_member_to_list, :add_member_to_list def add_member_to_list(list_slug, user_id, params = {}) __add_member_to_list(list_slug, params.merge({:id => user_id})) end alias_method :__remove_member_from_list, :remove_member_from_list def remove_member_from_list(list_slug, user_id, params = {}) __remove_member_from_list(list_slug, params.merge({:id => user_id})) end alias_method :__update_status, :update_status def update_status(params = {}) __update_status(params) end alias_method :__create_saved_search, :create_saved_search def create_saved_search(arg) arg = {:query => arg} if arg.kind_of?(String) __create_saved_search(arg) end def update(status, params = {}) update_status(params.merge({:status => status})) end def direct_message(user, text, params = {}) send_direct_message(params.merge({:user => user, :text => text})) end # HTTP Request def get(path, params = {}) path += '.json' path += '?' + to_param_str(params) unless params.empty? url = URI.join(@proxy_endpoint, path) http_request(path, Net::HTTP::Get.new(url.request_uri)) end def post(path, params = {}) path += '.json' url = URI.join(@proxy_endpoint, path) request = Net::HTTP::Post.new(url.request_uri) request.set_form_data(params) http_request(path, request) end def put(path, params = {}) path += '.json' url = URI.join(@proxy_endpoint, path) request = Net::HTTP::Put.new(url.request_uri) request.set_form_data(params) http_request(path, request) end def delete(path, params = {}) path += '.json' path += '?' + to_param_str(params) unless params.empty? url = URI.join(@proxy_endpoint, path) http_request(path, Net::HTTP::Delete.new(url.request_uri)) end def http_request(path, request) url = URI.join(@proxy_endpoint, path) http = Net::HTTP.new(url.host, url.port) request.oauth!(http, @access_token.consumer, @access_token, :request_uri => URI.join(@endpoint, path)) response = http.request(request) json_response = JSON.parse(response.body) if response.code == '200' then json_response else raise TwitterAPIError.new(json_response['error'], response) end end # Utility def to_param_str(hash) raise ArgumentError, 'Not a Hash object' unless hash.is_a?(Hash) hash.to_a.map{|i| i[0].to_s + '=' + CGI.escape(i[1].to_s) }.join('&') endend