tweetstream 2.1.0 → 2.2.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.md +12 -11
- data/lib/tweetstream/client.rb +158 -199
- data/lib/tweetstream/version.rb +1 -1
- data/spec/fixtures/delete.json +8 -0
- data/spec/fixtures/favorite.json +150 -0
- data/spec/fixtures/limit.json +5 -0
- data/spec/fixtures/scrub_geo.json +8 -0
- data/spec/fixtures/status_withheld.json +7 -0
- data/spec/fixtures/user_withheld.json +6 -0
- data/spec/spec_helper.rb +10 -12
- data/spec/tweetstream/client_authentication_spec.rb +2 -2
- data/spec/tweetstream/client_site_stream_spec.rb +5 -5
- data/spec/tweetstream/client_spec.rb +52 -63
- data/spec/tweetstream/client_userstream_spec.rb +16 -5
- data/tweetstream.gemspec +1 -1
- metadata +121 -34
data/README.md
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
# TweetStream [![Build Status](https://secure.travis-ci.org/intridea/tweetstream.png?branch=master)][travis] [![Dependency Status](https://gemnasium.com/intridea/tweetstream.png?travis)][gemnasium]
|
1
|
+
# TweetStream [![Build Status](https://secure.travis-ci.org/intridea/tweetstream.png?branch=master)][travis] [![Dependency Status](https://gemnasium.com/intridea/tweetstream.png?travis)][gemnasium] [![Code Climate](https://codeclimate.com/badge.png)][codeclimate]
|
2
2
|
TweetStream provides simple Ruby access to [Twitter's Streaming API](https://dev.twitter.com/docs/streaming-api).
|
3
3
|
|
4
4
|
[travis]: http://travis-ci.org/intridea/tweetstream
|
5
5
|
[gemnasium]: https://gemnasium.com/intridea/tweetstream
|
6
|
+
[codeclimate]: https://codeclimate.com/github/intridea/tweetstream
|
6
7
|
|
7
8
|
## Installation
|
8
9
|
|
@@ -57,7 +58,7 @@ additions in 2.0 include:
|
|
57
58
|
|
58
59
|
### OAuth
|
59
60
|
|
60
|
-
OAuth is now the default authentication method. Both userstreams and Site
|
61
|
+
OAuth is now the default authentication method. Both userstreams and Site
|
61
62
|
Streams exclusively work with OAuth. TweetStream still supports Basic Auth,
|
62
63
|
however it is no longer the default. If you are still using Basic Auth, you
|
63
64
|
should plan to move to OAuth as soon as possible.
|
@@ -68,7 +69,7 @@ Site Streams are now fully supported, including the connection management functi
|
|
68
69
|
|
69
70
|
### Compatablity with the Twitter gem
|
70
71
|
|
71
|
-
TweetStream now emits objects from the [Twitter gem](https://github.com/
|
72
|
+
TweetStream now emits objects from the [Twitter gem](https://github.com/sferik/twitter) instead of custom hashes. These objects are already defined in the `twitter` gem and are superior to the custom objects in the following ways:
|
72
73
|
|
73
74
|
1. Object equivalence (`#==` returns true if `#id`s are the same).
|
74
75
|
2. The `#created_at` method returns a `Date` instead of a `String`.
|
@@ -85,14 +86,14 @@ It offers functionality parity with twitter-stream while also supporting several
|
|
85
86
|
|
86
87
|
### Removal of on_interval callback
|
87
88
|
|
88
|
-
We have removed the `on_interval` callback. If you require interval-based timers, it is possible to run
|
89
|
+
We have removed the `on_interval` callback. If you require interval-based timers, it is possible to run
|
89
90
|
TweetStream inside an already running EventMachine reactor in which you can define `EM::Timer` or `EM::PeriodicTimer`
|
90
91
|
for time-based operations:
|
91
92
|
|
92
93
|
```ruby
|
93
94
|
EM.run do
|
94
95
|
client = TweetStream::Client.new
|
95
|
-
|
96
|
+
|
96
97
|
EM::PeriodicTimer.new(10) do
|
97
98
|
# do something on an interval
|
98
99
|
end
|
@@ -141,12 +142,12 @@ client.control.friends_ids('115192457') do |friends|
|
|
141
142
|
end
|
142
143
|
|
143
144
|
# obtain the current state of the stream
|
144
|
-
client.control.info do |info|
|
145
|
+
client.control.info do |info|
|
145
146
|
# do something
|
146
147
|
end
|
147
148
|
```
|
148
149
|
|
149
|
-
Note that per Twitter's documentation, connection management features are not
|
150
|
+
Note that per Twitter's documentation, connection management features are not
|
150
151
|
immediately available when connected
|
151
152
|
|
152
153
|
You also can use method hooks for both regular timeline statuses and direct messages.
|
@@ -169,7 +170,7 @@ client.userstream
|
|
169
170
|
|
170
171
|
## Authentication
|
171
172
|
|
172
|
-
TweetStream supports OAuth and Basic Auth. `TweetStream::Client` now accepts
|
173
|
+
TweetStream supports OAuth and Basic Auth. `TweetStream::Client` now accepts
|
173
174
|
a hash:
|
174
175
|
|
175
176
|
```ruby
|
@@ -200,12 +201,12 @@ end
|
|
200
201
|
|
201
202
|
TweetStream assumes OAuth by default. If you are using Basic Auth, it is recommended
|
202
203
|
that you update your code to use OAuth as Twitter is likely to phase out Basic Auth
|
203
|
-
support. Basic Auth is only available for public streams as User Stream and Site Stream
|
204
|
+
support. Basic Auth is only available for public streams as User Stream and Site Stream
|
204
205
|
functionality [only support OAuth](https://dev.twitter.com/docs/streaming-apis/connecting#Authentication).
|
205
206
|
|
206
|
-
## Parsing JSON
|
207
|
+
## Parsing JSON
|
207
208
|
|
208
|
-
TweetStream supports swappable JSON backends via MultiJson. Simply require your preferred
|
209
|
+
TweetStream supports swappable JSON backends via MultiJson. Simply require your preferred
|
209
210
|
JSON parser and it will be used to parse responses.
|
210
211
|
|
211
212
|
## Handling Deletes and Rate Limitations
|
data/lib/tweetstream/client.rb
CHANGED
@@ -1,18 +1,16 @@
|
|
1
|
-
require 'cgi'
|
2
1
|
require 'em-twitter'
|
3
2
|
require 'eventmachine'
|
4
3
|
require 'multi_json'
|
5
4
|
require 'twitter'
|
6
|
-
require 'uri'
|
7
5
|
|
8
6
|
module TweetStream
|
9
|
-
# Provides simple access to the Twitter Streaming API (
|
7
|
+
# Provides simple access to the Twitter Streaming API (https://dev.twitter.com/docs/streaming-api)
|
10
8
|
# for Ruby scripts that need to create a long connection to
|
11
9
|
# Twitter for tracking and other purposes.
|
12
10
|
#
|
13
11
|
# Basic usage of the library is to call one of the provided
|
14
12
|
# methods and provide a block that will perform actions on
|
15
|
-
# a yielded Twitter::
|
13
|
+
# a yielded Twitter::Tweet. For example:
|
16
14
|
#
|
17
15
|
# TweetStream::Client.new.track('fail') do |status|
|
18
16
|
# puts "[#{status.user.screen_name}] #{status.text}"
|
@@ -22,6 +20,21 @@ module TweetStream
|
|
22
20
|
# view the TweetStream::Daemon class.
|
23
21
|
class Client
|
24
22
|
|
23
|
+
OPTION_CALLBACKS = [:delete,
|
24
|
+
:scrub_geo,
|
25
|
+
:limit,
|
26
|
+
:error,
|
27
|
+
:enhance_your_calm,
|
28
|
+
:unauthorized,
|
29
|
+
:reconnect,
|
30
|
+
:inited,
|
31
|
+
:direct_message,
|
32
|
+
:timeline_status,
|
33
|
+
:anything,
|
34
|
+
:no_data_received,
|
35
|
+
:status_withheld,
|
36
|
+
:user_withheld].freeze unless defined?(OPTION_CALLBACKS)
|
37
|
+
|
25
38
|
# @private
|
26
39
|
attr_accessor *Configuration::VALID_OPTIONS_KEYS
|
27
40
|
attr_accessor :options
|
@@ -34,6 +47,7 @@ module TweetStream
|
|
34
47
|
Configuration::VALID_OPTIONS_KEYS.each do |key|
|
35
48
|
send("#{key}=", merged_options[key])
|
36
49
|
end
|
50
|
+
@callbacks = {}
|
37
51
|
end
|
38
52
|
|
39
53
|
# Returns all public statuses. The Firehose is not a generally
|
@@ -41,7 +55,7 @@ module TweetStream
|
|
41
55
|
# Creative use of a combination of other resources and various access
|
42
56
|
# levels can satisfy nearly every application use case.
|
43
57
|
def firehose(query_parameters = {}, &block)
|
44
|
-
start('statuses/firehose', query_parameters, &block)
|
58
|
+
start('/1/statuses/firehose.json', query_parameters, &block)
|
45
59
|
end
|
46
60
|
|
47
61
|
# Returns all statuses containing http: and https:. The links stream is
|
@@ -49,7 +63,7 @@ module TweetStream
|
|
49
63
|
# of access. Creative use of a combination of other resources and various
|
50
64
|
# access levels can satisfy nearly every application use case.
|
51
65
|
def links(query_parameters = {}, &block)
|
52
|
-
start('statuses/links', query_parameters, &block)
|
66
|
+
start('/1/statuses/links.json', query_parameters, &block)
|
53
67
|
end
|
54
68
|
|
55
69
|
# Returns all retweets. The retweet stream is not a generally available
|
@@ -59,7 +73,7 @@ module TweetStream
|
|
59
73
|
# the site-wide retweet feature has not yet launched,
|
60
74
|
# so there are currently few, if any, retweets on this stream.
|
61
75
|
def retweet(query_parameters = {}, &block)
|
62
|
-
start('statuses/retweet', query_parameters, &block)
|
76
|
+
start('/1/statuses/retweet.json', query_parameters, &block)
|
63
77
|
end
|
64
78
|
|
65
79
|
# Returns a random sample of all public statuses. The default access level
|
@@ -68,7 +82,7 @@ module TweetStream
|
|
68
82
|
# research applications that desire a larger proportion to be statistically
|
69
83
|
# significant sample.
|
70
84
|
def sample(query_parameters = {}, &block)
|
71
|
-
start('statuses/sample', query_parameters, &block)
|
85
|
+
start('/1/statuses/sample.json', query_parameters, &block)
|
72
86
|
end
|
73
87
|
|
74
88
|
# Specify keywords to track. Queries are subject to Track Limitations,
|
@@ -79,8 +93,7 @@ module TweetStream
|
|
79
93
|
# Keywords containing punctuation will only exact match tokens.
|
80
94
|
# Query parameters may be passed as the last argument.
|
81
95
|
def track(*keywords, &block)
|
82
|
-
query_params = keywords.
|
83
|
-
query_params ||= {}
|
96
|
+
query_params = keywords.extract_options!
|
84
97
|
filter(query_params.merge(:track => keywords), &block)
|
85
98
|
end
|
86
99
|
|
@@ -89,8 +102,7 @@ module TweetStream
|
|
89
102
|
# pressing the reply "swoosh") are not matched. Requires integer user
|
90
103
|
# IDs, not screen names. Query parameters may be passed as the last argument.
|
91
104
|
def follow(*user_ids, &block)
|
92
|
-
query_params = user_ids.
|
93
|
-
query_params ||= {}
|
105
|
+
query_params = user_ids.extract_options!
|
94
106
|
filter(query_params.merge(:follow => user_ids), &block)
|
95
107
|
end
|
96
108
|
|
@@ -103,8 +115,7 @@ module TweetStream
|
|
103
115
|
# the first pair denoting the southwest corner of the box
|
104
116
|
# longitude/latitude pairs, separated by commas. The first pair specifies the southwest corner of the box.
|
105
117
|
def locations(*locations_map, &block)
|
106
|
-
query_params = locations_map.
|
107
|
-
query_params ||= {}
|
118
|
+
query_params = locations_map.extract_options!
|
108
119
|
filter(query_params.merge(:locations => locations_map), &block)
|
109
120
|
end
|
110
121
|
|
@@ -114,26 +125,26 @@ module TweetStream
|
|
114
125
|
# method is provided separately for cases when it would conserve the
|
115
126
|
# number of HTTP connections to combine track and follow.
|
116
127
|
def filter(query_params = {}, &block)
|
117
|
-
start('statuses/filter', query_params.merge(:method => :post), &block)
|
128
|
+
start('/1/statuses/filter.json', query_params.merge(:method => :post), &block)
|
118
129
|
end
|
119
130
|
|
120
131
|
# Make a call to the userstream api for currently authenticated user
|
121
132
|
def userstream(query_params = {}, &block)
|
122
|
-
stream_params = { :host => "userstream.twitter.com"
|
133
|
+
stream_params = { :host => "userstream.twitter.com" }
|
123
134
|
query_params.merge!(:extra_stream_parameters => stream_params)
|
124
|
-
start('', query_params, &block)
|
135
|
+
start('/2/user.json', query_params, &block)
|
125
136
|
end
|
126
137
|
|
127
138
|
# Make a call to the userstream api
|
128
139
|
def sitestream(user_ids = [], query_params = {}, &block)
|
129
|
-
stream_params = { :host => "sitestream.twitter.com"
|
140
|
+
stream_params = { :host => "sitestream.twitter.com" }
|
130
141
|
query_params.merge!({
|
131
142
|
:method => :post,
|
132
143
|
:follow => user_ids,
|
133
144
|
:extra_stream_parameters => stream_params
|
134
145
|
})
|
135
146
|
query_params.merge!(:with => 'followings') if query_params.delete(:followings)
|
136
|
-
start('', query_params, &block)
|
147
|
+
start('/2b/site.json', query_params, &block)
|
137
148
|
end
|
138
149
|
|
139
150
|
# Set a Proc to be run when a deletion notice is received
|
@@ -149,12 +160,7 @@ module TweetStream
|
|
149
160
|
# deletion proc. When a block is given, the TweetStream::Client
|
150
161
|
# object is returned to allow for chaining.
|
151
162
|
def on_delete(&block)
|
152
|
-
|
153
|
-
@on_delete = block
|
154
|
-
self
|
155
|
-
else
|
156
|
-
@on_delete
|
157
|
-
end
|
163
|
+
on('delete', &block)
|
158
164
|
end
|
159
165
|
|
160
166
|
# Set a Proc to be run when a scrub_geo notice is received
|
@@ -170,12 +176,7 @@ module TweetStream
|
|
170
176
|
# scrub_geo proc. When a block is given, the TweetStream::Client
|
171
177
|
# object is returned to allow for chaining.
|
172
178
|
def on_scrub_geo(&block)
|
173
|
-
|
174
|
-
@on_scrub_geo = block
|
175
|
-
self
|
176
|
-
else
|
177
|
-
@on_scrub_geo
|
178
|
-
end
|
179
|
+
on('scrub_geo', &block)
|
179
180
|
end
|
180
181
|
|
181
182
|
# Set a Proc to be run when a rate limit notice is received
|
@@ -191,12 +192,7 @@ module TweetStream
|
|
191
192
|
# limit proc. When a block is given, the TweetStream::Client
|
192
193
|
# object is returned to allow for chaining.
|
193
194
|
def on_limit(&block)
|
194
|
-
|
195
|
-
@on_limit = block
|
196
|
-
self
|
197
|
-
else
|
198
|
-
@on_limit
|
199
|
-
end
|
195
|
+
on('limit', &block)
|
200
196
|
end
|
201
197
|
|
202
198
|
# Set a Proc to be run when an HTTP error is encountered in the
|
@@ -213,12 +209,7 @@ module TweetStream
|
|
213
209
|
# error proc. When a block is given, the TweetStream::Client
|
214
210
|
# object is returned to allow for chaining.
|
215
211
|
def on_error(&block)
|
216
|
-
|
217
|
-
@on_error = block
|
218
|
-
self
|
219
|
-
else
|
220
|
-
@on_error
|
221
|
-
end
|
212
|
+
on('error', &block)
|
222
213
|
end
|
223
214
|
|
224
215
|
# Set a Proc to be run when an HTTP status 401 is encountered while
|
@@ -229,12 +220,7 @@ module TweetStream
|
|
229
220
|
# unauthorized proc. When a block is given, the TweetStream::Client
|
230
221
|
# object is returned to allow for chaining.
|
231
222
|
def on_unauthorized(&block)
|
232
|
-
|
233
|
-
@on_unauthorized = block
|
234
|
-
self
|
235
|
-
else
|
236
|
-
@on_unauthorized
|
237
|
-
end
|
223
|
+
on('unauthorized', &block)
|
238
224
|
end
|
239
225
|
|
240
226
|
# Set a Proc to be run when a direct message is encountered in the
|
@@ -250,12 +236,7 @@ module TweetStream
|
|
250
236
|
# direct message proc. When a block is given, the TweetStream::Client
|
251
237
|
# object is returned to allow for chaining.
|
252
238
|
def on_direct_message(&block)
|
253
|
-
|
254
|
-
@on_direct_message = block
|
255
|
-
self
|
256
|
-
else
|
257
|
-
@on_direct_message
|
258
|
-
end
|
239
|
+
on('direct_message', &block)
|
259
240
|
end
|
260
241
|
|
261
242
|
# Set a Proc to be run whenever anything is encountered in the
|
@@ -271,12 +252,7 @@ module TweetStream
|
|
271
252
|
# timeline status proc. When a block is given, the TweetStream::Client
|
272
253
|
# object is returned to allow for chaining.
|
273
254
|
def on_anything(&block)
|
274
|
-
|
275
|
-
@on_anything = block
|
276
|
-
self
|
277
|
-
else
|
278
|
-
@on_anything
|
279
|
-
end
|
255
|
+
on('anything', &block)
|
280
256
|
end
|
281
257
|
|
282
258
|
# Set a Proc to be run when a regular timeline message is encountered in the
|
@@ -292,12 +268,7 @@ module TweetStream
|
|
292
268
|
# timeline status proc. When a block is given, the TweetStream::Client
|
293
269
|
# object is returned to allow for chaining.
|
294
270
|
def on_timeline_status(&block)
|
295
|
-
|
296
|
-
@on_timeline_status = block
|
297
|
-
self
|
298
|
-
else
|
299
|
-
@on_timeline_status
|
300
|
-
end
|
271
|
+
on('timeline_status', &block)
|
301
272
|
end
|
302
273
|
|
303
274
|
# Set a Proc to be run on reconnect.
|
@@ -308,12 +279,7 @@ module TweetStream
|
|
308
279
|
# end
|
309
280
|
#
|
310
281
|
def on_reconnect(&block)
|
311
|
-
|
312
|
-
@on_reconnect = block
|
313
|
-
self
|
314
|
-
else
|
315
|
-
@on_reconnect
|
316
|
-
end
|
282
|
+
on('reconnect', &block)
|
317
283
|
end
|
318
284
|
|
319
285
|
# Set a Proc to be run when connection established.
|
@@ -325,28 +291,18 @@ module TweetStream
|
|
325
291
|
# end
|
326
292
|
#
|
327
293
|
def on_inited(&block)
|
328
|
-
|
329
|
-
@on_inited = block
|
330
|
-
self
|
331
|
-
else
|
332
|
-
@on_inited
|
333
|
-
end
|
294
|
+
on('inited', &block)
|
334
295
|
end
|
335
296
|
|
336
297
|
# Set a Proc to be run when no data is received from the server
|
337
298
|
# and a stall occurs. Twitter defines this to be 90 seconds.
|
338
299
|
#
|
339
300
|
# @client = TweetStream::Client.new
|
340
|
-
# @client.
|
301
|
+
# @client.on_no_data_received do
|
341
302
|
# # Make note of no data, possi
|
342
303
|
# end
|
343
304
|
def on_no_data_received(&block)
|
344
|
-
|
345
|
-
@on_no_data = block
|
346
|
-
self
|
347
|
-
else
|
348
|
-
@on_no_data
|
349
|
-
end
|
305
|
+
on('no_data_received', &block)
|
350
306
|
end
|
351
307
|
|
352
308
|
# Set a Proc to be run when enhance_your_calm signal is received.
|
@@ -356,11 +312,45 @@ module TweetStream
|
|
356
312
|
# # do something, your account has been blocked
|
357
313
|
# end
|
358
314
|
def on_enhance_your_calm(&block)
|
315
|
+
on('enhance_your_calm', &block)
|
316
|
+
end
|
317
|
+
|
318
|
+
# Set a Proc to be run when a status_withheld message is received.
|
319
|
+
#
|
320
|
+
# @client = TweetStream::Client.new
|
321
|
+
# @client.on_status_withheld do |status|
|
322
|
+
# # do something with the status
|
323
|
+
# end
|
324
|
+
def on_status_withheld(&block)
|
325
|
+
on('status_withheld', &block)
|
326
|
+
end
|
327
|
+
|
328
|
+
# Set a Proc to be run when a status_withheld message is received.
|
329
|
+
#
|
330
|
+
# @client = TweetStream::Client.new
|
331
|
+
# @client.on_user_withheld do |status|
|
332
|
+
# # do something with the status
|
333
|
+
# end
|
334
|
+
def on_user_withheld(&block)
|
335
|
+
on('user_withheld', &block)
|
336
|
+
end
|
337
|
+
|
338
|
+
# Set a Proc to be run on userstream events
|
339
|
+
#
|
340
|
+
# @client = TweetStream::Client.new
|
341
|
+
# @client.event(:favorite) do |event|
|
342
|
+
# # do something with the status
|
343
|
+
# end
|
344
|
+
def on_event(event, &block)
|
345
|
+
on(event, &block)
|
346
|
+
end
|
347
|
+
|
348
|
+
def on(event, &block)
|
359
349
|
if block_given?
|
360
|
-
@
|
350
|
+
@callbacks[event.to_s] = block
|
361
351
|
self
|
362
352
|
else
|
363
|
-
@
|
353
|
+
@callbacks[event.to_s]
|
364
354
|
end
|
365
355
|
end
|
366
356
|
|
@@ -379,33 +369,24 @@ module TweetStream
|
|
379
369
|
end
|
380
370
|
|
381
371
|
# connect to twitter without starting a new EventMachine run loop
|
382
|
-
def connect(path,
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
inited_proc
|
392
|
-
|
393
|
-
timeline_status_proc = query_parameters.delete(:timeline_status) || self.on_timeline_status
|
394
|
-
anything_proc = query_parameters.delete(:anything) || self.on_anything
|
395
|
-
no_data_proc = query_parameters.delete(:no_data_received) || self.on_no_data_received
|
396
|
-
|
397
|
-
params = normalize_filter_parameters(query_parameters)
|
398
|
-
|
399
|
-
extra_stream_parameters = query_parameters.delete(:extra_stream_parameters) || {}
|
400
|
-
|
401
|
-
uri = method == :get ? build_uri(path, params) : build_uri(path)
|
372
|
+
def connect(path, options = {}, &block)
|
373
|
+
request_method = options.delete(:method) || :get
|
374
|
+
warn_if_callbacks(options)
|
375
|
+
|
376
|
+
callbacks = @callbacks.dup
|
377
|
+
OPTION_CALLBACKS.each do |callback|
|
378
|
+
callbacks.merge(callback.to_s => options.delete(callback)) if options[callback]
|
379
|
+
end
|
380
|
+
|
381
|
+
inited_proc = options.delete(:inited) || @callbacks['inited']
|
382
|
+
extra_stream_parameters = options.delete(:extra_stream_parameters) || {}
|
402
383
|
|
403
384
|
stream_params = {
|
404
|
-
:path
|
405
|
-
:method
|
385
|
+
:path => path,
|
386
|
+
:method => request_method.to_s.upcase,
|
406
387
|
:user_agent => user_agent,
|
407
|
-
:on_inited
|
408
|
-
:params
|
388
|
+
:on_inited => inited_proc,
|
389
|
+
:params => normalize_filter_parameters(options)
|
409
390
|
}.merge(extra_stream_parameters).merge(auth_params)
|
410
391
|
|
411
392
|
@stream = EM::Twitter::Client.connect(stream_params)
|
@@ -413,76 +394,36 @@ module TweetStream
|
|
413
394
|
begin
|
414
395
|
hash = MultiJson.decode(item, :symbolize_keys => true)
|
415
396
|
rescue MultiJson::DecodeError
|
416
|
-
|
397
|
+
invoke_callback(callbacks['error'], "MultiJson::DecodeError occured in stream: #{item}")
|
417
398
|
next
|
418
399
|
end
|
419
400
|
|
420
401
|
unless hash.is_a?(::Hash)
|
421
|
-
|
402
|
+
invoke_callback(callbacks['error'], "Unexpected JSON object in stream: #{item}")
|
422
403
|
next
|
423
404
|
end
|
424
405
|
|
425
406
|
Twitter.identity_map = false
|
426
407
|
|
427
|
-
|
428
|
-
@control_uri = hash[:control][:control_uri]
|
429
|
-
require 'tweetstream/site_stream_client'
|
430
|
-
@control = TweetStream::SiteStreamClient.new(@control_uri, options)
|
431
|
-
@control.on_error(&self.on_error)
|
432
|
-
elsif hash[:delete] && hash[:delete][:status]
|
433
|
-
delete_proc.call(hash[:delete][:status][:id], hash[:delete][:status][:user_id]) if delete_proc.is_a?(Proc)
|
434
|
-
elsif hash[:scrub_geo] && hash[:scrub_geo][:up_to_status_id]
|
435
|
-
scrub_geo_proc.call(hash[:scrub_geo][:up_to_status_id], hash[:scrub_geo][:user_id]) if scrub_geo_proc.is_a?(Proc)
|
436
|
-
elsif hash[:limit] && hash[:limit][:track]
|
437
|
-
limit_proc.call(hash[:limit][:track]) if limit_proc.is_a?(Proc)
|
438
|
-
elsif hash[:direct_message]
|
439
|
-
yield_message_to direct_message_proc, Twitter::DirectMessage.new(hash[:direct_message])
|
440
|
-
elsif hash[:text] && hash[:user]
|
441
|
-
@last_status = Twitter::Status.new(hash)
|
442
|
-
yield_message_to timeline_status_proc, @last_status
|
443
|
-
|
444
|
-
if block_given?
|
445
|
-
# Give the block the option to receive either one
|
446
|
-
# or two arguments, depending on its arity.
|
447
|
-
case block.arity
|
448
|
-
when 1
|
449
|
-
yield @last_status
|
450
|
-
when 2
|
451
|
-
yield @last_status, self
|
452
|
-
end
|
453
|
-
end
|
454
|
-
elsif hash[:for_user]
|
455
|
-
@message = hash
|
456
|
-
|
457
|
-
if block_given?
|
458
|
-
# Give the block the option to receive either one
|
459
|
-
# or two arguments, depending on its arity.
|
460
|
-
case block.arity
|
461
|
-
when 1
|
462
|
-
yield @message
|
463
|
-
when 2
|
464
|
-
yield @message, self
|
465
|
-
end
|
466
|
-
end
|
467
|
-
end
|
408
|
+
respond_to(hash, callbacks, &block)
|
468
409
|
|
469
|
-
yield_message_to
|
410
|
+
yield_message_to(callbacks['anything'], hash)
|
470
411
|
end
|
471
412
|
|
472
413
|
@stream.on_error do |message|
|
473
|
-
|
414
|
+
invoke_callback(callbacks['error'], message)
|
474
415
|
end
|
475
416
|
|
476
417
|
@stream.on_unauthorized do
|
477
|
-
|
418
|
+
invoke_callback(callbacks['unauthorized'])
|
478
419
|
end
|
479
420
|
|
480
421
|
@stream.on_enhance_your_calm do
|
481
|
-
|
422
|
+
invoke_callback(callbacks['enhance_your_calm'])
|
482
423
|
end
|
483
424
|
|
484
425
|
@stream.on_reconnect do |timeout, retries|
|
485
|
-
|
426
|
+
invoke_callback(callbacks['reconnect'], timeout, retries)
|
486
427
|
end
|
487
428
|
|
488
429
|
@stream.on_max_reconnects do |timeout, retries|
|
@@ -490,12 +431,42 @@ module TweetStream
|
|
490
431
|
end
|
491
432
|
|
492
433
|
@stream.on_no_data_received do
|
493
|
-
|
434
|
+
invoke_callback(callbacks['no_data_received'])
|
494
435
|
end
|
495
436
|
|
496
437
|
@stream
|
497
438
|
end
|
498
439
|
|
440
|
+
def respond_to(hash, callbacks, &block)
|
441
|
+
if hash[:control] && hash[:control][:control_uri]
|
442
|
+
@control_uri = hash[:control][:control_uri]
|
443
|
+
require 'tweetstream/site_stream_client'
|
444
|
+
@control = TweetStream::SiteStreamClient.new(@control_uri, options)
|
445
|
+
@control.on_error(&callbacks['error'])
|
446
|
+
elsif hash[:delete] && hash[:delete][:status]
|
447
|
+
invoke_callback(callbacks['delete'], hash[:delete][:status][:id], hash[:delete][:status][:user_id])
|
448
|
+
elsif hash[:scrub_geo] && hash[:scrub_geo][:up_to_status_id]
|
449
|
+
invoke_callback(callbacks['scrub_geo'], hash[:scrub_geo][:up_to_status_id], hash[:scrub_geo][:user_id])
|
450
|
+
elsif hash[:limit] && hash[:limit][:track]
|
451
|
+
invoke_callback(callbacks['limit'], hash[:limit][:track])
|
452
|
+
elsif hash[:direct_message]
|
453
|
+
yield_message_to(callbacks['direct_message'], Twitter::DirectMessage.new(hash[:direct_message]))
|
454
|
+
elsif hash[:status_withheld]
|
455
|
+
invoke_callback(callbacks['status_withheld'], hash[:status_withheld])
|
456
|
+
elsif hash[:user_withheld]
|
457
|
+
invoke_callback(callbacks['user_withheld'], hash[:user_withheld])
|
458
|
+
elsif hash[:event]
|
459
|
+
invoke_callback(callbacks[hash[:event].to_s], hash)
|
460
|
+
elsif hash[:text] && hash[:user]
|
461
|
+
@last_status = Twitter::Tweet.new(hash)
|
462
|
+
yield_message_to(callbacks['timeline_status'], @last_status)
|
463
|
+
|
464
|
+
yield_message_to(block, @last_status) if block_given?
|
465
|
+
elsif hash[:for_user]
|
466
|
+
yield_message_to(block, hash) if block_given?
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
499
470
|
# Terminate the currently running TweetStream and close EventMachine loop
|
500
471
|
def stop
|
501
472
|
EventMachine.stop_event_loop
|
@@ -513,23 +484,6 @@ module TweetStream
|
|
513
484
|
|
514
485
|
protected
|
515
486
|
|
516
|
-
def build_uri(path, query_parameters = {}) #:nodoc:
|
517
|
-
URI.parse("/1/#{path}.json#{build_query_parameters(query_parameters)}")
|
518
|
-
end
|
519
|
-
|
520
|
-
def build_query_parameters(query)
|
521
|
-
query.size > 0 ? "?#{build_post_body(query)}" : ''
|
522
|
-
end
|
523
|
-
|
524
|
-
def build_post_body(query) #:nodoc:
|
525
|
-
return '' unless query && query.is_a?(::Hash) && query.size > 0
|
526
|
-
|
527
|
-
query.map do |k, v|
|
528
|
-
v = v.flatten.collect { |q| q.to_s }.join(',') if v.is_a?(Array)
|
529
|
-
"#{k.to_s}=#{CGI.escape(v.to_s)}"
|
530
|
-
end.join('&')
|
531
|
-
end
|
532
|
-
|
533
487
|
def normalize_filter_parameters(query_parameters = {})
|
534
488
|
[:follow, :track, :locations].each do |param|
|
535
489
|
if query_parameters[param].kind_of?(Array)
|
@@ -542,38 +496,43 @@ module TweetStream
|
|
542
496
|
end
|
543
497
|
|
544
498
|
def auth_params
|
545
|
-
if auth_method ==
|
546
|
-
{ :basic =>
|
499
|
+
if auth_method.to_s == 'basic'
|
500
|
+
{ :basic => {
|
501
|
+
:username => username,
|
502
|
+
:password => password
|
503
|
+
}
|
504
|
+
}
|
547
505
|
else
|
548
|
-
{ :oauth =>
|
506
|
+
{ :oauth => {
|
507
|
+
:consumer_key => consumer_key,
|
508
|
+
:consumer_secret => consumer_secret,
|
509
|
+
:token => oauth_token,
|
510
|
+
:token_secret => oauth_token_secret
|
511
|
+
}
|
512
|
+
}
|
549
513
|
end
|
550
514
|
end
|
551
515
|
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
:password => password
|
556
|
-
}
|
557
|
-
end
|
558
|
-
|
559
|
-
def oauth_params
|
560
|
-
{
|
561
|
-
:consumer_key => consumer_key,
|
562
|
-
:consumer_secret => consumer_secret,
|
563
|
-
:token => oauth_token,
|
564
|
-
:token_secret => oauth_token_secret
|
565
|
-
}
|
516
|
+
# A utility method used to invoke callback methods against the Client
|
517
|
+
def invoke_callback(callback, *args)
|
518
|
+
callback.call(*args) if callback
|
566
519
|
end
|
567
520
|
|
568
521
|
def yield_message_to(procedure, message)
|
522
|
+
# Give the block the option to receive either one
|
523
|
+
# or two arguments, depending on its arity.
|
569
524
|
if procedure.is_a?(Proc)
|
570
525
|
case procedure.arity
|
571
|
-
|
572
|
-
|
573
|
-
when 2
|
574
|
-
procedure.call(message, self)
|
526
|
+
when 1 then invoke_callback(procedure, message)
|
527
|
+
when 2 then invoke_callback(procedure, message, self)
|
575
528
|
end
|
576
529
|
end
|
577
530
|
end
|
531
|
+
|
532
|
+
def warn_if_callbacks(options={})
|
533
|
+
if OPTION_CALLBACKS.select { |callback| options[callback] }.size > 0
|
534
|
+
Kernel.warn("Passing callbacks via the options hash is deprecated and will be removed in TweetStream 3.0")
|
535
|
+
end
|
536
|
+
end
|
578
537
|
end
|
579
538
|
end
|