intridea-tweetstream 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Intridea, Inc.
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.
@@ -0,0 +1,77 @@
1
+ = TweetStream
2
+
3
+ TweetStream provides simple Ruby access to Twitter's Streaming API
4
+ (http://apiwiki.twitter.com/Streaming-API-Documentation).
5
+
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
+
14
+ To install from Gemcutter:
15
+
16
+ gem sources -a http://gemcutter.org/
17
+ gem install tweetstream
18
+
19
+ == Usage
20
+
21
+ Using TweetStream is quite simple:
22
+
23
+ require 'rubygems'
24
+ require 'tweetstream'
25
+
26
+ # This will pull a sample of all tweets based on
27
+ # your Twitter account's Streaming API role.
28
+ TweetStream::Client.new('username','password').sample do |status|
29
+ # The status object is a special Hash with
30
+ # method access to its keys.
31
+ puts "#{status.text}"
32
+ end
33
+
34
+ You can also use it to track keywords or follow a given set of
35
+ user ids:
36
+
37
+ # Use 'track' to track a list of single-word keywords
38
+ TweetStream::Client.new('username','password').track('term1', 'term2') do |status|
39
+ puts "#{status.text}"
40
+ end
41
+
42
+ # Use 'follow' to follow a group of user ids (integers, not screen names)
43
+ TweetStream::Client.new('username','password').follow(14252, 53235) do |status|
44
+ puts "#{status.text}"
45
+ end
46
+
47
+ The methods available to TweetStream::Client will be kept in parity
48
+ with the methods available on the Streaming API wiki page.
49
+
50
+ == Daemonizing
51
+
52
+ It is also possible to create a daemonized script quite easily
53
+ using the TweetStream library:
54
+
55
+ # The third argument is an optional process name
56
+ TweetStream::Client.new('username','password', 'tracker').track('term1', 'term2') do |status|
57
+ # do something in the background
58
+ end
59
+
60
+ If you put the above into a script and run the script with <tt>ruby scriptname.rb</tt>, you will see a list of daemonization commands such
61
+ as start, stop, and run.
62
+
63
+ == Note on Patches/Pull Requests
64
+
65
+ * Fork the project.
66
+ * Make your feature addition or bug fix.
67
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
68
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
69
+ * Send me a pull request. Bonus points for topic branches.
70
+
71
+ == Contributors
72
+
73
+ * Michael Bleigh (initial gem)
74
+
75
+ == Copyright
76
+
77
+ Copyright (c) 2009 Intridea, Inc. (http://www.intridea.com/). See LICENSE for details.
@@ -0,0 +1,51 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "tweetstream"
8
+ gem.summary = %Q{TweetStream is a simple wrapper for consuming the Twitter Streaming API.}
9
+ gem.description = %Q{TweetStream allows you to easily consume the Twitter Streaming API utilizing the YAJL Ruby gem.}
10
+ gem.email = "michael@intridea.com"
11
+ gem.homepage = "http://github.com/intridea/tweetstream"
12
+ gem.authors = ["Michael Bleigh"]
13
+ gem.files = FileList["[A-Z]*", "{lib,spec}/**/*"] - FileList["**/*.log"]
14
+ gem.add_development_dependency "rspec"
15
+ gem.add_dependency 'yajl-ruby', '>= 0.6.3'
16
+ gem.add_dependency 'daemons'
17
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
+ end
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
21
+ end
22
+
23
+ require 'spec/rake/spectask'
24
+ Spec::Rake::SpecTask.new(:spec) do |spec|
25
+ spec.libs << 'lib' << 'spec'
26
+ spec.spec_files = FileList['spec/**/*_spec.rb']
27
+ end
28
+
29
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
30
+ spec.libs << 'lib' << 'spec'
31
+ spec.pattern = 'spec/**/*_spec.rb'
32
+ spec.rcov = true
33
+ end
34
+
35
+ task :spec => :check_dependencies
36
+
37
+ task :default => :spec
38
+
39
+ require 'rake/rdoctask'
40
+ Rake::RDocTask.new do |rdoc|
41
+ if File.exist?('VERSION')
42
+ version = File.read('VERSION')
43
+ else
44
+ version = ""
45
+ end
46
+
47
+ rdoc.rdoc_dir = 'rdoc'
48
+ rdoc.title = "tweetstream #{version}"
49
+ rdoc.rdoc_files.include('README*')
50
+ rdoc.rdoc_files.include('lib/**/*.rb')
51
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'tweetstream'
3
+ require 'logger'
4
+
5
+ File.open('tracker.log', File::WRONLY | File::APPEND | File::CREAT) do |file|
6
+ log = Logger.new(file)
7
+
8
+ TweetStream::Daemon.new('mbleigh','hotmail', 'tracker').track('fail') do |status|
9
+ log.info "[#{status.user.screen_name}] #{status.text}"
10
+ puts "[#{status.user.screen_name}] #{status.text}"
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ require 'tweetstream/client'
2
+ require 'tweetstream/hash'
3
+ require 'tweetstream/status'
4
+ require 'tweetstream/user'
5
+ require 'tweetstream/daemon'
@@ -0,0 +1,109 @@
1
+ require 'uri'
2
+ require 'cgi'
3
+ require 'yajl'
4
+ require 'yajl/http_stream'
5
+
6
+ module TweetStream
7
+ # Provides simple access to the Twitter Streaming API (http://apiwiki.twitter.com/Streaming-API-Documentation)
8
+ # for Ruby scripts that need to create a long connection to
9
+ # Twitter for tracking and other purposes.
10
+ #
11
+ # Basic usage of the library is to call one of the provided
12
+ # methods and provide a block that will perform actions on
13
+ # a yielded TweetStream::Status. For example:
14
+ #
15
+ # TweetStream::Client.new('user','pass').track('fail') do |status|
16
+ # puts "[#{status.user.screen_name}] #{status.text}"
17
+ # end
18
+ #
19
+ # For information about a daemonized TweetStream client,
20
+ # view the TweetStream::Daemon class.
21
+ class Client
22
+ attr_accessor :username, :password
23
+
24
+ # Create a new client with the Twitter credentials
25
+ # of the account you want to be using its API quota.
26
+ def initialize(user, pass)
27
+ self.username = user
28
+ self.password = pass
29
+ end
30
+
31
+ # Returns all public statuses. The Firehose is not a generally
32
+ # available resource. Few applications require this level of access.
33
+ # Creative use of a combination of other resources and various access
34
+ # levels can satisfy nearly every application use case.
35
+ def firehose(query_parameters = {}, &block)
36
+ start('statuses/firehose', query_parameters, &block)
37
+ end
38
+
39
+ # Returns all retweets. The retweet stream is not a generally available
40
+ # resource. Few applications require this level of access. Creative
41
+ # use of a combination of other resources and various access levels
42
+ # can satisfy nearly every application use case. As of 9/11/2009,
43
+ # the site-wide retweet feature has not yet launched,
44
+ # so there are currently few, if any, retweets on this stream.
45
+ def retweet(query_parameters = {}, &block)
46
+ start('statuses/retweet', query_parameters, &block)
47
+ end
48
+
49
+ # Returns a random sample of all public statuses. The default access level
50
+ # provides a small proportion of the Firehose. The "Gardenhose" access
51
+ # level provides a proportion more suitable for data mining and
52
+ # research applications that desire a larger proportion to be statistically
53
+ # significant sample.
54
+ def sample(query_parameters = {}, &block)
55
+ start('statuses/sample', query_parameters, &block)
56
+ end
57
+
58
+ # Specify keywords to track. Queries are subject to Track Limitations,
59
+ # described in Track Limiting and subject to access roles, described in
60
+ # the statuses/filter method. Track keywords are case-insensitive logical
61
+ # ORs. Terms are exact-matched, and also exact-matched ignoring
62
+ # punctuation. Phrases, keywords with spaces, are not supported.
63
+ # Keywords containing punctuation will only exact match tokens.
64
+ # Query parameters may be passed as the last argument.
65
+ def track(*keywords, &block)
66
+ query_params = keywords.pop if keywords.last.is_a?(::Hash)
67
+ query_params ||= {}
68
+ start('statuses/filter', query_params.merge(:track => keywords.join(',')), &block)
69
+ end
70
+
71
+ # Returns public statuses from or in reply to a set of users. Mentions
72
+ # ("Hello @user!") and implicit replies ("@user Hello!" created without
73
+ # pressing the reply "swoosh") are not matched. Requires integer user
74
+ # IDs, not screen names. Query parameters may be passed as the last argument.
75
+ def follow(*user_ids, &block)
76
+ query_params = user_ids.pop if user_ids.last.is_a?(::Hash)
77
+ query_params ||= {}
78
+ start('statuses/filter', query_params.merge(:follow => user_ids.join(',')), &block)
79
+ end
80
+
81
+ #:nodoc:
82
+ def start(path, query_parameters = {}, &block)
83
+ uri = build_uri(path, query_parameters)
84
+
85
+ Yajl::HttpStream.get(uri, :symbolize_keys => true) do |hash|
86
+ yield TweetStream::Status.new(hash)
87
+ end
88
+ end
89
+
90
+ protected
91
+
92
+ #:nodoc:
93
+ def build_uri(path, query_parameters = {})
94
+ URI.parse("http://#{self.username}:#{self.password}@stream.twitter.com/1/#{path}.json#{build_query_parameters(query_parameters)}")
95
+ end
96
+
97
+ #:nodoc:
98
+ def build_query_parameters(query)
99
+ return '' unless query && query.is_a?(::Hash) && query.size > 0
100
+ pairs = []
101
+
102
+ query.each_pair do |k,v|
103
+ pairs << "#{k.to_s}=#{CGI.escape(v.to_s)}"
104
+ end
105
+
106
+ "?#{pairs.join('&')}"
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,40 @@
1
+ require 'daemons'
2
+
3
+ # A daemonized TweetStream client that will allow you to
4
+ # create backgroundable scripts for application specific
5
+ # processes. For instance, if you create a script called
6
+ # <tt>tracker.rb</tt> and fill it with this:
7
+ #
8
+ # require 'rubygems'
9
+ # require 'tweetstream'
10
+ #
11
+ # TweetStream::Daemon.new('user','pass', 'tracker').track('intridea') do |status|
12
+ # # do something here
13
+ # end
14
+ #
15
+ # And then you call this from the shell:
16
+ #
17
+ # ruby tracker.rb start
18
+ #
19
+ # A daemon process will spawn that will automatically
20
+ # run the code in the passed block whenever a new tweet
21
+ # matching your search term ('intridea' in this case)
22
+ # is posted.
23
+ #
24
+ class TweetStream::Daemon < TweetStream::Client
25
+ # Initialize a Daemon with the credentials of the
26
+ # Twitter account you wish to use. The daemon has
27
+ # an optional process name for use when querying
28
+ # running processes.
29
+ def initialize(user, pass, app_name=nil)
30
+ @app_name = app_name
31
+ super(user, pass)
32
+ end
33
+
34
+ #:nodoc:
35
+ def start(path, query_parameters = {}, &block)
36
+ Daemons.run_proc(@app_name || 'tweetstream', :multiple => true) do
37
+ super(path, query_parameters, &block)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,16 @@
1
+ #:nodoc:
2
+ class TweetStream::Hash < ::Hash
3
+ def initialize(other_hash)
4
+ other_hash.keys.each do |key|
5
+ self[key.to_sym] = other_hash[key]
6
+ end
7
+ end
8
+
9
+ def method_missing(method_name, *args)
10
+ if key?(method_name.to_sym)
11
+ self[method_name.to_sym]
12
+ else
13
+ super
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ # A simple Hash wrapper that gives you method-based
2
+ # access to the properties of a Twitter status.
3
+ class TweetStream::Status < TweetStream::Hash
4
+ def initialize(hash)
5
+ super
6
+ self[:user] = TweetStream::User.new(self[:user])
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ # A simple Hash wrapper that gives you method-based
2
+ # access to user properties returned by the streamer.
3
+ class TweetStream::User < TweetStream::Hash
4
+
5
+ end
@@ -0,0 +1 @@
1
+ {"favorited":false,"text":"listening to Where U Headed by Universal Playaz. http://iLike.com/s/9zpOZ #musicmonday something for the ladies","in_reply_to_user_id":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://www.iLike.com\" rel=\"nofollow\">iLike</a>","truncated":false,"created_at":"Tue Sep 22 01:29:13 +0000 2009","user":{"statuses_count":378,"favourites_count":1,"profile_text_color":"666666","location":"Atlanta, Ga","profile_background_image_url":"http://a3.twimg.com/profile_background_images/36516125/Universal_Playaz.jpg","profile_link_color":"2FC2EF","description":"Paper Chaser","following":null,"verified":false,"notifications":null,"profile_sidebar_fill_color":"252429","profile_image_url":"http://a1.twimg.com/profile_images/413331530/DIESELSTATScopy_normal.jpg","url":"http://www.myspace.com/DieselDtheg","profile_sidebar_border_color":"181A1E","screen_name":"DieselD2143","profile_background_tile":true,"followers_count":75,"protected":false,"time_zone":"Eastern Time (US & Canada)","created_at":"Thu Jun 18 15:56:32 +0000 2009","name":"Diesel D","friends_count":119,"profile_background_color":"1A1B1F","id":48392351,"utc_offset":-18000},"in_reply_to_status_id":null,"id":4161231023} {"favorited":false,"text":"David Bowie and Nine Inch Nails perform \"Hurt\" http://bit.ly/AOaWG #musicmonday #nineinchnails #nin","in_reply_to_user_id":null,"in_reply_to_screen_name":null,"source":"web","truncated":false,"created_at":"Tue Sep 22 01:29:16 +0000 2009","user":{"statuses_count":668,"favourites_count":25,"profile_text_color":"445d85","location":"S\u00e3o Paulo, Brazil","profile_background_image_url":"http://a3.twimg.com/profile_background_images/38174991/GeorgeRomero-oil-400.jpg","profile_link_color":"555757","description":"You think I ain't worth a dollar, but I feel like a millionaire","following":null,"verified":false,"notifications":null,"profile_sidebar_fill_color":"a3a7ad","profile_image_url":"http://a1.twimg.com/profile_images/96034368/n1076431955_30001395_7912_normal.jpg","url":null,"profile_sidebar_border_color":"c7d1ed","screen_name":"RenatonMiranda","profile_background_tile":true,"followers_count":111,"protected":false,"time_zone":"Santiago","created_at":"Sat Mar 14 15:03:59 +0000 2009","name":"Renato Miranda","friends_count":143,"profile_background_color":"287356","id":24379310,"utc_offset":-14400},"in_reply_to_status_id":null,"id":4161232008} {"favorited":false,"text":"#musicmonday ,time to download some songs today!! :)","in_reply_to_user_id":null,"in_reply_to_screen_name":null,"source":"web","truncated":false,"created_at":"Tue Sep 22 01:29:19 +0000 2009","user":{"statuses_count":188,"favourites_count":0,"profile_text_color":"3D1957","location":"under the water","profile_background_image_url":"http://s.twimg.com/a/1253562286/images/themes/theme10/bg.gif","profile_link_color":"FF0000","description":"ask me ","following":null,"verified":false,"notifications":null,"profile_sidebar_fill_color":"7AC3EE","profile_image_url":"http://a1.twimg.com/profile_images/421281292/twit_pic_normal.jpg","url":"http://www.exploretalent.com/contest_video.php?talentnum=2053105&cm_id=3398","profile_sidebar_border_color":"65B0DA","screen_name":"julieanne11343","profile_background_tile":true,"followers_count":9,"protected":false,"time_zone":"Pacific Time (US & Canada)","created_at":"Mon Jul 20 21:08:22 +0000 2009","name":"Julieanne","friends_count":17,"profile_background_color":"642D8B","id":58591151,"utc_offset":-28800},"in_reply_to_status_id":null,"id":4161233120} {"text":"#Musicmonday \"Dont be tardy f0r the party\"","truncated":false,"source":"<a href=\"http://twitterhelp.blogspot.com/2008/05/twitter-via-mobile-web-mtwittercom.html\" rel=\"nofollow\">mobile web</a>","in_reply_to_status_id":null,"favorited":false,"created_at":"Tue Sep 22 01:29:19 +0000 2009","user":{"verified":false,"notifications":null,"profile_sidebar_fill_color":"e0ff92","location":"Dope Girl Island","profile_sidebar_border_color":"87bc44","description":"","following":null,"profile_background_tile":false,"followers_count":29,"profile_image_url":"http://a3.twimg.com/profile_images/217487577/badbad_normal.jpg","time_zone":"Eastern Time (US & Canada)","url":null,"friends_count":65,"profile_background_color":"9ae4e8","screen_name":"SwagGirlOnDeck","protected":false,"statuses_count":847,"favourites_count":0,"created_at":"Fri May 01 16:59:15 +0000 2009","profile_text_color":"000000","name":"Mariah Reta","id":36987168,"profile_background_image_url":"http://s.twimg.com/a/1253301564/images/themes/theme1/bg.png","utc_offset":-18000,"profile_link_color":"0000ff"},"in_reply_to_user_id":null,"id":4161233317,"in_reply_to_screen_name":null}
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format progress
@@ -0,0 +1,24 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'rubygems'
5
+ require 'tweetstream'
6
+ require 'spec'
7
+ require 'spec/autorun'
8
+ require 'yajl'
9
+
10
+ def sample_tweets
11
+ if @tweets
12
+ @tweets
13
+ else
14
+ @tweets = []
15
+ Yajl::Parser.parse(File.open(File.dirname(__FILE__) + '/data/statuses.json', 'r')) do |hash|
16
+ @tweets << hash
17
+ end
18
+ @tweets
19
+ end
20
+ end
21
+
22
+ Spec::Runner.configure do |config|
23
+
24
+ end
@@ -0,0 +1,122 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe TweetStream::Client do
4
+ it 'should set the username and password from the initializers' do
5
+ @client = TweetStream::Client.new('abc','def')
6
+ @client.username.should == 'abc'
7
+ @client.password.should == 'def'
8
+ end
9
+
10
+ describe '#build_uri' do
11
+ before do
12
+ @client = TweetStream::Client.new('abc','def')
13
+ end
14
+
15
+ it 'should return a URI' do
16
+ @client.send(:build_uri, '').is_a?(URI).should be_true
17
+ end
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
+ it 'should have the specified path with the version prefix and a json extension' do
25
+ @client.send(:build_uri, 'awesome').path.should == '/1/awesome.json'
26
+ end
27
+
28
+ it 'should add on a query string if such parameters are specified' do
29
+ @client.send(:build_uri, 'awesome', :q => 'abc').query.should == 'q=abc'
30
+ end
31
+ end
32
+
33
+ describe '#build_query_parameters' do
34
+ before do
35
+ @client = TweetStream::Client.new('abc','def')
36
+ end
37
+
38
+ it 'should return a blank string if passed a nil value' do
39
+ @client.send(:build_query_parameters, nil).should == ''
40
+ end
41
+
42
+ it 'should return a blank string if passed an empty hash' do
43
+ @client.send(:build_query_parameters, {}).should == ''
44
+ end
45
+
46
+ it 'should add a query parameter for a key' do
47
+ @client.send(:build_query_parameters, {:query => 'abc'}).should == '?query=abc'
48
+ end
49
+
50
+ it 'should escape characters in the value' do
51
+ @client.send(:build_query_parameters, {:query => 'awesome guy'}).should == '?query=awesome+guy'
52
+ end
53
+
54
+ it 'should join multiple pairs together' do
55
+ ['?a=b&c=d','?c=d&a=b'].include?(@client.send(:build_query_parameters, {:a => 'b', :c => 'd'})).should be_true
56
+ end
57
+ end
58
+
59
+ describe '#start' do
60
+ before do
61
+ @client = TweetStream::Client.new('abc','def')
62
+ end
63
+
64
+ it 'should make a call to Yajl::HttpStream' do
65
+ Yajl::HttpStream.should_receive(:get).once.with(URI.parse('http://abc:def@stream.twitter.com/1/cool.json'), :symbolize_keys => true).and_return({})
66
+ @client.start('cool')
67
+ end
68
+
69
+ it 'should yield a TwitterStream::Status for each update' do
70
+ Yajl::HttpStream.should_receive(:get).once.with(URI.parse('http://abc:def@stream.twitter.com/1/statuses/filter.json?track=musicmonday'), :symbolize_keys => true).and_yield(sample_tweets[0])
71
+ @client.track('musicmonday') do |status|
72
+ status.is_a?(TweetStream::Status).should be_true
73
+ @yielded = true
74
+ end
75
+ @yielded.should be_true
76
+ end
77
+ end
78
+
79
+ describe ' API methods' do
80
+ before do
81
+ @client = TweetStream::Client.new('abc','def')
82
+ end
83
+
84
+ %w(firehose retweet sample).each do |method|
85
+ it "##{method} should make a call to start with \"statuses/#{method}\"" do
86
+ @client.should_receive(:start).once.with('statuses/' + method, {})
87
+ @client.send(method)
88
+ end
89
+ end
90
+
91
+ it '#track should make a call to start with "statuses/filter" and a track query parameter' do
92
+ @client.should_receive(:start).once.with('statuses/filter', :track => 'test')
93
+ @client.track('test')
94
+ end
95
+
96
+ it '#track should comma-join multiple arguments' do
97
+ @client.should_receive(:start).once.with('statuses/filter', :track => 'foo,bar,baz')
98
+ @client.track('foo', 'bar', 'baz')
99
+ end
100
+
101
+ it '#follow should make a call to start with "statuses/filter" and a follow query parameter' do
102
+ @client.should_receive(:start).once.with('statuses/filter', :follow => '123')
103
+ @client.follow(123)
104
+ end
105
+
106
+ it '#follow should comma-join multiple arguments' do
107
+ @client.should_receive(:start).once.with('statuses/filter', :follow => '123,456')
108
+ @client.follow(123, 456)
109
+ end
110
+ end
111
+
112
+ describe '#track' do
113
+ before do
114
+ @client = TweetStream::Client.new('abc','def')
115
+ end
116
+
117
+ it 'should call #start with "statuses/filter" and the provided queries' do
118
+ @client.should_receive(:start).once.with('statuses/filter', :track => 'rock')
119
+ @client.track('rock')
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,19 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe TweetStream::Hash do
4
+ it 'should be initialized by passing in an existing hash' do
5
+ TweetStream::Hash.new(:abc => 123)[:abc].should == 123
6
+ end
7
+
8
+ it 'should symbolize incoming keys' do
9
+ TweetStream::Hash.new('abc' => 123)[:abc].should == 123
10
+ end
11
+
12
+ it 'should allow access via method calls' do
13
+ TweetStream::Hash.new(:abc => 123).abc.should == 123
14
+ end
15
+
16
+ it 'should still throw NoMethod for non-existent keys' do
17
+ lambda{TweetStream::Hash.new({}).akabi}.should raise_error(NoMethodError)
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe TweetStream::Status do
4
+ it 'should modify the :user key into a TweetStream::User object' do
5
+ @status = TweetStream::Status.new(:user => {:screen_name => 'bob'})
6
+ @status.user.is_a?(TweetStream::User).should be_true
7
+ @status.user.screen_name.should == 'bob'
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe TweetStream do
4
+
5
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: intridea-tweetstream
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Michael Bleigh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-09-22 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: yajl-ruby
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.6.3
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: daemons
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ description: TweetStream allows you to easily consume the Twitter Streaming API utilizing the YAJL Ruby gem.
46
+ email: michael@intridea.com
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - LICENSE
53
+ - README.rdoc
54
+ files:
55
+ - LICENSE
56
+ - README.rdoc
57
+ - Rakefile
58
+ - VERSION
59
+ - lib/tracker.rb
60
+ - lib/tweetstream.rb
61
+ - lib/tweetstream/client.rb
62
+ - lib/tweetstream/daemon.rb
63
+ - lib/tweetstream/hash.rb
64
+ - lib/tweetstream/status.rb
65
+ - lib/tweetstream/user.rb
66
+ - spec/data/statuses.json
67
+ - spec/spec.opts
68
+ - spec/spec_helper.rb
69
+ - spec/tweetstream/client_spec.rb
70
+ - spec/tweetstream/hash_spec.rb
71
+ - spec/tweetstream/status_spec.rb
72
+ - spec/tweetstream_spec.rb
73
+ has_rdoc: false
74
+ homepage: http://github.com/intridea/tweetstream
75
+ licenses:
76
+ post_install_message:
77
+ rdoc_options:
78
+ - --charset=UTF-8
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: "0"
86
+ version:
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: "0"
92
+ version:
93
+ requirements: []
94
+
95
+ rubyforge_project:
96
+ rubygems_version: 1.3.5
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: TweetStream is a simple wrapper for consuming the Twitter Streaming API.
100
+ test_files:
101
+ - spec/spec_helper.rb
102
+ - spec/tweetstream/client_spec.rb
103
+ - spec/tweetstream/hash_spec.rb
104
+ - spec/tweetstream/status_spec.rb
105
+ - spec/tweetstream_spec.rb