header image

twitter_post.pngI 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:

  1. module Twitter
  2.   class Base
  3.     def all_entries(method, options = {})
  4.       all_entries = [] 
  5.       next_100 = self.send method, {:page => (current_page = 1)}.merge(options)
  6.       while (next_100.size != 0) do
  7.         all_entries << next_100
  8.         next_100 = self.send method, {:page => (current_page += 1)}.merge(options)
  9.       end 
  10.       all_entries.flatten
  11.     end
  12.   end
  13. 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):

  1. module Twitter
  2.   class Base
  3.     alias_method :throw_method_missing, :method_missing
  4.  
  5.     def method_missing(method_name, *args, &bloke)
  6.       if (method_name.to_s =~ /^all_.+/)
  7.         all_entries(method_name.to_s[/all_(.+)/,1], args[0] || {})
  8.       else
  9.         throw_method_missing(method_name, *args, &bloke)
  10.       end
  11.     end
  12.   end
  13. 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.

  1. class Array
  2.   def names
  3.     self.map{|u| u.screen_name}
  4.   end
  5. end
  6.  
  7. module Twitter
  8.   class Base
  9.     def not_following_back
  10.       all_friends.names - all_followers.names
  11.     end
  12.   end
  13. 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 allfollowers.names - allfriends.names. This is how the final code looks like:

  1. require ‘rubygems’
  2. require ‘twitter’
  3.  
  4. connection =  Twitter::Base.new(‘yourname’, ‘yourpass’)
  5.  
  6. class Array
  7.   def names
  8.     self.map{|u| u.screen_name}
  9.   end
  10. end
  11.  
  12. module Twitter
  13.   class Base
  14.     alias_method :throw_method_missing, :method_missing
  15.  
  16.     def method_missing(method_name, *args, &bloke)
  17.       if (method_name.to_s =~ /^all_.+/)
  18.         all_entries(method_name.to_s[/all_(.+)/,1], args[0] || {})
  19.       else
  20.         throw_method_missing(method_name, *args, &bloke)
  21.       end
  22.     end
  23.  
  24.     def all_entries(method, options = {})
  25.       all_entries = [] 
  26.       next_100 = self.send method, {:page => (current_page = 1)}.merge(options)
  27.       while (next_100.size != 0) do
  28.         all_entries << next_100
  29.         next_100 = self.send method, {:page => (current_page += 1)}.merge(options)
  30.       end 
  31.       all_entries.flatten
  32.     end
  33.  
  34.     def not_following_back
  35.       all_friends.names - all_followers.names
  36.     end
  37.  
  38.   end 
  39. end 
  40.  
  41. 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.



If you liked the article, subscribe to the feed   and follow me on twitter!.


      

9 Responses to “Advanced Twitter Queries with the Twitter Gem”

  1. Brian Deterling Says:

    Nice patch. There is a relatively new API (/friends/ids/user.fmt) that lets you get all of your friends or followers in a single call but it only gives you the numeric ids so you still have to make additional calls to get any useful information. But you can use it to diff the list to narrow down what you have to get from the other calls.

    Check out http://tweepdiff.com. It’s basically the same concept in a Sinatra app. I’m not using the gem mainly because I’m using Curl::Multi and memcache to try to speed things up, but I may use it for future functionality.

    Brian

  2. peter Says:

    Thanks for the heads up Brian :-) Seems I had to write this post to find out these possibilities.

    Of course the other goal was to show how to extend the gem with functionality that is not there.

  3. Simon Harris Says:

    Have you tried Twitter4r? http://twitter4r.rubyforge.org/

  4. atmos Says:

    I’m pretty sure the code you’re looking for is friendids and followerids. You can get back the ids of all of your friends and followers in one query. You can do the same kind of array manipulation and then query again only on the ids you’re interested in. http://gist.github.com/71165

  5. baron Says:

    Actually all of this is part of the new Twitter API and the gem but you need to get it from github. Much cleaner and straightforward.

    http://github.com/jnunemaker/twitter/blob/f2260a9857e8a45db01a4b18d34f6c4c4b2e4b8a/lib/twitter/base.rb

  6. Jeff Paul Internet Millions Says:

    Now this is very interesting, impressive and never thought of. In simple words well done for providing creative information.

  7. twituser Says:

    So Twitter is awesome for Taking traffic to you website . It is very
    simple to setup and its a fun positive way to keep in contact with
    people. To get more followers on twitter check out this amazing
    tool.
    Twitter
    Traffic Machine

  8. Cleothildee Says:

    i love to Twitter my day to day activities to my friends and followers. Twitter is much better than blogging because it is direct to the point and does not require you to type so many unnecessary words.

    1a

  9. Kristine Shuee Says:
    • i just love to Twitter everyday with my friends. Twitter is much better than blogging in my opinion and it is very addictive too.

Leave a Reply




Bad Behavior has blocked 1031 access attempts in the last 7 days.