In my previous post, I discussed how to parse XML from a REST service. As it happens, the REST service I was interested in was the Twitter API. My aim was to use IronRuby to update my Twitter status from the REPL (Read-eval-print loop) – the interactive console. The result is IronTwitter 🙂
While I’m no expert on REST, I understand that you simply ping a URL with a correctly formed URL and process the response in the correct format (xml, json etc).
One of the great things about IronRuby is the REPL, this is the ir.exe console application and allows you to interact with the language and .net at runtime, they are very simple – type a line, hit enter and the line is executed. They are great for executing quick lines of code, or learning how do a task in the language. I used the REPL a lot while creating the XML parser as I could easily modify the code dynamically to see if something worked as I expected.
Interacting with IronTwitter
Interacting with IronTwitter is very easy. First you need to reference the library.
require ‘IronTwitter’
You then need to construct the object, providing your username and password
@twitter = IronTwitter.new ‘username’, ‘password’
The IronTwitter object has a method called update which has a parameter for your new status. Under the covers, it calls the API and updates your status. However, in order to make this easier to type, I added an alias for the method called t. To update your status, you simply type.
@twitter.t “Hello from IronTwitter!”
This will send a request to ‘http://twitter.com/statuses/update.xml?status=Hello from IronTwitter!’ and your twitter status will be updated.
We can now start taking advantage of IronRuby and we can start constructing tweets dynamically! For example, if we had a method which counted all the files and directories, we could tweet the result.
def count(dir)
num = 1
Dir[dir + ‘/*’].each do |d|
if File.file? d
num = num + 1
else
num = num + count(d)
end
end
return num
end
All we would need to do is call the method and join the response onto the string argument for the method.
twitter.t ‘The number of files currently in %TEMP% is ‘ + count(‘C:/Users/BENHAL~1/AppData/Local/Temp’).to_s
While this isn’t the most interesting tweet, it’s an interesting concept. You can see my various test tweets at http://twitter.com/ben_hall_test, note my main twitter account is http://twitter.com/ben_hall.
After being able to send a tweet, I wanted to see how to process the response. The API has a FriendsTimeline method, this will return the timeline you see on your twitter homepage, the tweets of you and the people your following. Using my xml wrapper, when you call the method friends_timeline, you then use a block to process each status, which is a monkey patched XmlElement object from the Xml Parser I created.
>>> @twitter.friends_timeline {|status| puts status.get(‘text’)}
Hello from IronTwitter!
…..
Under the covers of IronTwitter
While that is very interesting, what happens under the covers is more relevant. When dealing with the API, there are two important items, the first is the url, the second is the options. For update, I send a request to ‘statuses/update.xml’ with a parameter status containing my message.
def update(msg)
url = “http://twitter.com/statuses/update.xml”
options = { :status => msg }
send_request url, options
end
alias :t :update
This is then passed into my send_request method, this uses the WebRequest object from System.Net to send the correctly formatted request.
def send_request(url, options)
requestUrl = convert url, options
request = WebRequest.Create(requestUrl)
request.Method = “POST”;
request.ContentType=”application/x-www-form-urlencoded”;
request.ContentLength = 0;
request.UserAgent = “IronTwitter”
request.Credentials = NetworkCredential.new(@username, @password)
@response = request.GetResponse
end
The URL which is requested looks like this. As we use HTTPAuth, your status is updated.
http://twitter.com/statuses/update.xml?status=Hello from IronTwitter!
A similar approach is taken when it comes to the friends timeline. First, I’ve used an optional parameter so you can define the limit of statuses returned – by default it is 20. The method then takes a block, this is used to process the request. If a block is not provided, I raise an exception. I then use the Xml Parser I created to start processing the xml response.
def friends_timeline(tweetCount=20, &b)
url = “http://twitter.com/statuses/friends_timeline.xml”
options = { :count => tweetCount }
send_request url, options
readStream = System::IO::StreamReader.new(@response.GetResponseStream)
doc = Document.new(readStream.read_to_end)
if block_given?
doc.elements(‘statuses/status’) do |status|
b.call status
end
else
raise ‘Block required for processing statuses’
end
end
From the calling code, I simply access the elements on the node and output them to the screen.
twitter.friends_timeline do |status|
status.node(‘user’) {|u| print u.get(‘name’) }
print ‘ ‘
puts status.get(‘text’)
end
The name and the status of the user is then sent to the console, the result being this:
E:IronTwitter>ir sample.rb
Ben Hall This is a test tweet
Download the code and sample from here. I’ve also uploaded the code to the MSDN Code Gallery
Very Cool post! 🙂