tweetstream 1.1.5 → 2.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/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ Version 2.0.0
2
+ =============
3
+
4
+ * Added Site Stream support
5
+ * Switched to [em-twitter](https://github.com/spagalloco/em-twitter) for underlying streaming lib
6
+ * Switched to Twitter gem objects instead of custom hashes, see [47e5cd3d21a9562b3d959bc231009af460b37567](https://github.com/intridea/tweetstream/commit/47e5cd3d21a9562b3d959bc231009af460b37567) for details (sferik)
7
+ * Made OAuth the default authentication method
8
+ * Removed on_interval callback
9
+ * Removed parser configuration option
10
+
11
+ Version 1.1.5
12
+ =============
13
+
14
+ * Added support for the scrub_geo response (augustj)
15
+ * Update multi_json and twitter-stream version dependencies
16
+
1
17
  Version 1.1.4
2
18
  =============
3
19
 
@@ -27,8 +43,9 @@ Version 1.1.0
27
43
  * OAuth authentication
28
44
  * User Stream support
29
45
  * Removed swappable JSON backend support for MultiJson
30
- * Added epoll and kqueue EventMachine support
31
- * Added on___interval and on_inited callbacks
46
+ * Added EventMachine epoll and kqueue support
47
+ * Added on_interval callback
48
+ * Added on_inited callback
32
49
 
33
50
  Version 1.0.5
34
51
  =============
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 Intridea, Inc.
1
+ Copyright (c) 2012 Intridea, Inc.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -16,12 +16,11 @@ Using TweetStream is quite simple:
16
16
  require 'tweetstream'
17
17
 
18
18
  TweetStream.configure do |config|
19
- config.consumer_key = 'abcdefghijklmnopqrstuvwxyz'
20
- config.consumer_secret = '0123456789'
21
- config.oauth_token = 'abcdefghijklmnopqrstuvwxyz'
19
+ config.consumer_key = 'abcdefghijklmnopqrstuvwxyz'
20
+ config.consumer_secret = '0123456789'
21
+ config.oauth_token = 'abcdefghijklmnopqrstuvwxyz'
22
22
  config.oauth_token_secret = '0123456789'
23
- config.auth_method = :oauth
24
- config.parser = :yajl
23
+ config.auth_method = :oauth
25
24
  end
26
25
 
27
26
  # This will pull a sample of all tweets based on
@@ -48,20 +47,108 @@ TweetStream::Client.new.follow(14252, 53235) do |status|
48
47
  end
49
48
  ```
50
49
 
51
- The methods available to TweetStream::Client will be kept in parity
50
+ The methods available to TweetStream::Client are kept in parity
52
51
  with the methods available on the Streaming API wiki page.
53
52
 
53
+ ## Changes in 2.0
54
+
55
+ TweetStream 2.0 introduces a number of requested features and bug fixes. For the complete list refer to the [changelog](https://github.com/intridea/tweetstream/blob/master/CHANGELOG.md#version-200). Notable
56
+ additions in 2.0 include:
57
+
58
+ ### OAuth
59
+
60
+ OAuth is now the default authentication method. Both userstreams and Site
61
+ Streams exclusively work with OAuth. TweetStream still supports Basic Auth,
62
+ however it is no longer the default. If you are still using Basic Auth, you
63
+ should plan to move to OAuth as soon as possible.
64
+
65
+ ### Site Stream Support
66
+
67
+ Site Streams are now fully supported, including the connection management functionality.
68
+
69
+ ### Compatablity with the Twitter gem
70
+
71
+ TweetStream now emits objects from the [Twitter gem](https://github.com/jnunemaker/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
+ 1. Object equivalence (`#==` returns true if `#id`s are the same).
74
+ 2. The `#created_at` method returns a `Date` instead of a `String`.
75
+ 3. Allows boolean methods to be called with a question mark (e.g.
76
+ `User#protected?`)
77
+
78
+ Additionally, any new features that are added to objects in the
79
+ `twitter` gem (e.g. identity map) will be automatically inherited by TweetStream.
80
+
81
+ ### em-twitter
82
+
83
+ We've replaced the underlying gem that connects to the streaming API. [twitter-stream](https://github.com/voloko/twitter-stream) has been replaced with [em-twitter](https://github.com/spagalloco/em-twitter).
84
+ It offers functionality parity with twitter-stream while also supporting several new features.
85
+
86
+ ### Removal of on_interval callback
87
+
88
+ We have removed the `on_interval` callback. If you require interval-based timers, it is possible to run
89
+ TweetStream inside an already running EventMachine reactor in which you can define `EM::Timer` or `EM::PeriodicTimer`
90
+ for time-based operations:
91
+
92
+ ```ruby
93
+ EM.run do
94
+ client = TweetStream::Client.new
95
+
96
+ EM::PeriodicTimer.new(10) do
97
+ # do something on an interval
98
+ end
99
+ end
100
+ ```
101
+
102
+ ### Additional Notes
103
+
104
+ The parser configuration method has been removed as MultiJson automatically detects existing parsers.
105
+
54
106
  ## Using the Twitter Userstream
55
107
 
56
- Using the Twitter userstream works similarly to the regular streaming, except you use the userstream method.
108
+ Using the Twitter userstream works similarly to regular streaming, except you use the `userstream` method.
57
109
 
58
110
  ```ruby
59
111
  # Use 'userstream' to get message from your stream
60
- TweetStream::Client.new.userstream do |status|
112
+ client = TweetStream::Client.new
113
+
114
+ client.userstream do |status|
61
115
  puts status.text
62
116
  end
63
117
  ```
64
118
 
119
+ ## Using Twitter Site Streams
120
+
121
+ ```ruby
122
+ client = TweetStream::Client.new
123
+
124
+ client.sitestream(['115192457'], :followings => true) do |status|
125
+ puts status.inspect
126
+ end
127
+ ```
128
+
129
+ Once connected, you can [control the Site Stream connection](https://dev.twitter.com/docs/streaming-apis/streams/site/control):
130
+
131
+ ```ruby
132
+ # add users to the stream
133
+ client.control.add_user('2039761')
134
+
135
+ # remove users from the stream
136
+ client.control.remove_user('115192457')
137
+
138
+ # obtain a list of followings of users in the stream
139
+ client.control.friends_ids('115192457') do |friends|
140
+ # do something
141
+ end
142
+
143
+ # obtain the current state of the stream
144
+ client.control.info do |info|
145
+ # do something
146
+ end
147
+ ```
148
+
149
+ Note that per Twitter's documentation, connection management features are not
150
+ immediately available when connected
151
+
65
152
  You also can use method hooks for both regular timeline statuses and direct messages.
66
153
 
67
154
  ```ruby
@@ -80,11 +167,10 @@ end
80
167
  client.userstream
81
168
  ```
82
169
 
83
- ## Configuration and Changes in 1.1.0
170
+ ## Authentication
84
171
 
85
- As of version 1.1.0.rc1 TweetStream supports OAuth. Please note that in order
86
- to support OAuth, the `TweetStream::Client` initializer no longer accepts a
87
- username/password. `TweetStream::Client` now accepts a hash:
172
+ TweetStream supports OAuth and Basic Auth. `TweetStream::Client` now accepts
173
+ a hash:
88
174
 
89
175
  ```ruby
90
176
  TweetStream::Client.new(:username => 'you', :password => 'pass')
@@ -94,12 +180,11 @@ Alternatively, you can configure TweetStream via the configure method:
94
180
 
95
181
  ```ruby
96
182
  TweetStream.configure do |config|
97
- config.consumer_key = 'cVcIw5zoLFE2a4BdDsmmA'
98
- config.consumer_secret = 'yYgVgvTT9uCFAi2IuscbYTCqwJZ1sdQxzISvLhNWUA'
99
- config.oauth_token = '4618-H3gU7mjDQ7MtFkAwHhCqD91Cp4RqDTp1AKwGzpHGL3I'
183
+ config.consumer_key = 'cVcIw5zoLFE2a4BdDsmmA'
184
+ config.consumer_secret = 'yYgVgvTT9uCFAi2IuscbYTCqwJZ1sdQxzISvLhNWUA'
185
+ config.oauth_token = '4618-H3gU7mjDQ7MtFkAwHhCqD91Cp4RqDTp1AKwGzpHGL3I'
100
186
  config.oauth_token_secret = 'xmc9kFgOXpMdQ590Tho2gV7fE71v5OmBrX8qPGh7Y'
101
- config.auth_method = :oauth
102
- config.parser = :yajl
187
+ config.auth_method = :oauth
103
188
  end
104
189
  ```
105
190
 
@@ -107,31 +192,21 @@ If you are using Basic Auth:
107
192
 
108
193
  ```ruby
109
194
  TweetStream.configure do |config|
110
- config.username = 'username'
111
- config.password = 'password'
112
- config.auth_method = :basic
113
- config.parser = :yajl
195
+ config.username = 'username'
196
+ config.password = 'password'
197
+ config.auth_method = :basic
114
198
  end
115
199
  ```
116
200
 
117
201
  TweetStream assumes OAuth by default. If you are using Basic Auth, it is recommended
118
202
  that you update your code to use OAuth as Twitter is likely to phase out Basic Auth
119
- support.
120
-
121
- ## Swappable JSON Parsing
122
-
123
- As of version 1.1, TweetStream supports swappable JSON backends via MultiJson. You can
124
- specify a parser during configuration:
203
+ support. Basic Auth is only available for public streams as User Stream and Site Stream
204
+ functionality [only support OAuth](https://dev.twitter.com/docs/streaming-apis/connecting#Authentication).
125
205
 
126
- ```ruby
127
- # Parse tweets using Yajl-Ruby
128
- TweetStream.configure do |config|
129
- config.parser = :yajl
130
- end
131
- ```
206
+ ## Parsing JSON
132
207
 
133
- Available options are `:oj`, `:yajl`, `:json_gem`, `:json_pure`, and
134
- `:ok_json`.
208
+ TweetStream supports swappable JSON backends via MultiJson. Simply require your preferred
209
+ JSON parser and it will be used to parse responses.
135
210
 
136
211
  ## Handling Deletes and Rate Limitations
137
212
 
@@ -154,7 +229,7 @@ end
154
229
  @client.track('intridea')
155
230
  ```
156
231
 
157
- The on_delete and on_limit methods can also be chained, like so:
232
+ The on_delete and on_limit methods can also be chained:
158
233
 
159
234
  ```ruby
160
235
  TweetStream::Client.new.on_delete{ |status_id, user_id|
@@ -248,10 +323,6 @@ end
248
323
  If you put the above into a script and run the script with `ruby scriptname.rb`,
249
324
  you will see a list of daemonization commands such as start, stop, and run.
250
325
 
251
- ## TODO
252
-
253
- * SiteStream support
254
-
255
326
  ## Contributing
256
327
 
257
328
  * Fork the project.
@@ -262,9 +333,11 @@ you will see a list of daemonization commands such as start, stop, and run.
262
333
 
263
334
  ## Contributors
264
335
 
265
- * Michael Bleigh (initial gem)
266
- * Steve Agalloco (current maintainer)
336
+ * [Michael Bleigh](https://github.com/mbleigh) (initial gem)
337
+ * [Steve Agalloco](https://github.com/spagalloco) (current maintainer)
338
+ * [Erik Michaels-Ober](https://github.com/sferik) (current maintainer)
339
+ * [Countless others](https://github.com/intridea/tweetstream/graphs/contributors)
267
340
 
268
341
  ## Copyright
269
342
 
270
- Copyright (c) 2011 Intridea, Inc. (http://www.intridea.com/). See [LICENSE](https://github.com/intridea/tweetstream/blob/master/LICENSE.md) for details.
343
+ Copyright (c) 2012 Intridea, Inc. (http://www.intridea.com/). See [LICENSE](https://github.com/intridea/tweetstream/blob/master/LICENSE.md) for details.
data/Rakefile CHANGED
@@ -1,5 +1,3 @@
1
- #!/usr/bin/env rake
2
-
3
1
  require 'bundler'
4
2
  Bundler::GemHelper.install_tasks
5
3
 
@@ -3,14 +3,14 @@ require 'tweetstream'
3
3
  require 'growl'
4
4
 
5
5
  tracks = 'yankees'
6
- puts "Starting a GrowlTweet to track: #{tracks}"
6
+ puts "Starting a TweetStream Daemon to track: #{tracks}"
7
7
 
8
8
  TweetStream.configure do |config|
9
- config.consumer_key = 'abcdefghijklmnopqrstuvwxyz'
10
- config.consumer_secret = '0123456789'
11
- config.oauth_token = 'abcdefghijklmnopqrstuvwxyz'
9
+ config.consumer_key = 'abcdefghijklmnopqrstuvwxyz'
10
+ config.consumer_secret = '0123456789'
11
+ config.oauth_token = 'abcdefghijklmnopqrstuvwxyz'
12
12
  config.oauth_token_secret = '0123456789'
13
- config.auth_method = :oauth
13
+ config.auth_method = :oauth
14
14
  end
15
15
 
16
16
  TweetStream::Daemon.new('tracker').track(tracks) do |status|
data/examples/oauth.rb CHANGED
@@ -2,12 +2,11 @@ require 'yajl'
2
2
  require 'tweetstream'
3
3
 
4
4
  TweetStream.configure do |config|
5
- config.consumer_key = 'abcdefghijklmnopqrstuvwxyz'
6
- config.consumer_secret = '0123456789'
7
- config.oauth_token = 'abcdefghijklmnopqrstuvwxyz'
5
+ config.consumer_key = 'abcdefghijklmnopqrstuvwxyz'
6
+ config.consumer_secret = '0123456789'
7
+ config.oauth_token = 'abcdefghijklmnopqrstuvwxyz'
8
8
  config.oauth_token_secret = '0123456789'
9
- config.auth_method = :oauth
10
- config.parser = :yajl
9
+ config.auth_method = :oauth
11
10
  end
12
11
 
13
12
  client = TweetStream::Client.new
@@ -0,0 +1,40 @@
1
+ require 'yajl'
2
+ require 'tweetstream'
3
+
4
+ TweetStream.configure do |config|
5
+ config.consumer_key = 'abcdefghijklmnopqrstuvwxyz'
6
+ config.consumer_secret = '0123456789'
7
+ config.oauth_token = 'abcdefghijklmnopqrstuvwxyz'
8
+ config.oauth_token_secret = '0123456789'
9
+ config.auth_method = :oauth
10
+ end
11
+
12
+ EM.run do
13
+
14
+ client = TweetStream::Client.new
15
+
16
+ client.on_error do |error|
17
+ puts error
18
+ end
19
+
20
+ client.sitestream([user_id], :followings => true) do |status|
21
+ puts status.inspect
22
+ end
23
+
24
+ EM::Timer.new(60) do
25
+ client.control.add_user(user_id_to_add)
26
+ client.control.info { |i| puts i.inspect }
27
+ end
28
+
29
+ EM::Timer.new(75) do
30
+ client.control.friends_ids(user_id) do |friends|
31
+ puts friends.inspect
32
+ end
33
+ end
34
+
35
+ EM::Timer.new(90) do
36
+ client.control.remove_user(user_id_to_remove)
37
+ client.control.info { |i| puts i.inspect }
38
+ end
39
+
40
+ end
@@ -2,12 +2,11 @@ require 'yajl'
2
2
  require 'tweetstream'
3
3
 
4
4
  TweetStream.configure do |config|
5
- config.consumer_key = 'abcdefghijklmnopqrstuvwxyz'
6
- config.consumer_secret = '0123456789'
7
- config.oauth_token = 'abcdefghijklmnopqrstuvwxyz'
5
+ config.consumer_key = 'abcdefghijklmnopqrstuvwxyz'
6
+ config.consumer_secret = '0123456789'
7
+ config.oauth_token = 'abcdefghijklmnopqrstuvwxyz'
8
8
  config.oauth_token_secret = '0123456789'
9
- config.auth_method = :oauth
10
- config.parser = :yajl
9
+ config.auth_method = :oauth
11
10
  end
12
11
 
13
12
  client = TweetStream::Client.new
data/lib/tweetstream.rb CHANGED
@@ -1,9 +1,5 @@
1
1
  require 'tweetstream/configuration'
2
2
  require 'tweetstream/client'
3
- require 'tweetstream/hash'
4
- require 'tweetstream/status'
5
- require 'tweetstream/direct_message'
6
- require 'tweetstream/user'
7
3
  require 'tweetstream/error'
8
4
  require 'tweetstream/daemon'
9
5
 
@@ -1,8 +1,9 @@
1
- require 'uri'
2
1
  require 'cgi'
3
2
  require 'eventmachine'
4
- require 'twitter/json_stream'
5
3
  require 'multi_json'
4
+ require 'twitter'
5
+ require 'em-twitter'
6
+ require 'uri'
6
7
 
7
8
  module TweetStream
8
9
  # Provides simple access to the Twitter Streaming API (http://apiwiki.twitter.com/Streaming-API-Documentation)
@@ -11,7 +12,7 @@ module TweetStream
11
12
  #
12
13
  # Basic usage of the library is to call one of the provided
13
14
  # methods and provide a block that will perform actions on
14
- # a yielded TweetStream::Status. For example:
15
+ # a yielded Twitter::Status. For example:
15
16
  #
16
17
  # TweetStream::Client.new.track('fail') do |status|
17
18
  # puts "[#{status.user.screen_name}] #{status.text}"
@@ -23,22 +24,16 @@ module TweetStream
23
24
 
24
25
  # @private
25
26
  attr_accessor *Configuration::VALID_OPTIONS_KEYS
26
- attr_accessor :timer
27
+ attr_accessor :options
28
+ attr_reader :control_uri, :control, :stream
27
29
 
28
30
  # Creates a new API
29
31
  def initialize(options={})
30
- options = TweetStream.options.merge(options)
32
+ self.options = options
33
+ merged_options = TweetStream.options.merge(options)
31
34
  Configuration::VALID_OPTIONS_KEYS.each do |key|
32
- send("#{key}=", options[key])
35
+ send("#{key}=", merged_options[key])
33
36
  end
34
-
35
- # Ensure the json parser can be properly loaded
36
- json_parser
37
- end
38
-
39
- # Get the JSON parser class for this client.
40
- def json_parser
41
- parser_from(parser)
42
37
  end
43
38
 
44
39
  # Returns all public statuses. The Firehose is not a generally
@@ -124,7 +119,20 @@ module TweetStream
124
119
 
125
120
  # Make a call to the userstream api for currently authenticated user
126
121
  def userstream(&block)
127
- start('', :extra_stream_parameters => {:host => "userstream.twitter.com", :path => "/2/user.json"}, &block)
122
+ stream_params = { :host => "userstream.twitter.com", :path => "/2/user.json" }
123
+ start('', :extra_stream_parameters => stream_params, &block)
124
+ end
125
+
126
+ # Make a call to the userstream api
127
+ def sitestream(user_ids = [], query_params = {}, &block)
128
+ stream_params = { :host => "sitestream.twitter.com", :path => '/2b/site.json' }
129
+ sitestream_params = {
130
+ :method => :post,
131
+ :follow => user_ids,
132
+ :extra_stream_parameters => stream_params
133
+ }
134
+ sitestream_params.merge!(:with => 'followings') if query_params[:followings]
135
+ start('', sitestream_params, &block)
128
136
  end
129
137
 
130
138
  # Set a Proc to be run when a deletion notice is received
@@ -258,7 +266,7 @@ module TweetStream
258
266
  # processing of the stream.
259
267
  #
260
268
  # @client = TweetStream::Client.new
261
- # @client.on_timeline_message do |status|
269
+ # @client.on_timeline_status do |status|
262
270
  # # do something with the status
263
271
  # end
264
272
  #
@@ -308,21 +316,19 @@ module TweetStream
308
316
  end
309
317
  end
310
318
 
311
- # Set a Proc to be run on a regular interval
312
- # independent of timeline status updates
319
+ # Set a Proc to be run when no data is received from the server
320
+ # and a stall occurs. Twitter defines this to be 90 seconds.
313
321
  #
314
322
  # @client = TweetStream::Client.new
315
- # @client.on_interval(20) do
316
- # # do something every 20 seconds
323
+ # @client.on_no_data do
324
+ # # Make note of no data, possi
317
325
  # end
318
- #
319
- def on_interval(time_interval=nil, &block)
326
+ def on_no_data_received(&block)
320
327
  if block_given?
321
- @on_interval_time = time_interval
322
- @on_interval_proc = block
328
+ @on_no_data = block
323
329
  self
324
330
  else
325
- [@on_interval_time, @on_interval_proc]
331
+ @on_no_data
326
332
  end
327
333
  end
328
334
 
@@ -352,6 +358,7 @@ module TweetStream
352
358
  direct_message_proc = query_parameters.delete(:direct_message) || self.on_direct_message
353
359
  timeline_status_proc = query_parameters.delete(:timeline_status) || self.on_timeline_status
354
360
  anything_proc = query_parameters.delete(:anything) || self.on_anything
361
+ no_data_proc = query_parameters.delete(:no_data_received) || self.on_no_data_received
355
362
 
356
363
  params = normalize_filter_parameters(query_parameters)
357
364
 
@@ -360,51 +367,42 @@ module TweetStream
360
367
  uri = method == :get ? build_uri(path, params) : build_uri(path)
361
368
 
362
369
  stream_params = {
363
- :path => uri,
364
- :method => method.to_s.upcase,
365
- :user_agent => user_agent,
366
- :on_inited => inited_proc,
367
- :filters => params.delete(:track),
368
- :params => params,
369
- :ssl => true
370
- }.merge(auth_params).merge(extra_stream_parameters)
371
-
372
- if @on_interval_proc.is_a?(Proc)
373
- interval = @on_interval_time || Configuration::DEFAULT_TIMER_INTERVAL
374
- @timer = EventMachine.add_periodic_timer(interval) do
375
- EventMachine.defer do
376
- @on_interval_proc.call
377
- end
378
- end
379
- end
380
-
381
- @stream = Twitter::JSONStream.connect(stream_params)
382
- @stream.each_item do |item|
370
+ :path => uri,
371
+ :method => method.to_s.upcase,
372
+ :user_agent => user_agent,
373
+ :on_inited => inited_proc,
374
+ :params => params
375
+ }.merge(extra_stream_parameters).merge(auth_params)
376
+
377
+ @stream = EM::Twitter::Client.connect(stream_params)
378
+ @stream.each do |item|
383
379
  begin
384
- raw_hash = json_parser.decode(item)
380
+ hash = MultiJson.decode(item)
385
381
  rescue MultiJson::DecodeError
386
382
  error_proc.call("MultiJson::DecodeError occured in stream: #{item}") if error_proc.is_a?(Proc)
387
383
  next
388
384
  end
389
385
 
390
- unless raw_hash.is_a?(::Hash)
386
+ unless hash.is_a?(::Hash)
391
387
  error_proc.call("Unexpected JSON object in stream: #{item}") if error_proc.is_a?(Proc)
392
388
  next
393
389
  end
394
390
 
395
- hash = TweetStream::Hash.new(raw_hash)
396
- if hash[:delete] && hash[:delete][:status]
397
- delete_proc.call(hash[:delete][:status][:id], hash[:delete][:status][:user_id]) if delete_proc.is_a?(Proc)
398
- elsif hash[:scrub_geo] && hash[:scrub_geo][:up_to_status_id]
399
- scrub_geo_proc.call(hash[:scrub_geo][:up_to_status_id], hash[:scrub_geo][:user_id]) if scrub_geo_proc.is_a?(Proc)
400
- elsif hash[:limit] && hash[:limit][:track]
401
- limit_proc.call(hash[:limit][:track]) if limit_proc.is_a?(Proc)
402
-
403
- elsif hash[:direct_message]
404
- yield_message_to direct_message_proc, TweetStream::DirectMessage.new(hash[:direct_message])
405
-
406
- elsif hash[:text] && hash[:user]
407
- @last_status = TweetStream::Status.new(hash)
391
+ if hash['control'] && hash['control']['control_uri']
392
+ @control_uri = hash['control']['control_uri']
393
+ require 'tweetstream/site_stream_client'
394
+ @control = TweetStream::SiteStreamClient.new(@control_uri, options)
395
+ @control.on_error(&self.on_error)
396
+ elsif hash['delete'] && hash['delete']['status']
397
+ delete_proc.call(hash['delete']['status']['id'], hash['delete']['status']['user_id']) if delete_proc.is_a?(Proc)
398
+ elsif hash['scrub_geo'] && hash['scrub_geo']['up_to_status_id']
399
+ scrub_geo_proc.call(hash['scrub_geo']['up_to_status_id'], hash['scrub_geo']['user_id']) if scrub_geo_proc.is_a?(Proc)
400
+ elsif hash['limit'] && hash['limit']['track']
401
+ limit_proc.call(hash['limit']['track']) if limit_proc.is_a?(Proc)
402
+ elsif hash['direct_message']
403
+ yield_message_to direct_message_proc, Twitter::DirectMessage.new(hash['direct_message'])
404
+ elsif hash['text'] && hash['user']
405
+ @last_status = Twitter::Status.new(hash)
408
406
  yield_message_to timeline_status_proc, @last_status
409
407
 
410
408
  if block_given?
@@ -417,6 +415,19 @@ module TweetStream
417
415
  yield @last_status, self
418
416
  end
419
417
  end
418
+ elsif hash['for_user']
419
+ @message = hash
420
+
421
+ if block_given?
422
+ # Give the block the option to receive either one
423
+ # or two arguments, depending on its arity.
424
+ case block.arity
425
+ when 1
426
+ yield @message
427
+ when 2
428
+ yield @message, self
429
+ end
430
+ end
420
431
  end
421
432
 
422
433
  yield_message_to anything_proc, hash
@@ -434,6 +445,10 @@ module TweetStream
434
445
  raise TweetStream::ReconnectError.new(timeout, retries)
435
446
  end
436
447
 
448
+ @stream.on_no_data_received do
449
+ no_data_proc.call if no_data_proc.is_a?(Proc)
450
+ end
451
+
437
452
  @stream
438
453
  end
439
454
 
@@ -454,11 +469,6 @@ module TweetStream
454
469
 
455
470
  protected
456
471
 
457
- def parser_from(parser)
458
- MultiJson.adapter = parser
459
- MultiJson
460
- end
461
-
462
472
  def build_uri(path, query_parameters = {}) #:nodoc:
463
473
  URI.parse("/1/#{path}.json#{build_query_parameters(query_parameters)}")
464
474
  end
@@ -488,19 +498,29 @@ module TweetStream
488
498
  end
489
499
 
490
500
  def auth_params
491
- case auth_method
492
- when :basic
493
- return :auth => "#{username}:#{password}"
494
- when :oauth
495
- return :oauth => {
496
- :consumer_key => consumer_key,
497
- :consumer_secret => consumer_secret,
498
- :access_key => oauth_token,
499
- :access_secret => oauth_token_secret
500
- }
501
+ if auth_method == :basic
502
+ { :basic => basic_auth_params }
503
+ else
504
+ { :oauth => oauth_params }
501
505
  end
502
506
  end
503
507
 
508
+ def basic_auth_params
509
+ {
510
+ :username => username,
511
+ :password => password
512
+ }
513
+ end
514
+
515
+ def oauth_params
516
+ {
517
+ :consumer_key => consumer_key,
518
+ :consumer_secret => consumer_secret,
519
+ :token => oauth_token,
520
+ :token_secret => oauth_token_secret
521
+ }
522
+ end
523
+
504
524
  def yield_message_to(procedure, message)
505
525
  if procedure.is_a?(Proc)
506
526
  case procedure.arity