jsl-osprey 0.0.8 → 0.0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|