Re.Mark

My Life As A Blog

Ruby Tuesday #8 Part 1 : Tweeting from Ruby

leave a comment »

This week I aimed to tweet from Ruby.  The first thing I noticed was that the code that had worked last week had stopped working.  Twitter seems to be requiring requests for the friends timeline to be authenticated.  So I needed to make a couple of adjustments to cater for this change.  Firstly I created a new method called get_response.  It looks like this:

def get_response(request, url)
  begin
    res = Net::HTTP.start(url.host, url.port) {|http| http.request(request)}
    case res
    when Net::HTTPSuccess, Net::HTTPRedirection
      if res.body.empty?
        puts "Empty Body"
      else
        res.body
      end
    else
      puts res.to_s
    end
    res.body
  rescue SocketError
    puts "SocketError"
  end
end

I’ve put in some very rudimentary exception handling – this way I can see what’s going on – the begin / rescue is the error handling structure.  If you have a C# or Java background, beware: throw catch exists in Ruby, but it’s different.  Read this for a fuller explanation of exception handling in Ruby.  Next I needed to hook this method into the get_url method:

def get_url(base_address, path, username, password)
  url = form_url(base_address, path)
  req = Net::HTTP::Get.new(url.path)
  init_request req,  username, password
  get_response(req, url)
end

You may have spotted a couple of other changes in that method.  I’m asking for a username and password and I’ve added a couple of convenience methods that’ll help me write a post_url method.  The form_url method is simple:

def form_url(base_address, path)  
  URI.parse(base_address + path)
end

The init_request method looks like this:

def init_request(request, username, password)
  if (username && password)
    request.basic_auth(username, password)
  end
end

This method takes advantage of the fact that only nil and false equate to nil in Ruby.  So, now I can update my download_friends_timeline method like this:

def download_friends_timeline(username, password)
    download_timeline("/friends_timeline/#{username}.xml", username, password)
end

and the download_timeline method like this:

def download_timeline(path, username=nil, password=nil)
    get_url(BASE_ADDRESS, path, username, password)
end

Notice that I’ve supplied default values for username and password, which makes them optional (from the caller’s perspective.)  Since this method is called from a couple of methods where no authentication is required, making these arguments optional seems like a good idea.  A quick update to the code in main, and that all worked.  Great.  Now time to tweet.  A tweet requires a post, so we need a method to do that.  I decided to call the method post_url:

def post_url(base_address, path, username, password, form_data)
  url = form_url(base_address, path)
  req = Net::HTTP::Post.new(url.path)
  init_request req,  username, password
  req.set_form_data(form_data)
  get_response(req, url)
end

Looks a lot like get_url.  Hmm.  There must be a way to improve that – but let’s leave it for now.  Next we need a method on the Client class called Update:

def update(update_text, username, password)
    post_url(BASE_ADDRESS, "/update.xml", username, password, {'status' => update_text})
end

All that’s remaining is to call that from main:

require 'Twitter'
$KCODE = "u"
username = 'Put your username here'
password= 'Put your password here'
translator = Translator.new
client = Client.new
client.update('Tweeting from Ruby as part of Ruby Tuesday', username, password)

translator.xml_to_tweets(client.download_public_timeline).each do |tweet|
  puts "#{tweet.user.screen_name} says #{tweet.text}"
end

translator.xml_to_tweets(client.download_friends_timeline(username, password)).each do |tweet|
  puts "#{tweet.user.screen_name} says #{tweet.text}"
end

translator.xml_to_tweets(client.download_user_timeline('blooders')).each do |tweet| 
  puts "#{tweet.user.screen_name} says #{tweet.text}"
end

It all worked first time.  So, I can tweet from Ruby.  There’s probably some improvements that can be made to the code.  To make this usable, I need to add some sort of interface.  That should keep me busy next week.

Advertisements

Written by remark

June 3, 2008 at 6:54 pm

Posted in Ruby

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: