diff --git a/CHANGELOG b/CHANGELOG index 05b581b31..034167248 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,15 @@ 0.2.7 - June 29, 2008 * added #rate_limit_status (Daniel Morrison) + * added source parameter option to Base#post + * added twittergem as source when posting from command line + * Twitter::RateExceeded raised when you hit your limit (Jim O'Leary) + * Twitter::Unavailable raised when twitter returns 503 + * Twitter::CantConnect is now more descriptive as to what is the problem when it is raised during a request + * quoting your message when using twitter post on the command line is now optional (Benoit Caccinolo) + * aliased post to p on command line so it's shorter (Benoit Caccinolo) + * unescaped html and added some color in command line view (Miles Z. Sterrett) + * added gemspec (technoweenie, Miles Z. Sterrett) + * Fixed stack trace error on first command line operation (Matt Rose) 0.2.6 - April 2, 2008 * found a more simple way of doing stdin without any extra gem dependencies 0.2.5 - April 2, 2008 diff --git a/Manifest.txt b/Manifest.txt index 0f36b8bc4..bef2414d2 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -13,19 +13,31 @@ lib/twitter/base.rb lib/twitter/command.rb lib/twitter/direct_message.rb lib/twitter/easy_class_maker.rb +lib/twitter/rate_limit_status.rb lib/twitter/status.rb lib/twitter/user.rb lib/twitter/version.rb -log/debug.log script/destroy script/generate script/txt2html setup.rb +spec/base_spec.rb +spec/direct_message_spec.rb +spec/fixtures/followers.xml +spec/fixtures/friends.xml +spec/fixtures/friends_for.xml +spec/fixtures/friends_lite.xml +spec/fixtures/friends_timeline.xml +spec/fixtures/public_timeline.xml +spec/fixtures/rate_limit_status.xml +spec/fixtures/status.xml +spec/fixtures/user.xml +spec/fixtures/user_timeline.xml +spec/spec.opts +spec/spec_helper.rb +spec/status_spec.rb +spec/user_spec.rb tasks/deployment.rake tasks/environment.rake tasks/website.rake -test/test_helper.rb -test/unit/base_test.rb -test/unit/direct_message_test.rb -test/unit/status_test.rb -test/unit/user_test.rb +twitter.gemspec diff --git a/lib/twitter.rb b/lib/twitter.rb index 3caacd226..cc6915ba5 100644 --- a/lib/twitter.rb +++ b/lib/twitter.rb @@ -1,9 +1,20 @@ %w(uri cgi net/http yaml rubygems hpricot active_support).each { |f| require f } +$:.unshift(File.join(File.dirname(__FILE__))) require 'twitter/version' require 'twitter/easy_class_maker' require 'twitter/base' require 'twitter/user' require 'twitter/status' require 'twitter/direct_message' -require 'twitter/rate_limit_status' \ No newline at end of file +require 'twitter/rate_limit_status' + +module Twitter + class Unavailable < StandardError; end + class CantConnect < StandardError; end + class BadResponse < StandardError; end + class UnknownTimeline < ArgumentError; end + class RateExceeded < StandardError; end + + SourceName = 'twittergem' +end \ No newline at end of file diff --git a/lib/twitter/base.rb b/lib/twitter/base.rb index 7f906ff26..852b70e06 100644 --- a/lib/twitter/base.rb +++ b/lib/twitter/base.rb @@ -3,11 +3,6 @@ # # The private methods in this one are pretty fun. Be sure to check out users, statuses and call. module Twitter - class Untwitterable < StandardError; end - class CantConnect < Untwitterable; end - class BadResponse < Untwitterable; end - class UnknownTimeline < ArgumentError; end - class Base # Twitter's url, duh! @@api_url = 'twitter.com' @@ -130,18 +125,25 @@ def leave(id_or_screenname) end # Updates your twitter with whatever status string is passed in - def post(status) + def post(status, o={}) + options = {}.merge(o) + form_data = {'status' => status} + form_data['source'] = options[:source] if options[:source] url = URI.parse("http://#{@@api_url}/statuses/update.xml") req = Net::HTTP::Post.new(url.path) req.basic_auth(@config[:email], @config[:password]) - req.set_form_data({'status' => status}) + req.set_form_data(form_data) response = Net::HTTP.new(url.host, url.port).start { |http| http.request(req) } Status.new_from_xml(parse(response.body).at('status')) end alias :update :post + def verify_credentials + request('account/verify_credentials', :auth => true) + end + private # Converts an hpricot doc to an array of statuses def statuses(doc) @@ -174,14 +176,24 @@ def request(path, options={}) begin response = Net::HTTP.start(@@api_url, 80) do |http| - req = Net::HTTP::Get.new('/' + path, options[:headers]) - req.basic_auth(@config[:email], @config[:password]) if options[:auth] - http.request(req) + req = Net::HTTP::Get.new('/' + path, options[:headers]) + req.basic_auth(@config[:email], @config[:password]) if options[:auth] + http.request(req) end - raise BadResponse unless response.message == 'OK' || response.message == 'Not Modified' - parse(response.body) - rescue - raise CantConnect + rescue => error + raise CantConnect, error.message + end + + if %w[200 304].include?(response.code) + response = parse(response.body) + raise RateExceeded if (response/:hash/:error).text =~ /Rate limit exceeded/ + response + elsif response.code == '503' + raise Unavailable, response.message + elsif response.code == '401' + raise CantConnect, 'Authentication failed. Check your username and password' + else + raise CantConnect, "Twitter is returning a #{response.code}: #{response.message}" end end diff --git a/lib/twitter/command.rb b/lib/twitter/command.rb index ea956f46d..c8e773b37 100644 --- a/lib/twitter/command.rb +++ b/lib/twitter/command.rb @@ -2,7 +2,7 @@ # It is only used and included in the bin/twitter file. module Twitter class Command - @@commands = [:post, :timeline, :friends, :friend, :followers, :follower, :featured, :important, :follow, :leave, :d] + @@commands = [:post, :p, :timeline, :friends, :friend, :followers, :follower, :featured, :important, :follow, :leave, :d] @@template = < 1 + ARGV.join " " + else + ARGV.shift + end + print "\nSending twitter update" finished = false status = nil progress_thread = Thread.new { until finished; print "."; $stdout.flush; sleep 0.5; end; } post_thread = Thread.new(binding()) { |b| - status = Twitter::Base.new(config['email'], config['password']).post(post) + status = Twitter::Base.new(config['email'], config['password']).post(post, :source => Twitter::SourceName) finished = true } post_thread.join @@ -57,6 +62,7 @@ def post puts " OK!" puts "Got it! New twitter created at: #{status.created_at}\n" end + alias :p :post # Shows status, time and user for the specified timeline def timeline @@ -67,8 +73,8 @@ def timeline puts Twitter::Base.new(config['email'], config['password']).timeline(timeline).each do |s| - puts "#{s.text}\n-- #{s.user.name} at #{s.created_at}" - puts + puts "#{CGI::unescapeHTML(s.text)}\n --\e[34m #{CGI::unescapeHTML(s.user.name)}\e[32m at #{s.created_at}" + puts "\e[0m" end end @@ -144,8 +150,6 @@ def follower end def featured - puts - puts 'This is all implemented, just waiting for twitter to get the api call working' config = create_or_find_config puts @@ -234,7 +238,7 @@ def create_or_find_config config = YAML::load open(home + "/.twitter") rescue open(home + '/.twitter','w').write(@@template) - config = YAML::load open(home + "/.twitter") + config = YAML::load(@@template) end if config['email'] == nil or config['password'] == nil diff --git a/twitter.gemspec b/twitter.gemspec new file mode 100644 index 000000000..40e06a171 --- /dev/null +++ b/twitter.gemspec @@ -0,0 +1,23 @@ +Gem::Specification.new do |s| + s.name = %q{twitter} + s.version = "0.2.7" + s.specification_version = 2 if s.respond_to? :specification_version= + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["John Nunemaker"] + s.date = %q{2008-07-6} + s.default_executable = %q{twitter} + s.description = %q{a command line interface for twitter, also a library which wraps the twitter api} + s.email = %q{nunemaker@gmail.com} + s.executables = ["twitter"] + s.extra_rdoc_files = ["History.txt", "License.txt", "Manifest.txt", "README.txt"] + s.files = ["CHANGELOG", "History.txt", "License.txt", "Manifest.txt", "README.txt", "Rakefile", "bin/twitter", "config/hoe.rb", "config/requirements.rb", "examples/twitter.rb", "lib/twitter.rb", "lib/twitter/base.rb", "lib/twitter/command.rb", "lib/twitter/direct_message.rb", "lib/twitter/easy_class_maker.rb", "lib/twitter/rate_limit_status.rb", "lib/twitter/status.rb", "lib/twitter/user.rb", "lib/twitter/version.rb", "script/destroy", "script/generate", "script/txt2html", "setup.rb", "spec/base_spec.rb", "spec/direct_message_spec.rb", "spec/fixtures/followers.xml", "spec/fixtures/friends.xml", "spec/fixtures/friends_for.xml", "spec/fixtures/friends_lite.xml", "spec/fixtures/friends_timeline.xml", "spec/fixtures/public_timeline.xml", "spec/fixtures/rate_limit_status.xml", "spec/fixtures/status.xml", "spec/fixtures/user.xml", "spec/fixtures/user_timeline.xml", "spec/spec.opts", "spec/spec_helper.rb", "spec/status_spec.rb", "spec/user_spec.rb", "tasks/deployment.rake", "tasks/environment.rake", "tasks/website.rake"] + s.has_rdoc = true + s.homepage = %q{http://twitter.rubyforge.org} + s.rdoc_options = ["--main", "README.txt"] + s.require_paths = ["lib"] + s.rubyforge_project = %q{twitter} + s.rubygems_version = %q{1.1.1} + s.summary = %q{a command line interface for twitter, also a library which wraps the twitter api} + s.add_dependency(%q, [">= 0"]) + s.add_dependency(%q, [">= 0"]) +end \ No newline at end of file