---
title: Ruby wrapper for Twitter Search API
teaser:
tags: news,web,ruby
author: Dan Croak
published_on: 2008-09-09
---

[Twitter Search](http://search.twitter.com/) (formerly Summize) is sweet. I use
it every day to find first-person commentary on thoughtbot's work, Boston
sports, national politics, and anything else that catches my fancy.

The [Twitter Search <abbr title="Application Programming
Interface">API</abbr>](http://search.twitter.com/api) is also sweet. I wanted to
use it a while back for [Politweets.](http://politweets.com) In combination with
a simple cron job, the effect is commentary on the U.S. Presidential Election
from around the world, seen within minutes of being tweeted.

[![''](http://images.thoughtbot.com/ui/2008-9-5-politweets.png)](http://politweets.com)

[Dustin Sallings](http://twitter.com/dlsspy) wrote a great Ruby wrapper for the
Summize <abbr title="Application Programming Interface">API</abbr> that [he put
on github.](http://github.com/dustin) I forked it and added a shoulda test suite
and documentation.

Introducing the [Twitter Search](http://github.com/dancroak/twitter-search) gem.

## Usage

Install the gem.

    gem install twitter-search

Require the gem.

    require 'twitter_search'

Set up a `TwitterSearch::Client`. Name your client (a.k.a. 'user agent') to
something meaningful, such as your app's name. This helps Twitter Search answer
any questions about your use of the API.

    @client = TwitterSearch::Client.new 'politweets'

Request tweets by calling the query method of your client.

    @tweets = @client.query :q => 'twitter search'

## Search Operators

The following operator examples find tweets...

* [:q => \'twitter search\'](http://search.twitter.com/search?q=twitter+search)
  -- containing both twitter and search. This is the default operator.
* [:q => \'happy hour\'](http://search.twitter.com/search?q=%22happy+hour%22)
  -- containing the exact phrase happy hour.
* [:q => \'obama OR hillary\'](http://search.twitter.com/search?q=obama+OR+hillary)
  -- containing either obama or hillary (or both).
* [:q => \'beer -root\'](http://search.twitter.com/search?q=beer+-root)
  -- containing beer but not root.
* [:q => \'#haiku\'](http://search.twitter.com/search?q=%23haiku)
  -- containing the hashtag haiku.
* [:q => \'from:alexiskold\'](http://search.twitter.com/search?q=from%3Aalexiskold)
  -- sent from person alexiskold.
* [:q => \'to:techcrunch\'](http://search.twitter.com/search?q=to%3Atechcrunch)
  -- sent to person techcrunch.
* [:q => \'@mashable\'](http://search.twitter.com/search?q=%40mashable)
  -- referencing person mashable.
* [:q => \'superhero since:2008-05-01\'](http://search.twitter.com/search?q=superhero+since%3A2008-05-01)
  -- containing superhero and sent since date 2008-05-01 (year-month-day).
* [:q => \'ftw until:2008-05-03\'](http://search.twitter.com/search?q=ftw+until%3A2008-05-03)
  -- containing ftw and sent up to date 2008-05-03.
* [:q => \'movie -scary :)\'](http://search.twitter.com/search?q=movie+-scary+%3A%29)
  -- containing movie, but not scary, and with a positive attitude.
* [:q => \'flight :(\'](http://search.twitter.com/search?q=flight+%3A%28)
  -- containing flight and with a negative attitude.
* [:q => \'traffic ?\'](http://search.twitter.com/search?q=traffic+%3F)
  -- containing traffic and asking a question.
* [:q => \'hilarious filter:links\'](http://search.twitter.com/search?q=hilarious+filter%3Alinks)
  -- containing hilarious and linking to <abbr title="Uniform Resource
  Locator">URL</abbr>s.

## Foreign Languages

The Twitter Search <abbr title="Application Programming Interface">API</abbr>
supports foreign languages, accessible via the `:lang` key. Use the [ISO
639-1](http://en.wikipedia.org/wiki/ISO_639-1) codes as the value:

    @tweets = @client.query :q => 'programmé', :lang => 'fr'

## Result pagination

Alter the number of Tweets returned per page with the :rpp key. Stick with 10,
15, 20, 25, 30, or 50.

    @tweets = @client.query :q => 'Boston Celtics', :rpp => '30'

## Gotchas

* Searching for a positive attitude :) returns tweets containing the text :),
  =), :D, and :-)
* Searches are case-insenstive.
* The near operator available in the Twitter Search web interface is not
  available via the API. You must geocode before making your Twitter Search API
  call, and use the `:geocode` key in your request using the pattern `lat,lngmi`
  or `lat,lngkm`: `@tweets = @client.query :q => 'Pearl Jam', :geocode =>
  '43.4411,-70.9846mi'`

## Usage With ActiveRecord and Cron

You can get fancier with your setup, using queuing or another approach, but
here's a simple example using cron.

Schema:

```ruby
create_table "tweets", :force => true do |t|
  t.string   "user_name",          :limit => 20,  :default => "", :null => false
  t.string   "body",               :limit => 140, :default => "", :null => false
  t.datetime "created_at",                                        :null => false
  t.datetime "updated_at",                                        :null => false
  t.integer  "twitter_id",         :limit => 11
end

add_index "tweets", ["created_at"], :name => "index_tweets_on_created_at"
add_index "tweets", ["twitter_id"], :name => "index_tweets_on_twitter_id"
```

Hit the <abbr title="Application Programming Interface">API</abbr> in your rake
task ([write the code in a class so it can be easily
tested](http://blog.jayfields.com/2006/11/ruby-testing-rake-tasks.html)):

```ruby
class Twitter
  def self.import!
    # the implementation is up to you
  end
end
```

Since I don't have the cron <abbr title="Application Programming
Interface">API</abbr> memorized, I like to create cron jobs with a handy little
tool called [crondle](http://github.com/scrooloose/crondle):

```ruby
require 'lib/crondle'

Crondle.define_jobs do |builder|
  rails_root = '/var/www/apps/politweets/current'

  [3, 9, 15, 21, 27, 33, 39, 45, 51, 57].each do |minute|
    builder.desc "Import tweets at #{minute} past the hour"
    builder.job "#{rails_root}/script/runner Twitter.import!", :minute => minute
  end
end
```

Run the crondle script to get the text that you'll put in crontab -e:

```crontab
# Import tweets at 3 past the hour
3 * * * * /var/www/apps/politweets/current/script/runner Twitter.import!

# Import tweets at 9 past the hour
9 * * * * /var/www/apps/politweets/current/script/runner Twitter.import!
```

And you're on your way.

Thanks to [Doug](http://www.doug-march.com/), [Gabe](http://ducktyper.com/),
[Jason](http://sixtwothree.org/), [Min](http://www.thoughtsatsix.com/), and
[Dustin](http://bleu.west.spy.net/~dustin/) for their work on Politweets and the
Twitter Search gem.
