tweetstream 0.3.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of tweetstream might be problematic. Click here for more details.
- data/README.rdoc +35 -11
- data/RELEASE_NOTES.rdoc +5 -0
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/examples/growl_daemon.rb +14 -0
- data/lib/tweetstream/client.rb +95 -29
- data/lib/tweetstream/daemon.rb +2 -2
- data/lib/tweetstream/hash.rb +4 -2
- data/lib/tweetstream/parsers/active_support.rb +11 -0
- data/lib/tweetstream/parsers/json_gem.rb +11 -0
- data/lib/tweetstream/parsers/json_pure.rb +11 -0
- data/lib/tweetstream/parsers/yajl.rb +11 -0
- data/lib/tweetstream/status.rb +4 -0
- data/lib/tweetstream/user.rb +3 -1
- data/lib/tweetstream.rb +10 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/tweetstream/client_spec.rb +92 -69
- data/spec/tweetstream/parser_spec.rb +39 -0
- data/spec/tweetstream/status_spec.rb +6 -0
- metadata +13 -4
data/README.rdoc
CHANGED
@@ -4,16 +4,9 @@ TweetStream provides simple Ruby access to Twitter's Streaming API
|
|
4
4
|
(http://apiwiki.twitter.com/Streaming-API-Documentation).
|
5
5
|
|
6
6
|
== Installation
|
7
|
-
|
8
|
-
The TweetStream gem is available on GitHub and Gemcutter. To get the
|
9
|
-
latest gem from GitHub:
|
10
|
-
|
11
|
-
gem sources -a http://gems.github.com/
|
12
|
-
gem install intridea-tweetstream
|
13
7
|
|
14
8
|
To install from Gemcutter:
|
15
9
|
|
16
|
-
gem sources -a http://gemcutter.org/
|
17
10
|
gem install tweetstream
|
18
11
|
|
19
12
|
== Usage
|
@@ -47,6 +40,18 @@ user ids:
|
|
47
40
|
The methods available to TweetStream::Client will be kept in parity
|
48
41
|
with the methods available on the Streaming API wiki page.
|
49
42
|
|
43
|
+
== Swappable JSON Parsing
|
44
|
+
|
45
|
+
As of version 1.0, TweetStream supports swappable JSON backends for
|
46
|
+
parsing the Tweets. These are specified when you initialize the
|
47
|
+
client or daemon by passing it in as the last argument:
|
48
|
+
|
49
|
+
# Parse tweets using Yajl-Ruby
|
50
|
+
TweetStream::Client.new('abc','def',:yajl) # ...
|
51
|
+
|
52
|
+
Available options are <tt>:yajl</tt>, <tt>:json_gem</tt> (default),
|
53
|
+
<tt>:json_pure</tt>, and <tt>:active_support</tt>.
|
54
|
+
|
50
55
|
== Handling Deletes and Rate Limitations
|
51
56
|
|
52
57
|
Sometimes the Streaming API will send messages other than statuses.
|
@@ -90,18 +95,37 @@ Twitter recommends honoring deletions as quickly as possible, and
|
|
90
95
|
you would likely be wise to integrate this functionality into your
|
91
96
|
application.
|
92
97
|
|
98
|
+
== Errors and Reconnecting
|
99
|
+
|
100
|
+
TweetStream uses EventMachine to connect to the Twitter Streaming
|
101
|
+
API, and attempts to honor Twitter's guidelines in terms of automatic
|
102
|
+
reconnection. When Twitter becomes unavailable, the block specified
|
103
|
+
by you in <tt>on_error</tt> will be called. Note that this does not
|
104
|
+
indicate something is actually wrong, just that Twitter is momentarily
|
105
|
+
down. It could be for routine maintenance, etc.
|
106
|
+
|
107
|
+
TweetStream::Client.new('abc','def').on_error do |message|
|
108
|
+
# Log your error message somewhere
|
109
|
+
end.track('term') do |status|
|
110
|
+
# Do things when nothing's wrong
|
111
|
+
end
|
112
|
+
|
113
|
+
However, if the maximum number of reconnect attempts has been reached,
|
114
|
+
TweetStream will raise a <tt>TweetStream::ReconnectError</tt> with
|
115
|
+
information about the timeout and number of retries attempted.
|
116
|
+
|
93
117
|
== Terminating a TweetStream
|
94
118
|
|
95
119
|
It is often the case that you will need to change the parameters of your
|
96
120
|
track or follow tweet streams. In the case that you need to terminate
|
97
|
-
a stream,
|
98
|
-
|
121
|
+
a stream, you may add a second argument to your block that will yield
|
122
|
+
the client itself:
|
99
123
|
|
100
124
|
# Stop after collecting 10 statuses
|
101
125
|
@statuses = []
|
102
|
-
TweetStream::Client.new('username','password').
|
126
|
+
TweetStream::Client.new('username','password').sample do |status, client|
|
103
127
|
@statuses << status
|
104
|
-
|
128
|
+
client.stop if @statuses.size >= 10
|
105
129
|
end
|
106
130
|
|
107
131
|
When <tt>stop</tt> is called, TweetStream will return from the block
|
data/RELEASE_NOTES.rdoc
ADDED
data/Rakefile
CHANGED
@@ -10,9 +10,9 @@ begin
|
|
10
10
|
gem.email = "michael@intridea.com"
|
11
11
|
gem.homepage = "http://github.com/intridea/tweetstream"
|
12
12
|
gem.authors = ["Michael Bleigh"]
|
13
|
-
gem.files = FileList["[A-Z]*", "{lib,spec}/**/*"] - FileList["**/*.log"]
|
13
|
+
gem.files = FileList["[A-Z]*", "{lib,spec,examples}/**/*"] - FileList["**/*.log"]
|
14
14
|
gem.add_development_dependency "rspec"
|
15
|
-
gem.add_dependency '
|
15
|
+
gem.add_dependency 'twitter-stream'
|
16
16
|
gem.add_dependency 'daemons'
|
17
17
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
18
18
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'tweetstream'
|
3
|
+
require 'ruby-growl'
|
4
|
+
|
5
|
+
if args_start = ARGV.index('--')
|
6
|
+
username, password = ARGV[args_start + 1].split(':')
|
7
|
+
tracks = ARGV[args_start + 2 .. -1]
|
8
|
+
puts "Starting a GrowlTweet to track: #{tracks.inspect}"
|
9
|
+
end
|
10
|
+
|
11
|
+
TweetStream::Daemon.new(username,password).track(*tracks) do |status|
|
12
|
+
g = Growl.new 'localhost', 'growltweet', ['tweet']
|
13
|
+
g.notify 'tweet', status.user.screen_name, status.text
|
14
|
+
end
|
data/lib/tweetstream/client.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'cgi'
|
3
3
|
require 'yajl'
|
4
|
-
require '
|
4
|
+
require 'eventmachine'
|
5
|
+
require 'twitter/json_stream'
|
6
|
+
require 'json'
|
5
7
|
|
6
8
|
module TweetStream
|
7
9
|
# Provides simple access to the Twitter Streaming API (http://apiwiki.twitter.com/Streaming-API-Documentation)
|
@@ -20,12 +22,29 @@ module TweetStream
|
|
20
22
|
# view the TweetStream::Daemon class.
|
21
23
|
class Client
|
22
24
|
attr_accessor :username, :password
|
25
|
+
attr_reader :parser
|
26
|
+
|
27
|
+
# Set the JSON Parser for this client. Acceptable options are:
|
28
|
+
#
|
29
|
+
# <tt>:json_gem</tt>:: Parse using the JSON gem.
|
30
|
+
# <tt>:json_pure</tt>:: Parse using the pure-ruby implementation of the JSON gem.
|
31
|
+
# <tt>:active_support</tt>:: Parse using ActiveSupport::JSON.decode
|
32
|
+
# <tt>:yajl</tt>:: Parse using <tt>yajl-ruby</tt>.
|
33
|
+
#
|
34
|
+
# You may also pass a class that will return a hash with symbolized
|
35
|
+
# keys when <tt>YourClass.parse</tt> is called with a JSON string.
|
36
|
+
def parser=(parser)
|
37
|
+
@parser = parser_from(parser)
|
38
|
+
end
|
23
39
|
|
24
40
|
# Create a new client with the Twitter credentials
|
25
|
-
# of the account you want to be using its API quota.
|
26
|
-
|
41
|
+
# of the account you want to be using its API quota.
|
42
|
+
# You may also set the JSON parsing library as specified
|
43
|
+
# in the #parser= setter.
|
44
|
+
def initialize(user, pass, parser = :json_gem)
|
27
45
|
self.username = user
|
28
46
|
self.password = pass
|
47
|
+
self.parser = parser
|
29
48
|
end
|
30
49
|
|
31
50
|
# Returns all public statuses. The Firehose is not a generally
|
@@ -136,49 +155,96 @@ module TweetStream
|
|
136
155
|
end
|
137
156
|
end
|
138
157
|
|
158
|
+
# Set a Proc to be run when an HTTP error is encountered in the
|
159
|
+
# processing of the stream. Note that TweetStream will automatically
|
160
|
+
# try to reconnect, this is for reference only. Don't panic!
|
161
|
+
#
|
162
|
+
# @client = TweetStream::Client.new('user','pass')
|
163
|
+
# @client.on_error do |message|
|
164
|
+
# # Make note of error message
|
165
|
+
# end
|
166
|
+
#
|
167
|
+
# Block must take one argument: the error message.
|
168
|
+
# If no block is given, it will return the currently set
|
169
|
+
# error proc. When a block is given, the TweetStream::Client
|
170
|
+
# object is returned to allow for chaining.
|
171
|
+
def on_error(&block)
|
172
|
+
if block_given?
|
173
|
+
@on_limit = block
|
174
|
+
self
|
175
|
+
else
|
176
|
+
@on_limit
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
139
180
|
def start(path, query_parameters = {}, &block) #:nodoc:
|
140
181
|
method = query_parameters.delete(:method) || :get
|
141
182
|
delete_proc = query_parameters.delete(:delete) || self.on_delete
|
142
183
|
limit_proc = query_parameters.delete(:limit) || self.on_limit
|
184
|
+
error_proc = query_parameters.delete(:error) || self.on_error
|
143
185
|
|
144
186
|
uri = method == :get ? build_uri(path, query_parameters) : build_uri(path)
|
145
187
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
188
|
+
EventMachine::run {
|
189
|
+
@stream = Twitter::JSONStream.connect(
|
190
|
+
:path => uri,
|
191
|
+
:auth => "#{URI.encode self.username}:#{URI.encode self.password}",
|
192
|
+
:method => method.to_s.upcase,
|
193
|
+
:content => (method == :post ? build_post_body(query_parameters) : ''),
|
194
|
+
:user_agent => 'TweetStream'
|
195
|
+
)
|
196
|
+
|
197
|
+
@stream.each_item do |item|
|
198
|
+
hash = TweetStream::Hash.new(@parser.decode(item)) # @parser.parse(item)
|
199
|
+
|
200
|
+
if hash[:delete] && hash[:delete][:status]
|
201
|
+
delete_proc.call(hash[:delete][:status][:id], hash[:delete][:status][:user_id]) if delete_proc.is_a?(Proc)
|
202
|
+
elsif hash[:limit] && hash[:limit][:track]
|
203
|
+
limit_proc.call(hash[:limit][:track]) if limit_proc.is_a?(Proc)
|
204
|
+
elsif hash[:text] && hash[:user]
|
205
|
+
@last_status = TweetStream::Status.new(hash)
|
206
|
+
|
207
|
+
# Give the block the option to receive either one
|
208
|
+
# or two arguments, depending on its arity.
|
209
|
+
case block.arity
|
210
|
+
when 1
|
211
|
+
yield @last_status
|
212
|
+
when 2
|
213
|
+
yield @last_status, self
|
214
|
+
end
|
215
|
+
end
|
160
216
|
end
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
217
|
+
|
218
|
+
@stream.on_error do |message|
|
219
|
+
error_proc.call(message) if error_proc.is_a?(Proc)
|
220
|
+
end
|
221
|
+
|
222
|
+
@stream.on_max_reconnects do |timeout, retries|
|
223
|
+
raise TweetStream::ReconnectError.new(timeout, retries)
|
224
|
+
end
|
225
|
+
}
|
166
226
|
end
|
167
227
|
|
168
|
-
# Terminate the currently running TweetStream.
|
169
|
-
def self.stop
|
170
|
-
raise TweetStream::Terminated
|
171
|
-
end
|
172
|
-
|
173
228
|
# Terminate the currently running TweetStream.
|
174
229
|
def stop
|
175
|
-
|
230
|
+
EventMachine.stop_event_loop
|
231
|
+
@last_status
|
176
232
|
end
|
177
233
|
|
178
234
|
protected
|
179
235
|
|
236
|
+
def parser_from(parser)
|
237
|
+
case parser
|
238
|
+
when Class
|
239
|
+
parser
|
240
|
+
when Symbol
|
241
|
+
require "tweetstream/parsers/#{parser.to_s}"
|
242
|
+
eval("TweetStream::Parsers::#{parser.to_s.split('_').map(&:capitalize).join('')}")
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
180
246
|
def build_uri(path, query_parameters = {}) #:nodoc:
|
181
|
-
URI.parse("
|
247
|
+
URI.parse("/1/#{path}.json#{build_query_parameters(query_parameters)}")
|
182
248
|
end
|
183
249
|
|
184
250
|
def build_query_parameters(query)
|
data/lib/tweetstream/daemon.rb
CHANGED
@@ -26,9 +26,9 @@ class TweetStream::Daemon < TweetStream::Client
|
|
26
26
|
# Twitter account you wish to use. The daemon has
|
27
27
|
# an optional process name for use when querying
|
28
28
|
# running processes.
|
29
|
-
def initialize(user, pass, app_name=nil)
|
29
|
+
def initialize(user, pass, app_name=nil, parser=:json_gem)
|
30
30
|
@app_name = app_name
|
31
|
-
super(user, pass)
|
31
|
+
super(user, pass, parser)
|
32
32
|
end
|
33
33
|
|
34
34
|
def start(path, query_parameters = {}, &block) #:nodoc:
|
data/lib/tweetstream/hash.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
class TweetStream::Hash < ::Hash #:nodoc: all
|
2
2
|
def initialize(other_hash = {})
|
3
3
|
other_hash.keys.each do |key|
|
4
|
-
|
4
|
+
value = other_hash[key]
|
5
|
+
value = TweetStream::Hash.new(value) if value.is_a?(::Hash)
|
6
|
+
self[key.to_sym] = value
|
5
7
|
end
|
6
8
|
end
|
7
|
-
|
9
|
+
|
8
10
|
def method_missing(method_name, *args)
|
9
11
|
if key?(method_name.to_sym)
|
10
12
|
self[method_name.to_sym]
|
data/lib/tweetstream/status.rb
CHANGED
data/lib/tweetstream/user.rb
CHANGED
data/lib/tweetstream.rb
CHANGED
@@ -8,4 +8,14 @@ module TweetStream
|
|
8
8
|
class Terminated < ::StandardError; end
|
9
9
|
class Error < ::StandardError; end
|
10
10
|
class ConnectionError < TweetStream::Error; end
|
11
|
+
# A ReconnectError is raised when the maximum number of retries has
|
12
|
+
# failed to re-establish a connection.
|
13
|
+
class ReconnectError < StandardError
|
14
|
+
attr_accessor :timeout, :retries
|
15
|
+
def initialize(timeout, retries)
|
16
|
+
self.timeout = timeout
|
17
|
+
self.retries = retries
|
18
|
+
super("Failed to reconnect after #{retries} tries.")
|
19
|
+
end
|
20
|
+
end
|
11
21
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -16,11 +16,6 @@ describe TweetStream::Client do
|
|
16
16
|
@client.send(:build_uri, '').is_a?(URI).should be_true
|
17
17
|
end
|
18
18
|
|
19
|
-
it 'should contain the auth information from the client' do
|
20
|
-
@client.send(:build_uri, '').user.should == 'abc'
|
21
|
-
@client.send(:build_uri, '').password.should == 'def'
|
22
|
-
end
|
23
|
-
|
24
19
|
it 'should have the specified path with the version prefix and a json extension' do
|
25
20
|
@client.send(:build_uri, 'awesome').path.should == '/1/awesome.json'
|
26
21
|
end
|
@@ -58,52 +53,96 @@ describe TweetStream::Client do
|
|
58
53
|
|
59
54
|
describe '#start' do
|
60
55
|
before do
|
56
|
+
@stream = stub("Twitter::JSONStream",
|
57
|
+
:connect => true,
|
58
|
+
:unbind => true,
|
59
|
+
:each_item => true,
|
60
|
+
:on_error => true,
|
61
|
+
:on_max_reconnects => true,
|
62
|
+
:connection_completed => true
|
63
|
+
)
|
64
|
+
EM.stub!(:run).and_yield
|
65
|
+
Twitter::JSONStream.stub!(:connect).and_return(@stream)
|
61
66
|
@client = TweetStream::Client.new('abc','def')
|
62
67
|
end
|
63
|
-
|
64
|
-
it 'should
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
+
|
69
|
+
it 'should try to connect via a JSON stream' do
|
70
|
+
Twitter::JSONStream.should_receive(:connect).with(
|
71
|
+
:auth => 'abc:def',
|
72
|
+
:content => 'track=monday',
|
73
|
+
:path => URI.parse('/1/statuses/filter.json'),
|
74
|
+
:method => 'POST',
|
75
|
+
:user_agent => 'TweetStream'
|
76
|
+
).and_return(@stream)
|
77
|
+
|
78
|
+
@client.track('monday')
|
68
79
|
end
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
@
|
80
|
+
|
81
|
+
describe '#each_item' do
|
82
|
+
it 'should call the appropriate parser' do
|
83
|
+
@client = TweetStream::Client.new('abc','def',:active_support)
|
84
|
+
TweetStream::Parsers::ActiveSupport.should_receive(:decode).and_return({})
|
85
|
+
@stream.should_receive(:each_item).and_yield(sample_tweets[0].to_json)
|
86
|
+
@client.track('abc','def')
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should yield a TweetStream::Status' do
|
90
|
+
@stream.should_receive(:each_item).and_yield(sample_tweets[0].to_json)
|
91
|
+
@client.track('abc'){|s| s.should be_kind_of(TweetStream::Status)}
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should also yield the client if a block with arity 2 is given' do
|
95
|
+
@stream.should_receive(:each_item).and_yield(sample_tweets[0].to_json)
|
96
|
+
@client.track('abc'){|s,c| c.should == @client}
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should include the proper values' do
|
100
|
+
tweet = sample_tweets[0]
|
101
|
+
tweet[:id] = 123
|
102
|
+
tweet[:user][:screen_name] = 'monkey'
|
103
|
+
tweet[:text] = "Oo oo aa aa"
|
104
|
+
@stream.should_receive(:each_item).and_yield(tweet.to_json)
|
105
|
+
@client.track('abc') do |s|
|
106
|
+
s[:id].should == 123
|
107
|
+
s.user.screen_name.should == 'monkey'
|
108
|
+
s.text.should == 'Oo oo aa aa'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should call the on_delete if specified' do
|
113
|
+
delete = '{ "delete": { "status": { "id": 1234, "user_id": 3 } } }'
|
114
|
+
@stream.should_receive(:each_item).and_yield(delete)
|
115
|
+
@client.on_delete do |id, user_id|
|
116
|
+
id.should == 1234
|
117
|
+
user_id.should == 3
|
118
|
+
end.track('abc')
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should call the on_limit if specified' do
|
122
|
+
limit = '{ "limit": { "track": 1234 } }'
|
123
|
+
@stream.should_receive(:each_item).and_yield(limit)
|
124
|
+
@client.on_limit do |track|
|
125
|
+
track.should == 1234
|
126
|
+
end.track('abc')
|
76
127
|
end
|
77
|
-
@yielded.should be_true
|
78
128
|
end
|
79
129
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
130
|
+
describe '#on_error' do
|
131
|
+
it 'should pass the message on to the error block' do
|
132
|
+
@stream.should_receive(:on_error).and_yield('Uh oh')
|
133
|
+
@client.on_error do |m|
|
134
|
+
m.should == 'Uh oh'
|
135
|
+
end.track('abc')
|
136
|
+
end
|
84
137
|
end
|
85
138
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
@client.send("on_#{special_method}", &@proc)
|
94
|
-
Yajl::HttpStream.should_receive(:new).and_return(y = mock("Yajl::HttpStream"))
|
95
|
-
y.should_receive(:post).once.with(URI.parse('http://abc:def@stream.twitter.com/1/statuses/filter.json'), "track=musicmonday", :symbolize_keys => true).and_yield(special_object)
|
96
|
-
@client.track('musicmonday')
|
97
|
-
@called.should == true
|
98
|
-
end
|
99
|
-
|
100
|
-
it "should accept a proc on a :#{special_method} option if a #{special_method} object is given" do
|
101
|
-
@called = false
|
102
|
-
@proc = Proc.new{|*args| @called = true }
|
103
|
-
Yajl::HttpStream.should_receive(:new).and_return(y = mock("Yajl::HttpStream"))
|
104
|
-
y.should_receive(:post).once.with(URI.parse('http://abc:def@stream.twitter.com/1/statuses/filter.json'), "track=musicmonday", :symbolize_keys => true).and_yield(special_object)
|
105
|
-
@client.track('musicmonday', special_method => @proc)
|
106
|
-
@called.should == true
|
139
|
+
describe '#on_max_reconnects' do
|
140
|
+
it 'should raise a ReconnectError' do
|
141
|
+
@stream.should_receive(:on_max_reconnects).and_yield(30, 20)
|
142
|
+
lambda{@client.track('abc')}.should raise_error(TweetStream::ReconnectError) do |e|
|
143
|
+
e.timeout.should == 30
|
144
|
+
e.retries.should == 20
|
145
|
+
end
|
107
146
|
end
|
108
147
|
end
|
109
148
|
end
|
@@ -170,34 +209,18 @@ describe TweetStream::Client do
|
|
170
209
|
@client.track('rock')
|
171
210
|
end
|
172
211
|
end
|
173
|
-
|
174
|
-
describe '.stop' do
|
175
|
-
it 'should raise a TweetStream::Terminated error' do
|
176
|
-
lambda{ TweetStream::Client.stop }.should raise_error(TweetStream::Terminated)
|
177
|
-
end
|
178
|
-
|
179
|
-
it 'should not cause a TweetStream to crash with a real exception' do
|
180
|
-
@client = TweetStream::Client.new('abc','def')
|
181
|
-
@statuses = []
|
182
|
-
Yajl::HttpStream.should_receive(:new).and_return(y = mock("Yajl::HttpStream"))
|
183
|
-
y.should_receive(:post).once.with(URI.parse('http://abc:def@stream.twitter.com/1/statuses/filter.json'), 'track=musicmonday', :symbolize_keys => true).and_yield(sample_tweets[0])
|
184
|
-
@client.track('musicmonday') do |status|
|
185
|
-
@statuses << status
|
186
|
-
TweetStream::Client.stop
|
187
|
-
end.should == @statuses.first
|
188
|
-
@statuses.size.should == 1
|
189
|
-
end
|
190
|
-
end
|
191
212
|
|
192
213
|
describe 'instance .stop' do
|
193
|
-
it 'should
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
214
|
+
it 'should call EventMachine::stop_event_loop' do
|
215
|
+
EventMachine.should_receive :stop_event_loop
|
216
|
+
TweetStream::Client.new('test','fake').stop.should be_nil
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'should return the last status yielded' do
|
220
|
+
EventMachine.should_receive :stop_event_loop
|
221
|
+
client = TweetStream::Client.new('test','fake')
|
222
|
+
client.send(:instance_variable_set, :@last_status, {})
|
223
|
+
client.stop.should == {}
|
201
224
|
end
|
202
225
|
end
|
203
226
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe 'TweetStream JSON Parsers' do
|
4
|
+
it 'should default to the JSON Gem' do
|
5
|
+
TweetStream::Client.new('test','fake').parser.should == TweetStream::Parsers::JsonGem
|
6
|
+
end
|
7
|
+
|
8
|
+
[:json_gem, :yajl, :active_support, :json_pure].each do |engine|
|
9
|
+
describe "#{engine} parsing" do
|
10
|
+
before do
|
11
|
+
@client = TweetStream::Client.new('test','fake',engine)
|
12
|
+
@class_name = "TweetStream::Parsers::#{engine.to_s.split('_').map(&:capitalize).join('')}"
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should set the parser to the appropriate class' do
|
16
|
+
@client.parser.to_s == @class_name
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should be settable via client.parser=' do
|
20
|
+
@client.parser = nil
|
21
|
+
@client.parser.should be_nil
|
22
|
+
@client.parser = engine
|
23
|
+
@client.parser.to_s.should == @class_name
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class FakeParser
|
29
|
+
def self.decode(text)
|
30
|
+
{}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should be settable to a class' do
|
35
|
+
@client = TweetStream::Client.new('abc','def')
|
36
|
+
@client.parser = FakeParser
|
37
|
+
@client.parser.should == FakeParser
|
38
|
+
end
|
39
|
+
end
|
@@ -6,4 +6,10 @@ describe TweetStream::Status do
|
|
6
6
|
@status.user.is_a?(TweetStream::User).should be_true
|
7
7
|
@status.user.screen_name.should == 'bob'
|
8
8
|
end
|
9
|
+
|
10
|
+
it 'should override the #id method for itself and the user' do
|
11
|
+
@status = TweetStream::Status.new(:id => 123, :user => {:id => 345})
|
12
|
+
@status.id.should == 123
|
13
|
+
@status.user.id.should == 345
|
14
|
+
end
|
9
15
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tweetstream
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Bleigh
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-01-25 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -23,14 +23,14 @@ dependencies:
|
|
23
23
|
version: "0"
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
|
-
name:
|
26
|
+
name: twitter-stream
|
27
27
|
type: :runtime
|
28
28
|
version_requirement:
|
29
29
|
version_requirements: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0
|
33
|
+
version: "0"
|
34
34
|
version:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: daemons
|
@@ -54,12 +54,18 @@ extra_rdoc_files:
|
|
54
54
|
files:
|
55
55
|
- LICENSE
|
56
56
|
- README.rdoc
|
57
|
+
- RELEASE_NOTES.rdoc
|
57
58
|
- Rakefile
|
58
59
|
- VERSION
|
60
|
+
- examples/growl_daemon.rb
|
59
61
|
- lib/tweetstream.rb
|
60
62
|
- lib/tweetstream/client.rb
|
61
63
|
- lib/tweetstream/daemon.rb
|
62
64
|
- lib/tweetstream/hash.rb
|
65
|
+
- lib/tweetstream/parsers/active_support.rb
|
66
|
+
- lib/tweetstream/parsers/json_gem.rb
|
67
|
+
- lib/tweetstream/parsers/json_pure.rb
|
68
|
+
- lib/tweetstream/parsers/yajl.rb
|
63
69
|
- lib/tweetstream/status.rb
|
64
70
|
- lib/tweetstream/user.rb
|
65
71
|
- spec/data/statuses.json
|
@@ -67,6 +73,7 @@ files:
|
|
67
73
|
- spec/spec_helper.rb
|
68
74
|
- spec/tweetstream/client_spec.rb
|
69
75
|
- spec/tweetstream/hash_spec.rb
|
76
|
+
- spec/tweetstream/parser_spec.rb
|
70
77
|
- spec/tweetstream/status_spec.rb
|
71
78
|
- spec/tweetstream_spec.rb
|
72
79
|
has_rdoc: true
|
@@ -101,5 +108,7 @@ test_files:
|
|
101
108
|
- spec/spec_helper.rb
|
102
109
|
- spec/tweetstream/client_spec.rb
|
103
110
|
- spec/tweetstream/hash_spec.rb
|
111
|
+
- spec/tweetstream/parser_spec.rb
|
104
112
|
- spec/tweetstream/status_spec.rb
|
105
113
|
- spec/tweetstream_spec.rb
|
114
|
+
- examples/growl_daemon.rb
|