I wanted a reliable way to find out a few things about my twitter account (for example which of the users I am following are not following me back) – unfortunately the third party apps out there are not always very reliable, do not exactly do what I want/as I want so I decided to check out how easy it is to hack up a more advanced query using a Ruby twitter API wrapper. It turned out that it couldn’t be easier!
There are several gems wrapping the Twitter API out there – I started to use the ‘twitter’ gem from John Nunemaker and I am perfectly happy with it so far. John did a great job supporting all the features offered by the API – it’s a different question that the API, like twitter itself, is quite minimalistic. For example I have not found a way to get all my followers/friends easily (drop me a comment if I am missing something) so I monkey-patched this into the module in a generic way:
module Twitter
class Base
def all_entries(method, options = {})
all_entries = []
next_100 = self.send method, {:page => (current_page = 1)}.merge(options)
while (next_100.size != 0) do
all_entries << next_100
next_100 = self.send method, {:page => (current_page += 1)}.merge(options)
end
all_entries.flatten
end
end
end
for example you can call connection.all\_entries(:friends) to get all of your friends, given that you set up a connection to your account (I found only a method which returns your first 100 friends – didn’t spend too much time with the documentation though – agin, drop me a message if I overlooked something).
I have added a bit of syntactic sugar to be able to call connection.all\_friends instead of connection.all\_entries(:friends):
module Twitter
class Base
alias_method :throw_method_missing, :method_missing
def method_missing(method_name, *args, &bloke)
if (method_name.to_s =~ /^all_.+/)
all_entries(method_name.to_s[/all_(.+)/,1], args[0] || {})
else
throw_method_missing(method_name, *args, &bloke)
end
end
end
end
Here we ensure that only method calls that start with all\_ are handled by all\_entries, the rest is throwing a method\_missing since we are not interested in handling those messages.
Now it could not be easier to implement the function I originally intended to build: list of users who are not following back.
class Array
def names
self.map{|u| u.screen_name}
end
end
module Twitter
class Base
def not_following_back
all_friends.names - all_followers.names
end
end
end
That’s all there’s to it (I am not a big fan of monkey patching core classes btw ; but in this case, adding the names() method to the Array class just made the method I intended to originally implement much cleaner so I rolled with it).
Note that since subtraction is a non-commutative operation, all\_friends.names – all\_followers.names is not necessarily the same as all_followers.names – all_friends.names.
This is how the final code looks like:
require 'rubygems'
require 'twitter'
connection = Twitter::Base.new('yourname', 'yourpass')
class Array
def names
self.map{|u| u.screen_name}
end
end
module Twitter
class Base
alias_method :throw_method_missing, :method_missing
def method_missing(method_name, *args, &bloke)
if (method_name.to_s =~ /^all_.+/)
all_entries(method_name.to_s[/all_(.+)/,1], args[0] || {})
else
throw_method_missing(method_name, *args, &bloke)
end
end
def all_entries(method, options = {})
all_entries = []
next_100 = self.send method, {:page => (current_page = 1)}.merge(options)
while (next_100.size != 0) do
all_entries << next_100
next_100 = self.send method, {:page => (current_page += 1)}.merge(options)
end
all_entries.flatten
end
def not_following_back
all_friends.names - all_followers.names
end
end
end
p connection.not_following_back
You can download/check out the code here – do not try to copy & paste it from the text as it will be b0rk3d.
In part 2 I’d like to set up a small Sinatra app showing the above users in a list – displaying their avatar, screen name and real name, plus a link to remove them if you decide so.