jsl-osprey 0.0.8 → 0.0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +4 -2
- data/Rakefile +42 -0
- data/VERSION.yml +4 -0
- data/lib/core_ext/array.rb +8 -0
- data/lib/core_ext/hash.rb +17 -0
- data/lib/osprey/result_set.rb +22 -0
- data/lib/osprey/search.rb +177 -0
- data/lib/osprey/tweet.rb +7 -0
- data/lib/osprey.rb +17 -0
- data/osprey.gemspec +50 -0
- data/spec/fixtures/swine_flu1.json +1 -0
- data/spec/fixtures/swine_flu2.json +1 -0
- data/spec/fixtures/swine_flu_result_set1.yml +200 -0
- data/spec/fixtures/swine_flu_result_set2.yml +197 -0
- data/spec/osprey/result_set_spec.rb +15 -0
- data/spec/osprey/search_spec.rb +126 -0
- data/spec/osprey_spec.rb +7 -0
- data/spec/spec_helper.rb +19 -0
- metadata +28 -3
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 Justin S. Leitgeb
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
CHANGED
@@ -9,14 +9,14 @@ by storing the ids of previous tweets in a global pool which can easily be share
|
|
9
9
|
|
10
10
|
= Installation
|
11
11
|
|
12
|
-
sudo gem install osprey
|
12
|
+
sudo gem install jsl-osprey
|
13
13
|
|
14
14
|
= Usage
|
15
15
|
|
16
16
|
Basic usage of Osprey is simple, and more advanced usage is easily accomodated by the accepted options and the
|
17
17
|
ability to write custom backend modules.
|
18
18
|
|
19
|
-
In more basic cases, you can use Osprey as follows:
|
19
|
+
In more basic cases, you can use Osprey::Search (the main interface to Osprey) as follows:
|
20
20
|
|
21
21
|
require 'osprey'
|
22
22
|
|
@@ -35,6 +35,8 @@ Note that because this is done, in most cases "results" will be the same as "new
|
|
35
35
|
guarantee that results arrive in order, however, Osprey does checking to make sure that new_results really aren't
|
36
36
|
ones that we've seen before.
|
37
37
|
|
38
|
+
See the documentation for Osprey::Search for more information on providing options for the backend configuration of Osprey.
|
39
|
+
|
38
40
|
= Processing Details
|
39
41
|
|
40
42
|
Osprey implements a simple but effective algorithm for keeping track of which tweets are new and which have been seen before.
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
|
4
|
+
require 'rake'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
require 'rake/rdoctask'
|
7
|
+
|
8
|
+
require 'lib/osprey'
|
9
|
+
|
10
|
+
desc 'Test the plugin.'
|
11
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
12
|
+
t.spec_opts = ["--format", "progress", "--colour"]
|
13
|
+
t.libs << 'lib'
|
14
|
+
t.verbose = true
|
15
|
+
end
|
16
|
+
|
17
|
+
begin
|
18
|
+
require 'jeweler'
|
19
|
+
Jeweler::Tasks.new do |gemspec|
|
20
|
+
gemspec.name = "osprey"
|
21
|
+
gemspec.summary = "A Twitter API that keeps track of tweets you've seen"
|
22
|
+
gemspec.email = "justin@phq.org"
|
23
|
+
gemspec.homepage = "http://github.com/jsl/osprey"
|
24
|
+
gemspec.description = "Osprey interfaces with the Twitter search API and keeps track of tweets you've seen"
|
25
|
+
gemspec.authors = ["Justin Leitgeb"]
|
26
|
+
end
|
27
|
+
rescue LoadError
|
28
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "Run all the tests"
|
32
|
+
task :default => :spec
|
33
|
+
|
34
|
+
desc 'Generate documentation'
|
35
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
36
|
+
rdoc.rdoc_dir = 'rdoc'
|
37
|
+
rdoc.title = 'Osprey'
|
38
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
39
|
+
rdoc.rdoc_files.include('README.rdoc')
|
40
|
+
rdoc.rdoc_files.include('lib/osprey/**/*.rb')
|
41
|
+
end
|
42
|
+
|
data/VERSION.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Hash
|
2
|
+
# Returns a Hash containing only input keys.
|
3
|
+
# Method from merb-core.
|
4
|
+
def except(*rejected)
|
5
|
+
reject { |k,v| rejected.include?(k) }
|
6
|
+
end
|
7
|
+
|
8
|
+
def reverse_merge(other_hash)
|
9
|
+
other_hash.merge(self)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns a new hash containing only the input keys.
|
13
|
+
# Method from merb-core.
|
14
|
+
def only(*allowed)
|
15
|
+
reject { |k,v| !allowed.include?(k) }
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Osprey
|
2
|
+
|
3
|
+
# Container for sets of tweets.
|
4
|
+
class ResultSet < Array
|
5
|
+
attr_accessor :etag
|
6
|
+
|
7
|
+
# Returns all records. In most cases, this will be the same as the results
|
8
|
+
# in #new_records, since we add the id of the last tweet fetched to the query
|
9
|
+
# string automatically. If Twitter somehow sends us a Tweet that we saw in a
|
10
|
+
# previous fetch, however, this result will return all records indiscriminately
|
11
|
+
# while the method #new_records will be populated with tweets that are really
|
12
|
+
# ones that we haven't seen before.
|
13
|
+
def records
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns only records that are new in the most recent fetch.
|
18
|
+
def new_records
|
19
|
+
self.select{|r| r.new_record == true}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
module Osprey
|
2
|
+
|
3
|
+
# Primary interface to the Osprey Twitter search library.
|
4
|
+
class Search
|
5
|
+
attr_reader :term
|
6
|
+
|
7
|
+
DEFAULTS = {
|
8
|
+
:backend => {
|
9
|
+
:moneta_klass => 'Moneta::Memory',
|
10
|
+
},
|
11
|
+
:rpp => 50,
|
12
|
+
:preserved_tweet_ids => 10_000
|
13
|
+
} unless defined?(DEFAULTS)
|
14
|
+
|
15
|
+
# Initializes the Osprey::Search client.
|
16
|
+
#
|
17
|
+
# Usage (Basic):
|
18
|
+
#
|
19
|
+
# search = Osprey::Search.new(term, options)
|
20
|
+
# results = search.fetch
|
21
|
+
#
|
22
|
+
# Usage (Custom Backend):
|
23
|
+
#
|
24
|
+
# o = Osprey::Search.new('Swine Flu', { :backend => { :moneta_klass => 'Moneta::Memcache', :server => 'localhost:1978' } })
|
25
|
+
# results = o.fetch
|
26
|
+
#
|
27
|
+
# Options:
|
28
|
+
#
|
29
|
+
# The Osprey::Search library supports options for customizing the parameters that will be passed to Twitter as well
|
30
|
+
# as to the local backend for keeping track of state.
|
31
|
+
#
|
32
|
+
# - _backend_ - A hash of options which are passed directly to the Moneta class used as key-value store. The
|
33
|
+
# value for this option should be another Hash containing configuration options for the backend. Keys supported
|
34
|
+
# by the backend hash:
|
35
|
+
#
|
36
|
+
# - _moneta_backend_ - The backend used for storing the serialized representation of the last fetch of
|
37
|
+
# this query. Uses Moneta, a unified interface to key-value storage systems. This value may be a String,
|
38
|
+
# in which case the appropriate Moneta library will be automatically required, or a class constant. If a
|
39
|
+
# class constant is given, it is up to the calling user to require the appropriate Moneta library before referring
|
40
|
+
# to the constant in the initialization of Osprey::Search.
|
41
|
+
#
|
42
|
+
# - _other_options_ - Any other options given to the backend hash will be passed directly to the Moneta class
|
43
|
+
# used as key-value store for configuration. Please see the documentation for the appropriate Moneta class for
|
44
|
+
# options supported.
|
45
|
+
#
|
46
|
+
# - _preserved_tweet_ids_ - The number of Tweet ids that will be preserved. This ensures that we're able to detect if
|
47
|
+
# running different queries returns the same tweet in order to not mark that tweet as a new
|
48
|
+
# record. Choosing a higher number here will mean some additional processing time for each
|
49
|
+
# new tweet, and a small amount of increased storage. The default should be a decent compromise
|
50
|
+
# between performance needs while still not seeing duplicate tweets show up as new records.
|
51
|
+
#
|
52
|
+
# - _rpp_ - Requests per page. Determines the results to fetch from Twitter. Defaults to 50.
|
53
|
+
#
|
54
|
+
# - _since_id_ - Tells twitter to only give us results with an ID greater than the given ID. Supplied by
|
55
|
+
# default in URL string if previous results were found.
|
56
|
+
def initialize(term, options = { })
|
57
|
+
@term = term
|
58
|
+
@options = options.reverse_merge(DEFAULTS)
|
59
|
+
@backend = initialize_backend(@options[:backend][:moneta_klass], @options[:backend].except(:moneta_klass))
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns a Osprey::ResultSet object containing Osprey::Tweet objects for the tweets found for query.
|
63
|
+
def fetch
|
64
|
+
p_results = previous_results
|
65
|
+
|
66
|
+
res = Curl::Easy.perform(url(p_results))
|
67
|
+
|
68
|
+
if res.response_code == 200
|
69
|
+
parse_tweets(res, p_results)
|
70
|
+
else
|
71
|
+
$stderr.puts "Received invalid twitter response code of #{res.response_code}."
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
# Initializes the structure that keeps track of the Twitter ids that we've seen.
|
78
|
+
def initialize_backend(klass, options)
|
79
|
+
HashBack::Backend.new('Osprey', klass, options)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns an Array of ids for the Tweets in result
|
83
|
+
def twitter_ids_from_json_result(json)
|
84
|
+
json['results'].map{|r| r['id'].to_i }
|
85
|
+
end
|
86
|
+
|
87
|
+
def twitter_ids_in(id_list)
|
88
|
+
id_list
|
89
|
+
end
|
90
|
+
|
91
|
+
# Determines the etag from the request headers. Method from Paul Dix's Feedzirra.
|
92
|
+
#
|
93
|
+
# === Parameters
|
94
|
+
# [header<String>] Raw request header returned from the request
|
95
|
+
# === Returns
|
96
|
+
# A string of the etag or nil if it cannot be found in the headers.
|
97
|
+
def etag_from_header(header)
|
98
|
+
header =~ /.*ETag:\s(.*)\r/
|
99
|
+
$1
|
100
|
+
end
|
101
|
+
|
102
|
+
def parse_tweets(curl, p_results)
|
103
|
+
json = JSON.parse(curl.body_str)
|
104
|
+
|
105
|
+
res = Osprey::ResultSet.new
|
106
|
+
id_pool = twitter_id_pool
|
107
|
+
|
108
|
+
json['results'].each do |t|
|
109
|
+
new_record = p_results.detect{|rec| rec.twitter_id == t['id'] }.nil? && !id_pool.include?(t['id'])
|
110
|
+
res << Osprey::Tweet.new(t.merge(:new_record => new_record, :twitter_id => t['id']))
|
111
|
+
end
|
112
|
+
|
113
|
+
add_to_twitter_id_pool(res.new_records)
|
114
|
+
|
115
|
+
# Store the results from this fetch, unless this set is empty and the previous set is not empty.
|
116
|
+
if res.empty? && !p_results.nil?
|
117
|
+
res = p_results
|
118
|
+
res.each{|r| r.new_record = false}
|
119
|
+
end
|
120
|
+
|
121
|
+
@backend[url_key] = res
|
122
|
+
|
123
|
+
res
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns an Array of recently-fetched Twitter IDS, or an empty Array
|
127
|
+
# if the backend doesn't have any previous results.
|
128
|
+
def twitter_id_pool
|
129
|
+
# This is a hack to deal with the fact that the backend seems to return an empty Hash when
|
130
|
+
# a Moneta::Memory store has an uninitialized value. TODO - take a closer look at this later
|
131
|
+
# and see if Moneta needs to be patched or if it's something screwy in the way we're using it.
|
132
|
+
res = @backend[twitter_id_pool_key]
|
133
|
+
res.nil? || res == { } ? [ ] : res
|
134
|
+
end
|
135
|
+
|
136
|
+
# Adds the given new tweet ids to the twitter id pool so that subsequent requests,
|
137
|
+
# even if they're for other terms, won't see these tweets as new.
|
138
|
+
def add_to_twitter_id_pool(tweets)
|
139
|
+
pool = twitter_id_pool
|
140
|
+
@backend[twitter_id_pool_key] =
|
141
|
+
( pool | tweets.map{|t| t.twitter_id} ).sort.reverse.uniq[1..@options[:preserved_tweet_ids]]
|
142
|
+
end
|
143
|
+
|
144
|
+
def twitter_id_pool_key
|
145
|
+
%w[twitter id pool].join('-')
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns an Array of results from the previous fetch, or an empty
|
149
|
+
# Array if no previous results are detected.
|
150
|
+
def previous_results
|
151
|
+
@backend[url_key] || [ ]
|
152
|
+
end
|
153
|
+
|
154
|
+
# Returns the backend string that will be used for the storage of this term.
|
155
|
+
# Effectively namespaces the urls so that we can use the backend modules for
|
156
|
+
# storage of other things like a pool of recently-read twitter ids.
|
157
|
+
def url_key
|
158
|
+
term_hash = MD5.hexdigest(@term)
|
159
|
+
['term', term_hash].join('-')
|
160
|
+
end
|
161
|
+
|
162
|
+
# Returns the Twitter search URL for @term. Merges the last response ID into the query string
|
163
|
+
# if we have previous results for this query. This eliminates most duplication from previous
|
164
|
+
# results and decreases transfer size.
|
165
|
+
def url(previous_response)
|
166
|
+
url = "http://search.twitter.com/search.json?rpp=#{@options[:rpp]}&q=#{CGI.escape(@term)}"
|
167
|
+
|
168
|
+
unless previous_response.nil? || previous_response.empty?
|
169
|
+
last_response_id = previous_response.records.map{|r| r.twitter_id}.sort.last
|
170
|
+
url += "&since_id=#{last_response_id}"
|
171
|
+
end
|
172
|
+
|
173
|
+
url
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
end
|
data/lib/osprey/tweet.rb
ADDED
data/lib/osprey.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'singleton'
|
3
|
+
require 'curb'
|
4
|
+
require 'hashback'
|
5
|
+
require 'json'
|
6
|
+
require 'md5'
|
7
|
+
require 'memcache'
|
8
|
+
require 'ostruct'
|
9
|
+
require 'cgi'
|
10
|
+
|
11
|
+
lib_dirs = [ 'core_ext', 'osprey' ].map do |d|
|
12
|
+
File.join(File.dirname(__FILE__), d)
|
13
|
+
end
|
14
|
+
|
15
|
+
lib_dirs.each do |d|
|
16
|
+
Dir[File.join(d, "*.rb")].each {|file| require file }
|
17
|
+
end
|
data/osprey.gemspec
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{osprey}
|
5
|
+
s.version = "0.0.8.2"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Justin Leitgeb"]
|
9
|
+
s.date = %q{2009-05-05}
|
10
|
+
s.description = %q{Osprey interfaces with the Twitter search API and keeps track of tweets you've seen}
|
11
|
+
s.email = %q{justin@phq.org}
|
12
|
+
s.extra_rdoc_files = [
|
13
|
+
"README.rdoc"
|
14
|
+
]
|
15
|
+
|
16
|
+
s.files = ["lib/core_ext/array.rb", "lib/core_ext/hash.rb", "lib/osprey/result_set.rb",
|
17
|
+
"lib/osprey/search.rb", "lib/osprey/tweet.rb", "lib/osprey.rb", "LICENSE",
|
18
|
+
"osprey.gemspec", "Rakefile", "README.rdoc", "spec/fixtures/swine_flu1.json", "spec/fixtures/swine_flu2.json",
|
19
|
+
"spec/fixtures/swine_flu_result_set1.yml", "spec/fixtures/swine_flu_result_set2.yml",
|
20
|
+
"spec/osprey/result_set_spec.rb", "spec/osprey/search_spec.rb", "spec/osprey_spec.rb",
|
21
|
+
"spec/spec_helper.rb", "VERSION.yml"]
|
22
|
+
|
23
|
+
s.has_rdoc = true
|
24
|
+
s.homepage = %q{http://github.com/jsl/osprey}
|
25
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
26
|
+
s.require_paths = ["lib"]
|
27
|
+
s.rubygems_version = %q{1.3.1}
|
28
|
+
s.summary = %q{A Twitter API that keeps track of tweets you've seen}
|
29
|
+
s.test_files = ["spec/fixtures/swine_flu1.json", "spec/fixtures/swine_flu2.json",
|
30
|
+
"spec/fixtures/swine_flu_result_set1.yml", "spec/fixtures/swine_flu_result_set2.yml",
|
31
|
+
"spec/osprey/result_set_spec.rb", "spec/osprey/search_spec.rb", "spec/osprey_spec.rb", "spec/spec_helper.rb"]
|
32
|
+
|
33
|
+
s.extra_rdoc_files = [ "README.rdoc" ]
|
34
|
+
|
35
|
+
s.rdoc_options += [
|
36
|
+
'--title', 'Osprey',
|
37
|
+
'--main', 'README.rdoc',
|
38
|
+
'--line-numbers',
|
39
|
+
'--inline-source'
|
40
|
+
]
|
41
|
+
|
42
|
+
%w[ curb wycats-moneta hashback json memcache-client ].each do |dep|
|
43
|
+
s.add_dependency(dep)
|
44
|
+
end
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
48
|
+
s.specification_version = 2
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
{"results":[{"text":"RT @nicfish: Tracking Swine Flu with Microsoft Virtual Earth and Live Search http:\/\/bit.ly\/YqdDC --> sweet!","to_user_id":null,"from_user":"tameraclark","id":1701715308,"from_user_id":386286,"iso_language_code":"en","source":"<a href="http:\/\/www.tweetdeck.com\/">TweetDeck<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/188156012\/eye2_normal.jpg","created_at":"Tue, 05 May 2009 01:28:14 +0000"},{"text":"@keepsgettinbetr when did i worry about the swine flu","to_user_id":9477722,"to_user":"keepsgettinbetr","from_user":"Bayleeee","id":1701714956,"from_user_id":7978237,"iso_language_code":"en","source":"<a href="http:\/\/twitterfon.net\/">TwitterFon<\/a>","profile_image_url":"http:\/\/static.twitter.com\/images\/default_profile_normal.png","created_at":"Tue, 05 May 2009 01:28:12 +0000"},{"text":"RT @TelegraphNews: Swine flu: Mexico starts to ease virus restrictions http:\/\/tinyurl.com\/db6jff","to_user_id":null,"from_user":"lili_one","id":1701714620,"from_user_id":4481131,"iso_language_code":"en","source":"<a href="http:\/\/www.tweetdeck.com\/">TweetDeck<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/181901124\/31-01-07_1330_normal.jpg","created_at":"Tue, 05 May 2009 01:28:10 +0000"},{"text":"Up to the minute swine flu origins: the visual explanation!\nRT @tweetmeme Coconut Chutney: When pigs fly http:\/\/tinyurl.com\/d8cobj","to_user_id":null,"from_user":"hiddenground","id":1701714439,"from_user_id":4158379,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/66627032\/frau-freide_normal.jpg","created_at":"Tue, 05 May 2009 01:28:09 +0000"},{"text":"School is shut down! due to swine flu!! thats a good thing right?","to_user_id":null,"from_user":"moonbrella","id":1701714354,"from_user_id":14559662,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/189894422\/IMG00701_normal.JPG","created_at":"Tue, 05 May 2009 01:28:10 +0000"},{"text":"Blame it on the flu got u feelin blue, blame it on the swine got u feelin blind, blame it on the mex mex mex mex mex mexicans....","to_user_id":null,"from_user":"DJELOO","id":1701714238,"from_user_id":4513402,"iso_language_code":"en","source":"<a href="http:\/\/orangatame.com\/products\/twitterberry\/">TwitterBerry<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/133607145\/djeloowel_normal.jpg","created_at":"Tue, 05 May 2009 01:28:07 +0000"},{"text":"Swine Flu","to_user_id":null,"from_user":"friendbartrends","id":1701713717,"from_user_id":14573136,"source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/static.twitter.com\/images\/default_profile_normal.png","created_at":"Tue, 05 May 2009 01:28:04 +0000"},{"text":"Destroying swine flu","to_user_id":null,"from_user":"premierozone","id":1701713665,"from_user_id":15592670,"iso_language_code":"da","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/197468025\/images_normal.jpg","created_at":"Tue, 05 May 2009 01:28:04 +0000"},{"text":"@M_tm uh, finally, something more disturbing than swine flu...","to_user_id":125590,"to_user":"M_tm","from_user":"Funchilde","id":1701712780,"from_user_id":1983836,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/61959717\/DD_Oaxaca_Flower_normal.jpg","created_at":"Tue, 05 May 2009 01:27:58 +0000"},{"text":"Susie gave me a Lysol Hand Sanitizer that says "Protects from Swine Flu" (Haha) for the bracelet.","to_user_id":null,"from_user":"StayPositive_","id":1701712037,"from_user_id":15567837,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/197027649\/waiting_normal.jpg","created_at":"Tue, 05 May 2009 01:27:53 +0000"},{"text":"@danilogentili Swine Flu !!!!!","to_user_id":168227,"to_user":"danilogentili","from_user":"pannain","id":1701711989,"from_user_id":13123935,"iso_language_code":"eo","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/151854910\/20070408041551_nivertia06churras07-01069_normal.jpg","created_at":"Tue, 05 May 2009 01:27:53 +0000"},{"text":"realized that after swine flu we'll get Bear pox, followed by beaver fever, and ending with Mongoose Malaria.... Be on your toes!","to_user_id":null,"from_user":"BubbaStoned85","id":1701711830,"from_user_id":1580999,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/59851479\/n31700687_7014_normal.jpg","created_at":"Tue, 05 May 2009 01:27:52 +0000"},{"text":"+ "90 people get the swine flu and everyone wants to wear a face mask. Millions get AIDS and nobody wears a condom. Go figure."","to_user_id":null,"from_user":"gemmerzz","id":1701711644,"from_user_id":166576,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/88556721\/profpic2_lg_normal.png","created_at":"Tue, 05 May 2009 01:27:51 +0000"},{"text":"#swineflu 6 More Swine Flu Cases Confirmed on LI - LongIslandPress.com http:\/\/ad.vu\/bir4","to_user_id":null,"from_user":"News_SwineFlu","id":1701711527,"from_user_id":14562545,"iso_language_code":"en","source":"<a href="http:\/\/twitterfeed.com">twitterfeed<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/189807824\/1_normal.jpg","created_at":"Tue, 05 May 2009 01:27:50 +0000"},{"text":"That darn Swine Flu is getting a tad close for comfort! A school about twenty minutes from mine closed down for a few days tonight!","to_user_id":null,"from_user":"tylergraves2009","id":1701710705,"from_user_id":8288437,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/193624367\/100_1084_normal.jpg","created_at":"Tue, 05 May 2009 01:27:45 +0000"}],"since_id":0,"max_id":1701715308,"refresh_url":"?since_id=1701715308&q=swine+flu","results_per_page":15,"next_page":"?page=2&max_id=1701715308&q=swine+flu","completed_in":0.032499,"page":1,"query":"swine+flu"}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"results":[{"text":"School is shut down! due to swine flu!! thats a good thing right?","to_user_id":null,"from_user":"moonbrella","id":1701714354,"from_user_id":14559662,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/189894422\/IMG00701_normal.JPG","created_at":"Tue, 05 May 2009 01:28:10 +0000"},{"text":"Blame it on the flu got u feelin blue, blame it on the swine got u feelin blind, blame it on the mex mex mex mex mex mexicans....","to_user_id":null,"from_user":"DJELOO","id":1701714238,"from_user_id":4513402,"iso_language_code":"en","source":"<a href="http:\/\/orangatame.com\/products\/twitterberry\/">TwitterBerry<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/133607145\/djeloowel_normal.jpg","created_at":"Tue, 05 May 2009 01:28:07 +0000"},{"text":"Swine Flu","to_user_id":null,"from_user":"friendbartrends","id":1701713717,"from_user_id":14573136,"source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/static.twitter.com\/images\/default_profile_normal.png","created_at":"Tue, 05 May 2009 01:28:04 +0000"},{"text":"Destroying swine flu","to_user_id":null,"from_user":"premierozone","id":1701713665,"from_user_id":15592670,"iso_language_code":"da","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/197468025\/images_normal.jpg","created_at":"Tue, 05 May 2009 01:28:04 +0000"},{"text":"@M_tm uh, finally, something more disturbing than swine flu...","to_user_id":125590,"to_user":"M_tm","from_user":"Funchilde","id":1701712780,"from_user_id":1983836,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/61959717\/DD_Oaxaca_Flower_normal.jpg","created_at":"Tue, 05 May 2009 01:27:58 +0000"},{"text":"Susie gave me a Lysol Hand Sanitizer that says "Protects from Swine Flu" (Haha) for the bracelet.","to_user_id":null,"from_user":"StayPositive_","id":1701712037,"from_user_id":15567837,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/197027649\/waiting_normal.jpg","created_at":"Tue, 05 May 2009 01:27:53 +0000"},{"text":"@danilogentili Swine Flu !!!!!","to_user_id":168227,"to_user":"danilogentili","from_user":"pannain","id":1701711989,"from_user_id":13123935,"iso_language_code":"eo","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/151854910\/20070408041551_nivertia06churras07-01069_normal.jpg","created_at":"Tue, 05 May 2009 01:27:53 +0000"},{"text":"realized that after swine flu we'll get Bear pox, followed by beaver fever, and ending with Mongoose Malaria.... Be on your toes!","to_user_id":null,"from_user":"BubbaStoned85","id":1701711830,"from_user_id":1580999,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/59851479\/n31700687_7014_normal.jpg","created_at":"Tue, 05 May 2009 01:27:52 +0000"},{"text":"+ "90 people get the swine flu and everyone wants to wear a face mask. Millions get AIDS and nobody wears a condom. Go figure."","to_user_id":null,"from_user":"gemmerzz","id":1701711644,"from_user_id":166576,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/88556721\/profpic2_lg_normal.png","created_at":"Tue, 05 May 2009 01:27:51 +0000"},{"text":"#swineflu 6 More Swine Flu Cases Confirmed on LI - LongIslandPress.com http:\/\/ad.vu\/bir4","to_user_id":null,"from_user":"News_SwineFlu","id":1701711527,"from_user_id":14562545,"iso_language_code":"en","source":"<a href="http:\/\/twitterfeed.com">twitterfeed<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/189807824\/1_normal.jpg","created_at":"Tue, 05 May 2009 01:27:50 +0000"},{"text":"That darn Swine Flu is getting a tad close for comfort! A school about twenty minutes from mine closed down for a few days tonight!","to_user_id":null,"from_user":"tylergraves2009","id":1701710705,"from_user_id":8288437,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/193624367\/100_1084_normal.jpg","created_at":"Tue, 05 May 2009 01:27:45 +0000"},{"text":"Explaining to the children why they don't need to be terrified of swine flu, but why they really do need to wash their hands. #swineflu","to_user_id":null,"from_user":"jojobo","id":1701710268,"from_user_id":3617869,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/71116723\/jojobo_normal.jpg","created_at":"Tue, 05 May 2009 01:27:42 +0000"},{"text":"Another day locked up with Swine Flu outside. Just went to HomeDepot and more then 50 percent of clients have masks there.","to_user_id":null,"from_user":"dennisvdheijden","id":1701709964,"from_user_id":3362361,"iso_language_code":"en","source":"<a href="http:\/\/twitter.com\/">web<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/76497810\/picture_normal.jpg","created_at":"Tue, 05 May 2009 01:27:40 +0000"},{"text":"RT: @KYLking: Byron Center High School students celebrate 'swine break' after flu closes school for week http:\/\/tinyurl.com\/d2b3yh","to_user_id":null,"from_user":"creister","id":1701709832,"from_user_id":643746,"iso_language_code":"nl","source":"<a href="http:\/\/twitterfox.net\/">TwitterFox<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/79399738\/cami1_normal.jpg","created_at":"Tue, 05 May 2009 01:27:39 +0000"},{"text":"I know I said I was going to sleep but who sleeps when you can twitter Itslike an epidemic this twitter stuff it spread like the swine flu","to_user_id":null,"from_user":"chefjay1121","id":1701709797,"from_user_id":7400045,"iso_language_code":"en","source":"<a href="http:\/\/iconfactory.com\/software\/twitterrific">twitterrific<\/a>","profile_image_url":"http:\/\/s3.amazonaws.com\/twitter_production\/profile_images\/150699579\/for_my_baby_normal.jpg","created_at":"Tue, 05 May 2009 01:27:39 +0000"}],"since_id":0,"max_id":1701714354,"refresh_url":"?since_id=1701714354&q=swine+flu","results_per_page":15,"next_page":"?page=2&max_id=1701714354&q=swine+flu","completed_in":0.023306,"page":1,"query":"swine+flu"}
|
@@ -0,0 +1,200 @@
|
|
1
|
+
--- !seq:Osprey::ResultSet
|
2
|
+
- !ruby/object:Osprey::Tweet
|
3
|
+
table:
|
4
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/188156012/eye2_normal.jpg
|
5
|
+
:source: "<a href="http://www.tweetdeck.com/">TweetDeck</a>"
|
6
|
+
:created_at: Tue, 05 May 2009 01:28:14 +0000
|
7
|
+
:to_user_id:
|
8
|
+
:text: "RT @nicfish: Tracking Swine Flu with Microsoft Virtual Earth and Live Search http://bit.ly/YqdDC --> sweet!"
|
9
|
+
:new_record?: true
|
10
|
+
:from_user: tameraclark
|
11
|
+
:from_user_id: 386286
|
12
|
+
:twitter_id: 1701715308
|
13
|
+
:iso_language_code: en
|
14
|
+
:id: 1701715308
|
15
|
+
- !ruby/object:Osprey::Tweet
|
16
|
+
table:
|
17
|
+
:profile_image_url: http://static.twitter.com/images/default_profile_normal.png
|
18
|
+
:source: "<a href="http://twitterfon.net/">TwitterFon</a>"
|
19
|
+
:created_at: Tue, 05 May 2009 01:28:12 +0000
|
20
|
+
:to_user_id: 9477722
|
21
|
+
:text: "@keepsgettinbetr when did i worry about the swine flu"
|
22
|
+
:new_record?: true
|
23
|
+
:from_user: Bayleeee
|
24
|
+
:from_user_id: 7978237
|
25
|
+
:twitter_id: 1701714956
|
26
|
+
:to_user: keepsgettinbetr
|
27
|
+
:iso_language_code: en
|
28
|
+
:id: 1701714956
|
29
|
+
- !ruby/object:Osprey::Tweet
|
30
|
+
table:
|
31
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/181901124/31-01-07_1330_normal.jpg
|
32
|
+
:source: "<a href="http://www.tweetdeck.com/">TweetDeck</a>"
|
33
|
+
:created_at: Tue, 05 May 2009 01:28:10 +0000
|
34
|
+
:to_user_id:
|
35
|
+
:text: "RT @TelegraphNews: Swine flu: Mexico starts to ease virus restrictions http://tinyurl.com/db6jff"
|
36
|
+
:new_record?: true
|
37
|
+
:from_user: lili_one
|
38
|
+
:from_user_id: 4481131
|
39
|
+
:twitter_id: 1701714620
|
40
|
+
:iso_language_code: en
|
41
|
+
:id: 1701714620
|
42
|
+
- !ruby/object:Osprey::Tweet
|
43
|
+
table:
|
44
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/66627032/frau-freide_normal.jpg
|
45
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
46
|
+
:created_at: Tue, 05 May 2009 01:28:09 +0000
|
47
|
+
:to_user_id:
|
48
|
+
:text: |-
|
49
|
+
Up to the minute swine flu origins: the visual explanation!
|
50
|
+
RT @tweetmeme Coconut Chutney: When pigs fly http://tinyurl.com/d8cobj
|
51
|
+
:new_record?: true
|
52
|
+
:from_user: hiddenground
|
53
|
+
:from_user_id: 4158379
|
54
|
+
:twitter_id: 1701714439
|
55
|
+
:iso_language_code: en
|
56
|
+
:id: 1701714439
|
57
|
+
- !ruby/object:Osprey::Tweet
|
58
|
+
table:
|
59
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/189894422/IMG00701_normal.JPG
|
60
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
61
|
+
:created_at: Tue, 05 May 2009 01:28:10 +0000
|
62
|
+
:to_user_id:
|
63
|
+
:text: School is shut down! due to swine flu!! thats a good thing right?
|
64
|
+
:new_record?: true
|
65
|
+
:from_user: moonbrella
|
66
|
+
:from_user_id: 14559662
|
67
|
+
:twitter_id: 1701714354
|
68
|
+
:iso_language_code: en
|
69
|
+
:id: 1701714354
|
70
|
+
- !ruby/object:Osprey::Tweet
|
71
|
+
table:
|
72
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/133607145/djeloowel_normal.jpg
|
73
|
+
:source: "<a href="http://orangatame.com/products/twitterberry/">TwitterBerry</a>"
|
74
|
+
:created_at: Tue, 05 May 2009 01:28:07 +0000
|
75
|
+
:to_user_id:
|
76
|
+
:text: Blame it on the flu got u feelin blue, blame it on the swine got u feelin blind, blame it on the mex mex mex mex mex mexicans....
|
77
|
+
:new_record?: true
|
78
|
+
:from_user: DJELOO
|
79
|
+
:from_user_id: 4513402
|
80
|
+
:twitter_id: 1701714238
|
81
|
+
:iso_language_code: en
|
82
|
+
:id: 1701714238
|
83
|
+
- !ruby/object:Osprey::Tweet
|
84
|
+
table:
|
85
|
+
:profile_image_url: http://static.twitter.com/images/default_profile_normal.png
|
86
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
87
|
+
:created_at: Tue, 05 May 2009 01:28:04 +0000
|
88
|
+
:to_user_id:
|
89
|
+
:text: Swine Flu
|
90
|
+
:new_record?: true
|
91
|
+
:from_user: friendbartrends
|
92
|
+
:from_user_id: 14573136
|
93
|
+
:twitter_id: 1701713717
|
94
|
+
:id: 1701713717
|
95
|
+
- !ruby/object:Osprey::Tweet
|
96
|
+
table:
|
97
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/197468025/images_normal.jpg
|
98
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
99
|
+
:created_at: Tue, 05 May 2009 01:28:04 +0000
|
100
|
+
:to_user_id:
|
101
|
+
:text: Destroying swine flu
|
102
|
+
:new_record?: true
|
103
|
+
:from_user: premierozone
|
104
|
+
:from_user_id: 15592670
|
105
|
+
:twitter_id: 1701713665
|
106
|
+
:iso_language_code: da
|
107
|
+
:id: 1701713665
|
108
|
+
- !ruby/object:Osprey::Tweet
|
109
|
+
table:
|
110
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/61959717/DD_Oaxaca_Flower_normal.jpg
|
111
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
112
|
+
:created_at: Tue, 05 May 2009 01:27:58 +0000
|
113
|
+
:to_user_id: 125590
|
114
|
+
:text: "@M_tm uh, finally, something more disturbing than swine flu..."
|
115
|
+
:new_record?: true
|
116
|
+
:from_user: Funchilde
|
117
|
+
:from_user_id: 1983836
|
118
|
+
:twitter_id: 1701712780
|
119
|
+
:to_user: M_tm
|
120
|
+
:iso_language_code: en
|
121
|
+
:id: 1701712780
|
122
|
+
- !ruby/object:Osprey::Tweet
|
123
|
+
table:
|
124
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/197027649/waiting_normal.jpg
|
125
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
126
|
+
:created_at: Tue, 05 May 2009 01:27:53 +0000
|
127
|
+
:to_user_id:
|
128
|
+
:text: Susie gave me a Lysol Hand Sanitizer that says "Protects from Swine Flu" (Haha) for the bracelet.
|
129
|
+
:new_record?: true
|
130
|
+
:from_user: StayPositive_
|
131
|
+
:from_user_id: 15567837
|
132
|
+
:twitter_id: 1701712037
|
133
|
+
:iso_language_code: en
|
134
|
+
:id: 1701712037
|
135
|
+
- !ruby/object:Osprey::Tweet
|
136
|
+
table:
|
137
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/151854910/20070408041551_nivertia06churras07-01069_normal.jpg
|
138
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
139
|
+
:created_at: Tue, 05 May 2009 01:27:53 +0000
|
140
|
+
:to_user_id: 168227
|
141
|
+
:text: "@danilogentili Swine Flu !!!!!"
|
142
|
+
:new_record?: true
|
143
|
+
:from_user: pannain
|
144
|
+
:from_user_id: 13123935
|
145
|
+
:twitter_id: 1701711989
|
146
|
+
:to_user: danilogentili
|
147
|
+
:iso_language_code: eo
|
148
|
+
:id: 1701711989
|
149
|
+
- !ruby/object:Osprey::Tweet
|
150
|
+
table:
|
151
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/59851479/n31700687_7014_normal.jpg
|
152
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
153
|
+
:created_at: Tue, 05 May 2009 01:27:52 +0000
|
154
|
+
:to_user_id:
|
155
|
+
:text: realized that after swine flu we'll get Bear pox, followed by beaver fever, and ending with Mongoose Malaria.... Be on your toes!
|
156
|
+
:new_record?: true
|
157
|
+
:from_user: BubbaStoned85
|
158
|
+
:from_user_id: 1580999
|
159
|
+
:twitter_id: 1701711830
|
160
|
+
:iso_language_code: en
|
161
|
+
:id: 1701711830
|
162
|
+
- !ruby/object:Osprey::Tweet
|
163
|
+
table:
|
164
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/88556721/profpic2_lg_normal.png
|
165
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
166
|
+
:created_at: Tue, 05 May 2009 01:27:51 +0000
|
167
|
+
:to_user_id:
|
168
|
+
:text: + "90 people get the swine flu and everyone wants to wear a face mask. Millions get AIDS and nobody wears a condom. Go figure."
|
169
|
+
:new_record?: true
|
170
|
+
:from_user: gemmerzz
|
171
|
+
:from_user_id: 166576
|
172
|
+
:twitter_id: 1701711644
|
173
|
+
:iso_language_code: en
|
174
|
+
:id: 1701711644
|
175
|
+
- !ruby/object:Osprey::Tweet
|
176
|
+
table:
|
177
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/189807824/1_normal.jpg
|
178
|
+
:source: "<a href="http://twitterfeed.com">twitterfeed</a>"
|
179
|
+
:created_at: Tue, 05 May 2009 01:27:50 +0000
|
180
|
+
:to_user_id:
|
181
|
+
:text: "#swineflu 6 More Swine Flu Cases Confirmed on LI - LongIslandPress.com http://ad.vu/bir4"
|
182
|
+
:new_record?: true
|
183
|
+
:from_user: News_SwineFlu
|
184
|
+
:from_user_id: 14562545
|
185
|
+
:twitter_id: 1701711527
|
186
|
+
:iso_language_code: en
|
187
|
+
:id: 1701711527
|
188
|
+
- !ruby/object:Osprey::Tweet
|
189
|
+
table:
|
190
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/193624367/100_1084_normal.jpg
|
191
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
192
|
+
:created_at: Tue, 05 May 2009 01:27:45 +0000
|
193
|
+
:to_user_id:
|
194
|
+
:text: That darn Swine Flu is getting a tad close for comfort! A school about twenty minutes from mine closed down for a few days tonight!
|
195
|
+
:new_record?: true
|
196
|
+
:from_user: tylergraves2009
|
197
|
+
:from_user_id: 8288437
|
198
|
+
:twitter_id: 1701710705
|
199
|
+
:iso_language_code: en
|
200
|
+
:id: 1701710705
|
@@ -0,0 +1,197 @@
|
|
1
|
+
--- !seq:Osprey::ResultSet
|
2
|
+
- !ruby/object:Osprey::Tweet
|
3
|
+
table:
|
4
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
5
|
+
:from_user_id: 14559662
|
6
|
+
:iso_language_code: en
|
7
|
+
:new_record: false
|
8
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/189894422/IMG00701_normal.JPG
|
9
|
+
:twitter_id: 1701714354
|
10
|
+
:text: School is shut down! due to swine flu!! thats a good thing right?
|
11
|
+
:created_at: Tue, 05 May 2009 01:28:10 +0000
|
12
|
+
:to_user_id:
|
13
|
+
:id: 1701714354
|
14
|
+
:from_user: moonbrella
|
15
|
+
- !ruby/object:Osprey::Tweet
|
16
|
+
table:
|
17
|
+
:source: "<a href="http://orangatame.com/products/twitterberry/">TwitterBerry</a>"
|
18
|
+
:from_user_id: 4513402
|
19
|
+
:iso_language_code: en
|
20
|
+
:new_record: false
|
21
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/133607145/djeloowel_normal.jpg
|
22
|
+
:twitter_id: 1701714238
|
23
|
+
:text: Blame it on the flu got u feelin blue, blame it on the swine got u feelin blind, blame it on the mex mex mex mex mex mexicans....
|
24
|
+
:created_at: Tue, 05 May 2009 01:28:07 +0000
|
25
|
+
:to_user_id:
|
26
|
+
:id: 1701714238
|
27
|
+
:from_user: DJELOO
|
28
|
+
- !ruby/object:Osprey::Tweet
|
29
|
+
table:
|
30
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
31
|
+
:from_user_id: 14573136
|
32
|
+
:new_record: false
|
33
|
+
:profile_image_url: http://static.twitter.com/images/default_profile_normal.png
|
34
|
+
:twitter_id: 1701713717
|
35
|
+
:text: Swine Flu
|
36
|
+
:created_at: Tue, 05 May 2009 01:28:04 +0000
|
37
|
+
:to_user_id:
|
38
|
+
:id: 1701713717
|
39
|
+
:from_user: friendbartrends
|
40
|
+
- !ruby/object:Osprey::Tweet
|
41
|
+
table:
|
42
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
43
|
+
:from_user_id: 15592670
|
44
|
+
:iso_language_code: da
|
45
|
+
:new_record: false
|
46
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/197468025/images_normal.jpg
|
47
|
+
:twitter_id: 1701713665
|
48
|
+
:text: Destroying swine flu
|
49
|
+
:created_at: Tue, 05 May 2009 01:28:04 +0000
|
50
|
+
:to_user_id:
|
51
|
+
:id: 1701713665
|
52
|
+
:from_user: premierozone
|
53
|
+
- !ruby/object:Osprey::Tweet
|
54
|
+
table:
|
55
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
56
|
+
:from_user_id: 1983836
|
57
|
+
:iso_language_code: en
|
58
|
+
:new_record: false
|
59
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/61959717/DD_Oaxaca_Flower_normal.jpg
|
60
|
+
:twitter_id: 1701712780
|
61
|
+
:text: "@M_tm uh, finally, something more disturbing than swine flu..."
|
62
|
+
:created_at: Tue, 05 May 2009 01:27:58 +0000
|
63
|
+
:to_user_id: 125590
|
64
|
+
:to_user: M_tm
|
65
|
+
:id: 1701712780
|
66
|
+
:from_user: Funchilde
|
67
|
+
- !ruby/object:Osprey::Tweet
|
68
|
+
table:
|
69
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
70
|
+
:from_user_id: 15567837
|
71
|
+
:iso_language_code: en
|
72
|
+
:new_record: false
|
73
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/197027649/waiting_normal.jpg
|
74
|
+
:twitter_id: 1701712037
|
75
|
+
:text: Susie gave me a Lysol Hand Sanitizer that says "Protects from Swine Flu" (Haha) for the bracelet.
|
76
|
+
:created_at: Tue, 05 May 2009 01:27:53 +0000
|
77
|
+
:to_user_id:
|
78
|
+
:id: 1701712037
|
79
|
+
:from_user: StayPositive_
|
80
|
+
- !ruby/object:Osprey::Tweet
|
81
|
+
table:
|
82
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
83
|
+
:from_user_id: 13123935
|
84
|
+
:iso_language_code: eo
|
85
|
+
:new_record: false
|
86
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/151854910/20070408041551_nivertia06churras07-01069_normal.jpg
|
87
|
+
:twitter_id: 1701711989
|
88
|
+
:text: "@danilogentili Swine Flu !!!!!"
|
89
|
+
:created_at: Tue, 05 May 2009 01:27:53 +0000
|
90
|
+
:to_user_id: 168227
|
91
|
+
:to_user: danilogentili
|
92
|
+
:id: 1701711989
|
93
|
+
:from_user: pannain
|
94
|
+
- !ruby/object:Osprey::Tweet
|
95
|
+
table:
|
96
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
97
|
+
:from_user_id: 1580999
|
98
|
+
:iso_language_code: en
|
99
|
+
:new_record: false
|
100
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/59851479/n31700687_7014_normal.jpg
|
101
|
+
:twitter_id: 1701711830
|
102
|
+
:text: realized that after swine flu we'll get Bear pox, followed by beaver fever, and ending with Mongoose Malaria.... Be on your toes!
|
103
|
+
:created_at: Tue, 05 May 2009 01:27:52 +0000
|
104
|
+
:to_user_id:
|
105
|
+
:id: 1701711830
|
106
|
+
:from_user: BubbaStoned85
|
107
|
+
- !ruby/object:Osprey::Tweet
|
108
|
+
table:
|
109
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
110
|
+
:from_user_id: 166576
|
111
|
+
:iso_language_code: en
|
112
|
+
:new_record: false
|
113
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/88556721/profpic2_lg_normal.png
|
114
|
+
:twitter_id: 1701711644
|
115
|
+
:text: + "90 people get the swine flu and everyone wants to wear a face mask. Millions get AIDS and nobody wears a condom. Go figure."
|
116
|
+
:created_at: Tue, 05 May 2009 01:27:51 +0000
|
117
|
+
:to_user_id:
|
118
|
+
:id: 1701711644
|
119
|
+
:from_user: gemmerzz
|
120
|
+
- !ruby/object:Osprey::Tweet
|
121
|
+
table:
|
122
|
+
:source: "<a href="http://twitterfeed.com">twitterfeed</a>"
|
123
|
+
:from_user_id: 14562545
|
124
|
+
:iso_language_code: en
|
125
|
+
:new_record: false
|
126
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/189807824/1_normal.jpg
|
127
|
+
:twitter_id: 1701711527
|
128
|
+
:text: "#swineflu 6 More Swine Flu Cases Confirmed on LI - LongIslandPress.com http://ad.vu/bir4"
|
129
|
+
:created_at: Tue, 05 May 2009 01:27:50 +0000
|
130
|
+
:to_user_id:
|
131
|
+
:id: 1701711527
|
132
|
+
:from_user: News_SwineFlu
|
133
|
+
- !ruby/object:Osprey::Tweet
|
134
|
+
table:
|
135
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
136
|
+
:from_user_id: 8288437
|
137
|
+
:iso_language_code: en
|
138
|
+
:new_record: false
|
139
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/193624367/100_1084_normal.jpg
|
140
|
+
:twitter_id: 1701710705
|
141
|
+
:text: That darn Swine Flu is getting a tad close for comfort! A school about twenty minutes from mine closed down for a few days tonight!
|
142
|
+
:created_at: Tue, 05 May 2009 01:27:45 +0000
|
143
|
+
:to_user_id:
|
144
|
+
:id: 1701710705
|
145
|
+
:from_user: tylergraves2009
|
146
|
+
- !ruby/object:Osprey::Tweet
|
147
|
+
table:
|
148
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
149
|
+
:from_user_id: 3617869
|
150
|
+
:iso_language_code: en
|
151
|
+
:new_record: true
|
152
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/71116723/jojobo_normal.jpg
|
153
|
+
:twitter_id: 1701710268
|
154
|
+
:text: "Explaining to the children why they don't need to be terrified of swine flu, but why they really do need to wash their hands. #swineflu"
|
155
|
+
:created_at: Tue, 05 May 2009 01:27:42 +0000
|
156
|
+
:to_user_id:
|
157
|
+
:id: 1701710268
|
158
|
+
:from_user: jojobo
|
159
|
+
- !ruby/object:Osprey::Tweet
|
160
|
+
table:
|
161
|
+
:source: "<a href="http://twitter.com/">web</a>"
|
162
|
+
:from_user_id: 3362361
|
163
|
+
:iso_language_code: en
|
164
|
+
:new_record: true
|
165
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/76497810/picture_normal.jpg
|
166
|
+
:twitter_id: 1701709964
|
167
|
+
:text: Another day locked up with Swine Flu outside. Just went to HomeDepot and more then 50 percent of clients have masks there.
|
168
|
+
:created_at: Tue, 05 May 2009 01:27:40 +0000
|
169
|
+
:to_user_id:
|
170
|
+
:id: 1701709964
|
171
|
+
:from_user: dennisvdheijden
|
172
|
+
- !ruby/object:Osprey::Tweet
|
173
|
+
table:
|
174
|
+
:source: "<a href="http://twitterfox.net/">TwitterFox</a>"
|
175
|
+
:from_user_id: 643746
|
176
|
+
:iso_language_code: nl
|
177
|
+
:new_record: true
|
178
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/79399738/cami1_normal.jpg
|
179
|
+
:twitter_id: 1701709832
|
180
|
+
:text: "RT: @KYLking: Byron Center High School students celebrate 'swine break' after flu closes school for week http://tinyurl.com/d2b3yh"
|
181
|
+
:created_at: Tue, 05 May 2009 01:27:39 +0000
|
182
|
+
:to_user_id:
|
183
|
+
:id: 1701709832
|
184
|
+
:from_user: creister
|
185
|
+
- !ruby/object:Osprey::Tweet
|
186
|
+
table:
|
187
|
+
:source: "<a href="http://iconfactory.com/software/twitterrific">twitterrific</a>"
|
188
|
+
:from_user_id: 7400045
|
189
|
+
:iso_language_code: en
|
190
|
+
:new_record: true
|
191
|
+
:profile_image_url: http://s3.amazonaws.com/twitter_production/profile_images/150699579/for_my_baby_normal.jpg
|
192
|
+
:twitter_id: 1701709797
|
193
|
+
:text: I know I said I was going to sleep but who sleeps when you can twitter Itslike an epidemic this twitter stuff it spread like the swine flu
|
194
|
+
:created_at: Tue, 05 May 2009 01:27:39 +0000
|
195
|
+
:to_user_id:
|
196
|
+
:id: 1701709797
|
197
|
+
:from_user: chefjay1121
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[ .. spec_helper ])
|
2
|
+
|
3
|
+
describe Osprey::ResultSet do
|
4
|
+
before do
|
5
|
+
@rs = YAML.load_file(File.join(File.dirname(__FILE__), %w[.. fixtures swine_flu_result_set2.yml]))
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should return 4 results for #new_records" do
|
9
|
+
@rs.new_records.size.should == 4
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should return 15 results for #records" do
|
13
|
+
@rs.records.size.should == 15
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[ .. spec_helper ])
|
2
|
+
|
3
|
+
describe Osprey::Search do
|
4
|
+
describe "initialization" do
|
5
|
+
it "should initialize without error" do
|
6
|
+
Osprey::Search.new('bar')
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should create a new instance of the default backend" do
|
10
|
+
Osprey::Search.new('bar').instance_variable_get(:@backend).should be_a(HashBack::Backend)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should set the attr accessor for the term" do
|
15
|
+
tr = Osprey::Search.new('foo')
|
16
|
+
tr.term.should == 'foo'
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#fetch" do
|
20
|
+
before do
|
21
|
+
@tr = Osprey::Search.new('swine flu')
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "when the backend does not contain a previous result set" do
|
25
|
+
before do
|
26
|
+
@curl = mock('curl')
|
27
|
+
@curl.expects(:response_code).returns(200)
|
28
|
+
@swine_flu_json = File.read(File.join(File.dirname(__FILE__), %w[.. fixtures swine_flu1.json]))
|
29
|
+
@curl.expects(:body_str).returns(@swine_flu_json)
|
30
|
+
Curl::Easy.expects(:perform).with('http://search.twitter.com/search.json?rpp=50&q=swine+flu').returns(@curl)
|
31
|
+
@results = @tr.fetch
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "on the initial request of a term" do
|
35
|
+
it "should return a Osprey::ResultSet" do
|
36
|
+
@results.should be_a(Osprey::ResultSet)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should contain 15 results" do
|
40
|
+
@results.size.should == 15
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should contain all Osprey::Tweet items" do
|
44
|
+
@results.each{|t| t.should be_a(Osprey::Tweet) }
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should have all results respond affirmatively to new_record" do
|
48
|
+
@results.each{|t| t.new_record.should be_true}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "when the backend does contain a previous result set" do
|
54
|
+
before do
|
55
|
+
@curl.expects(:response_code).returns(200)
|
56
|
+
@backend = mock('backend')
|
57
|
+
@backend.expects(:[]).with('twitter-id-pool').twice
|
58
|
+
@backend.expects(:[]).with(@tr.__send__(:url_key)).returns(YAML.load_file(File.join(File.dirname(__FILE__), %w[.. fixtures swine_flu_result_set1.yml])))
|
59
|
+
@backend.expects(:[]=).twice
|
60
|
+
@tr.instance_variable_set(:@backend, @backend)
|
61
|
+
@swine_flu_json = File.read(File.join(File.dirname(__FILE__), %w[.. fixtures swine_flu2.json]))
|
62
|
+
@curl.expects(:body_str).returns(@swine_flu_json)
|
63
|
+
Curl::Easy.expects(:perform).with('http://search.twitter.com/search.json?rpp=50&q=swine+flu&since_id=1701715308').returns(@curl)
|
64
|
+
@results = @tr.fetch
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should have 4 records that are not marked as new" do
|
68
|
+
@results.select{|r| r.new_record }.size.should == 4
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "when feed ids are listed in the pool" do
|
73
|
+
before do
|
74
|
+
@curl.expects(:response_code).returns(200)
|
75
|
+
@backend = mock('backend')
|
76
|
+
@backend.expects(:[]).with('twitter-id-pool').twice.returns([1701715308, 1701714956])
|
77
|
+
@backend.expects(:[]).with(@tr.__send__(:url_key)).returns(nil)
|
78
|
+
@backend.expects(:[]=).twice
|
79
|
+
@tr.instance_variable_set(:@backend, @backend)
|
80
|
+
@swine_flu_json = File.read(File.join(File.dirname(__FILE__), %w[.. fixtures swine_flu1.json]))
|
81
|
+
@curl.expects(:body_str).returns(@swine_flu_json)
|
82
|
+
Curl::Easy.expects(:perform).with('http://search.twitter.com/search.json?rpp=50&q=swine+flu').returns(@curl)
|
83
|
+
@results = @tr.fetch
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should return 13 elements in new_records" do
|
87
|
+
@results.new_records.size.should == 13
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "#url_key" do
|
93
|
+
it "should create a key with the MD5 hexdigest of the term" do
|
94
|
+
term = 'swine flu'
|
95
|
+
@tr = Osprey::Search.new(term)
|
96
|
+
@tr.__send__(:url_key).should == "term-#{MD5.hexdigest(term)}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#url" do
|
101
|
+
before do
|
102
|
+
@tr = Osprey::Search.new('swine flu')
|
103
|
+
@results = YAML.load_file(File.join(File.dirname(__FILE__), %w[.. fixtures swine_flu_result_set1.yml]))
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should include the greatest ID in since_if of the given set if results are present" do
|
107
|
+
url = @tr.__send__(:url, @results)
|
108
|
+
url.should =~ /since_id=1701715308/
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should not contain since_id if the previous results are nil" do
|
112
|
+
url = @tr.__send__(:url, nil)
|
113
|
+
url.should_not =~ /since_id/
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should not contain since_id if the previous results contain no records" do
|
117
|
+
url = @tr.__send__(:url, [])
|
118
|
+
url.should_not =~ /since_id/
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should contain an option rpp (results per page) that is set to the @options[:rpp] value" do
|
122
|
+
url = @tr.__send__(:url, [])
|
123
|
+
url.should =~ /rpp=50/
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/spec/osprey_spec.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'mocha'
|
3
|
+
require 'spec'
|
4
|
+
|
5
|
+
require File.join(File.dirname(__FILE__), %w[.. lib osprey])
|
6
|
+
|
7
|
+
Spec::Runner.configure do |config|
|
8
|
+
config.mock_with(:mocha)
|
9
|
+
end
|
10
|
+
|
11
|
+
shared_examples_for "all backends" do
|
12
|
+
it "should respond to #get" do
|
13
|
+
@backend.should respond_to(:get)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should respond to #set" do
|
17
|
+
@backend.should respond_to(:set)
|
18
|
+
end
|
19
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsl-osprey
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.8
|
4
|
+
version: 0.0.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Leitgeb
|
@@ -71,7 +71,25 @@ extensions: []
|
|
71
71
|
extra_rdoc_files:
|
72
72
|
- README.rdoc
|
73
73
|
files:
|
74
|
+
- lib/core_ext/array.rb
|
75
|
+
- lib/core_ext/hash.rb
|
76
|
+
- lib/osprey/result_set.rb
|
77
|
+
- lib/osprey/search.rb
|
78
|
+
- lib/osprey/tweet.rb
|
79
|
+
- lib/osprey.rb
|
80
|
+
- LICENSE
|
81
|
+
- osprey.gemspec
|
82
|
+
- Rakefile
|
74
83
|
- README.rdoc
|
84
|
+
- spec/fixtures/swine_flu1.json
|
85
|
+
- spec/fixtures/swine_flu2.json
|
86
|
+
- spec/fixtures/swine_flu_result_set1.yml
|
87
|
+
- spec/fixtures/swine_flu_result_set2.yml
|
88
|
+
- spec/osprey/result_set_spec.rb
|
89
|
+
- spec/osprey/search_spec.rb
|
90
|
+
- spec/osprey_spec.rb
|
91
|
+
- spec/spec_helper.rb
|
92
|
+
- VERSION.yml
|
75
93
|
has_rdoc: true
|
76
94
|
homepage: http://github.com/jsl/osprey
|
77
95
|
post_install_message:
|
@@ -104,5 +122,12 @@ rubygems_version: 1.2.0
|
|
104
122
|
signing_key:
|
105
123
|
specification_version: 2
|
106
124
|
summary: A Twitter API that keeps track of tweets you've seen
|
107
|
-
test_files:
|
108
|
-
|
125
|
+
test_files:
|
126
|
+
- spec/fixtures/swine_flu1.json
|
127
|
+
- spec/fixtures/swine_flu2.json
|
128
|
+
- spec/fixtures/swine_flu_result_set1.yml
|
129
|
+
- spec/fixtures/swine_flu_result_set2.yml
|
130
|
+
- spec/osprey/result_set_spec.rb
|
131
|
+
- spec/osprey/search_spec.rb
|
132
|
+
- spec/osprey_spec.rb
|
133
|
+
- spec/spec_helper.rb
|