tweetable 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. data/Gemfile +8 -0
  2. data/History.txt +4 -0
  3. data/Manifest.txt +33 -0
  4. data/PostInstall.txt +7 -0
  5. data/README.rdoc +37 -0
  6. data/Rakefile +19 -0
  7. data/VERSION +1 -0
  8. data/lib/tweetable/authorization.rb +21 -0
  9. data/lib/tweetable/collection.rb +54 -0
  10. data/lib/tweetable/link.rb +30 -0
  11. data/lib/tweetable/message.rb +119 -0
  12. data/lib/tweetable/persistable.rb +32 -0
  13. data/lib/tweetable/photo.rb +6 -0
  14. data/lib/tweetable/queue.rb +121 -0
  15. data/lib/tweetable/search.rb +77 -0
  16. data/lib/tweetable/twitter_client.rb +36 -0
  17. data/lib/tweetable/twitter_streaming_client.rb +67 -0
  18. data/lib/tweetable/url.rb +39 -0
  19. data/lib/tweetable/user.rb +104 -0
  20. data/lib/tweetable.rb +82 -0
  21. data/pkg/tweetable-0.1.7.gem +0 -0
  22. data/script/console +10 -0
  23. data/script/destroy +14 -0
  24. data/script/generate +14 -0
  25. data/spec/collection_spec.rb +55 -0
  26. data/spec/fixtures/blank.json +1 -0
  27. data/spec/fixtures/flippyhead.json +1 -0
  28. data/spec/fixtures/follower_ids.json +1 -0
  29. data/spec/fixtures/friend_ids.json +1 -0
  30. data/spec/fixtures/friends_timeline.json +1 -0
  31. data/spec/fixtures/link_blank.json +1 -0
  32. data/spec/fixtures/link_exists.json +1 -0
  33. data/spec/fixtures/rate_limit_status.json +1 -0
  34. data/spec/fixtures/search.json +1 -0
  35. data/spec/fixtures/user_timeline.json +1 -0
  36. data/spec/fixtures/verify_credentials.json +1 -0
  37. data/spec/link_spec.rb +35 -0
  38. data/spec/message_spec.rb +148 -0
  39. data/spec/persistable_spec.rb +53 -0
  40. data/spec/queue_spec.rb +29 -0
  41. data/spec/search_spec.rb +60 -0
  42. data/spec/spec.opts +5 -0
  43. data/spec/spec_helper.rb +55 -0
  44. data/spec/tweetable_spec.rb +19 -0
  45. data/spec/twitter_client_spec.rb +41 -0
  46. data/spec/twitter_streaming_client_spec.rb +18 -0
  47. data/spec/user_spec.rb +143 -0
  48. data/tweetable.gemspec +106 -0
  49. metadata +165 -0
@@ -0,0 +1 @@
1
+ {"created_at":"Wed Feb 20 04:05:51 +0000 2008","description":"Haha made ya read!","profile_background_tile":false,"profile_link_color":"FF0000","status":{"created_at":"Sun Apr 04","in_reply_to_status_id":null,"favorited":false,"source":"<a href=\"http://gettwidget.com/\" rel=\"nofollow\">Twidget</a>","in_reply_to_user_id":null,"truncated":false,"in_reply_to_screen_name":null,"id":11572672967,"text":"http://iamawesome.com/"},"following":false,"followers_count":229,"statuses_count":247,"profile_sidebar_fill_color":"FFF7CC","url":"http://wagglelabs.com","notifications":false,"friends_count":339,"profile_image_url":"http://a3.twimg.com/profile_images/74792235/screen-capture-2_normal.png","contributors_enabled":false,"time_zone":"Pacific Time (US & Canada)","profile_sidebar_border_color":"F2E195","location":"Capitol Hill, Washington","favourites_count":2,"screen_name":"Flippyhead","protected":false,"geo_enabled":true,"profile_background_color":"BADFCD","name":"Peter T. Brown","id":13705052,"lang":"en","verified":false,"profile_background_image_url":"http://s.twimg.com/a/1269553143/images/themes/theme12/bg.gif","utc_offset":-28800,"profile_text_color":"0C3E53"}
data/spec/link_spec.rb ADDED
@@ -0,0 +1,35 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ attrs = {:url => 'http://someurl.com', :created_at => Time.now.utc.to_s, :screen_name => 'somename'}
4
+
5
+ describe Tweetable::Link, 'when doing CRUD' do
6
+ before do
7
+ RedisSpecHelper.reset
8
+ @link = Tweetable::Link.create(:url => attrs[:url], :created_at => attrs[:created_at])
9
+ end
10
+
11
+ it "should find link by URL" do
12
+ link = Tweetable::Link.find(:url => attrs[:url]).first
13
+ link.url.should == attrs[:url]
14
+ end
15
+ end
16
+
17
+ describe Tweetable::Link, 'when counting' do
18
+ before do
19
+ RedisSpecHelper.reset
20
+ @link = Tweetable::Link.create(:url => attrs[:url], :created_at => attrs[:created_at])
21
+ @user = Tweetable::User.create(:screen_name => attrs[:screen_name])
22
+ @link.users.add(@user)
23
+ end
24
+
25
+ it "should not increment count for users already in set" do
26
+ @link.should_not_receive(:incr).with(:count)
27
+ @link.increment_usage_count(@user)
28
+ end
29
+
30
+ it "should increment count for users already in set" do
31
+ user = Tweetable::User.create(:screen_name => attrs[:screen_name] + '_other')
32
+ @link.should_receive(:incr).with(:count)
33
+ @link.increment_usage_count(user)
34
+ end
35
+ end
@@ -0,0 +1,148 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ attrs = {:short_url => 'http://bit.ly/k1n4M', :long_url => 'http://pathable.com', :from_screen_name => 'somename'}
4
+
5
+ describe Tweetable::Message do
6
+ before do
7
+ RedisSpecHelper.reset
8
+ stub_get('http://www.longurlplease.com/api/v1.1?q=http%3A%2F%2Fwww.thisisalink.com%2Fwith-a-path%2Fand-so_forth.xml', 'link_blank.json')
9
+ stub_get('http://www.longurlplease.com/api/v1.1?q=http%3A%2F%2Fbit.ly%2Fk1n4M', 'link_exists.json')
10
+
11
+ @user = Tweetable::User.create(:screen_name => attrs[:from_screen_name])
12
+ @message = Tweetable::Message.create(
13
+ :message_id => '1234',
14
+ :text => "here a link http://www.thisisalink.com/with-a-path/and-so_forth.xml there a link #{attrs[:short_url]}",
15
+ :links_parsed => "0",
16
+ :photos_parsed => "0",
17
+ :from_screen_name => attrs[:from_screen_name],
18
+ :created_at => Time.now
19
+ )
20
+ @message.parse_links
21
+ end
22
+
23
+ context "when doing CRUD" do
24
+ it "shuould find from_user" do
25
+ @message.from_user.should == @user
26
+ end
27
+
28
+ it "should consider two objects with same id ==" do
29
+ copy = @message.dup
30
+ (copy == @message).should be_true
31
+ end
32
+ end
33
+
34
+ context "when purging" do
35
+ it "should get all" do
36
+ Tweetable::Message.should_receive(:all).and_return(mock("AllMessages", :sort => []))
37
+ Tweetable::Message.purge
38
+ end
39
+
40
+ it "should delete message if block returns true" do
41
+ mock_message = mock(Tweetable::Message)
42
+ mock_message.should_receive(:delete).once
43
+
44
+ Tweetable::Message.should_receive(:all).and_return(mock("AllMessages", :sort => [mock_message]))
45
+ Tweetable::Message.purge do
46
+ true
47
+ end
48
+ end
49
+
50
+ it "should not delete message if block returns false" do
51
+ mock_message = mock(Tweetable::Message)
52
+ mock_message.should_receive(:delete).never
53
+
54
+ Tweetable::Message.should_receive(:all).and_return(mock("AllMessages", :sort => [mock_message]))
55
+ Tweetable::Message.purge do
56
+ false
57
+ end
58
+ end
59
+ end
60
+
61
+ context "when parsing links" do
62
+ it "should should add of Link type" do
63
+ @message.links.first.should be_instance_of Tweetable::Link
64
+ end
65
+
66
+ it "should add with correct URL" do
67
+ @message.links.first.url.should == 'http://www.thisisalink.com/with-a-path/and-so_forth.xml'
68
+ end
69
+
70
+ it "should extract multiple" do
71
+ @message.links.size.should == 2
72
+ end
73
+
74
+ it "should initialize counter at 1" do
75
+ @message.links.first.count.should == 1
76
+ end
77
+
78
+ it "should flag message as parsed" do
79
+ @message.links_parsed.should == "1"
80
+ end
81
+
82
+ it "should not parse already parsed" do
83
+ @message.text.should_not_receive(:scan)
84
+ @message.parse_links
85
+ end
86
+
87
+ it "should be able to find parsed links" do
88
+ @message.parse_links
89
+ link = Tweetable::Link.find(:url => attrs[:short_url]).first
90
+ link.should_not be_nil
91
+ end
92
+
93
+ it "should search messages for non parsed links" do
94
+ Tweetable::Message.find(:links_parsed => "0") do |results|
95
+ results.each do |message|
96
+ links = message.parse_links
97
+ links.size.should == 1
98
+ end
99
+ end
100
+ end
101
+
102
+ it "should get long url for short urls" do
103
+ @message.links.all[1].long_url.should == attrs[:long_url]
104
+ end
105
+
106
+ it "should increment links count on other messages with link" do
107
+ Tweetable::User.create(:screen_name => attrs[:from_screen_name] + '_other')
108
+
109
+ message = Tweetable::Message.create(
110
+ :message_id => '5678',
111
+ :text => "xxx #{attrs[:short_url]} rrr",
112
+ :created_at => Time.now.utc.to_s,
113
+ :from_screen_name => attrs[:from_screen_name] + '_other',
114
+ :links_parsed => "0",
115
+ :photos_parsed => "0")
116
+
117
+ message.parse_links
118
+ message.links.first.count.should == 2
119
+ end
120
+
121
+ it "should not increment links count on other messages from same user" do
122
+ message = Tweetable::Message.create(
123
+ :message_id => '5678',
124
+ :text => "xxx #{attrs[:short_url]} rrr",
125
+ :links_parsed => "0",
126
+ :photos_parsed => "0",
127
+ :from_screen_name => attrs[:from_screen_name],
128
+ :created_at => Time.now)
129
+
130
+ message.parse_links
131
+ message.links.first.count.should == 1
132
+ end
133
+
134
+ it "should not try to create already existing link" do
135
+ message = Tweetable::Message.create(:message_id => '5678', :text => "xxx #{attrs[:short_url]}", :created_at => Time.now, :links_parsed => "0", :photos_parsed => "0")
136
+ Tweetable::Link.should_not_receive(:create)
137
+ message.parse_links
138
+ end
139
+ end
140
+
141
+ context 'when posting status updates' do
142
+ it "should return new messages" do
143
+ # Tweetable::Message.should_receive(:create_from_timeline).once
144
+ # Tweetable::Message.create_from_status('a status update')
145
+ end
146
+ end
147
+ end
148
+
@@ -0,0 +1,53 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ attrs = {:now => Time.new.to_s, :then => 'Sat Sep 26 13:32:22 -0700 2009'}
4
+
5
+ describe Tweetable::Persistable do
6
+ before do
7
+ RedisSpecHelper.reset
8
+ end
9
+
10
+ context 'when building' do
11
+ before do
12
+ Tweetable.login('l', 'p')
13
+ end
14
+
15
+ it "should have a twitter client" do
16
+ item = Tweetable::Persistable.create(:created_at => attrs[:now], :updated_at => attrs[:now])
17
+ item.send(:client).class.should == Tweetable::TwitterClient
18
+ end
19
+
20
+ it "should store a persistable item with dates" do
21
+ item = Tweetable::Persistable.create(:created_at => attrs[:now], :updated_at => attrs[:now])
22
+ item.should be_valid
23
+ end
24
+
25
+ it "should find or create new" do
26
+ item = Tweetable::User.find_or_create(:screen_name, 'Flippyhead')
27
+ item.should be_valid
28
+ end
29
+
30
+ it "should find or create existing" do
31
+ existing = Tweetable::User.create(:screen_name => 'Flippyhead', :created_at => Time.now.utc.to_s)
32
+ item = Tweetable::User.find_or_create(:screen_name, 'Flippyhead')
33
+ existing.id.to_s.should == item.id.to_s
34
+ end
35
+ end
36
+
37
+ context 'when needs update' do
38
+ it "should not need_update when new" do
39
+ item = Tweetable::Persistable.create(:updated_at => attrs[:now])
40
+ item.should_not be_needs_update
41
+ end
42
+
43
+ it "should need_update when old enough" do
44
+ item = Tweetable::Persistable.create(:updated_at => attrs[:then])
45
+ item.should be_needs_update
46
+ end
47
+
48
+ it "should need_update when forced" do
49
+ item = Tweetable::Persistable.create(:updated_at => attrs[:now])
50
+ item.should be_needs_update(true)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,29 @@
1
+ # require File.dirname(__FILE__) + '/spec_helper.rb'
2
+ #
3
+ # search_attrs ={:name => 'test-search_queue', :queries => ['google','pathable']}
4
+ #
5
+ # describe Tweetable::Queue, 'when adding to search queue' do
6
+ # before do
7
+ # RedisSpecHelper.reset
8
+ # end
9
+ #
10
+ # it "should create search queue" do
11
+ # Tweetable::Queue.add_to_search_queue(search_attrs[:name], search_attrs[:queries])
12
+ # queue = Tweetable::SearchCollection.find(:name, search_attrs[:name]).first
13
+ # queue.should_not be_nil
14
+ # end
15
+ #
16
+ # it "should add queries to queue collection" do
17
+ # Tweetable::Queue.add_to_search_queue(search_attrs[:name], search_attrs[:queries])
18
+ # queue = Tweetable::SearchCollection.find(:name, search_attrs[:name]).first
19
+ # queue.searches.size.should == 2
20
+ # end
21
+ #
22
+ # it "should process things passed to block" do
23
+ # Tweetable::Queue.add_to_search_queue(search_attrs[:name], search_attrs[:queries]) do |search|
24
+ # search.update(:query => 'xxx')
25
+ # end
26
+ # queue = Tweetable::SearchCollection.find(:name, search_attrs[:name]).first
27
+ # queue.searches.collect{|s| s.query}.should include('xxx')
28
+ # end
29
+ # end
@@ -0,0 +1,60 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ attrs = {:valid_query => 'google'}
4
+
5
+ describe Tweetable::Search, 'when searching' do
6
+ before do
7
+ RedisSpecHelper.reset
8
+ @search = Tweetable::Search.create(:query => attrs[:valid_query], :created_at => DateTime.now)
9
+ end
10
+
11
+ context 'when searching' do
12
+ before do
13
+ 14.times do |page|
14
+ stub_get("http://search.twitter.com/search.json?rpp=100&page=#{page}&since_id=0&q=google", 'search.json')
15
+ end
16
+ end
17
+
18
+ it "should find messages for valid search" do
19
+ @search.update_messages(1)
20
+ @search.messages.first.should be_instance_of Tweetable::Message
21
+ end
22
+
23
+ it "should store messages after search" do
24
+ @search.update_messages(1)
25
+ search = Tweetable::Search.find(:query => 'google').first
26
+ search.messages.first.should be_instance_of Tweetable::Message
27
+ end
28
+
29
+ it "should create users associated with messages" do
30
+ @search.update_messages(1)
31
+ search = Tweetable::Search.find(:query => 'google').first
32
+ search.messages.first.from_user.should be_instance_of Tweetable::User
33
+ end
34
+
35
+ it "should update existing messages but not duplicate in messages list" do
36
+ stub_get("http://search.twitter.com/search.json?q=google&rpp=100&since_id=11674745688&page=1", 'search.json') # since_id is last id in search.json
37
+
38
+ @search.update_messages(1)
39
+ search = Tweetable::Search.find(:query => 'google').first
40
+ search.messages.size.should == 100
41
+
42
+ @search.update_messages(1)
43
+ search.messages.size.should == 100 # not adding duplicates to messages list
44
+ end
45
+
46
+ it "should get multiple pages" do
47
+ array = Array.new
48
+ array.stub!(:size => 100)
49
+ @search.should_receive(:search).exactly(3).times.and_return(mock('search', :results => array))
50
+ @search.update_messages(3)
51
+ end
52
+ end
53
+
54
+ context 'when doing CRUD' do
55
+ it "should have validations errors with invald data" do
56
+ item = Tweetable::Search.create(:created_at => DateTime.now)
57
+ item.errors.should == [[:query, :not_present]]
58
+ end
59
+ end
60
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,5 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
5
+ --backtrace
@@ -0,0 +1,55 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ require 'rubygems'
11
+ require 'ohm'
12
+ require 'redis'
13
+ require 'tweetable'
14
+ require 'fakeweb'
15
+
16
+ FakeWeb.allow_net_connect = false
17
+
18
+ def twitter_url(path, login=nil, password=nil)
19
+ if path =~ /^http/
20
+ path
21
+ else
22
+ login || pass ? "http://#{login}:#{password}@api.twitter.com#{path}" : path
23
+ end
24
+ end
25
+
26
+ def fixture_file(filename)
27
+ return '' if filename == ''
28
+ file_path = File.expand_path(File.dirname(__FILE__) + '/fixtures/' + filename)
29
+ File.read(file_path)
30
+ end
31
+
32
+ def stub_get(url, filename, options = {})
33
+ fwoptions = {:body => fixture_file(filename)}
34
+ fwoptions.merge!({:status => options[:status]}) unless options[:status].nil?
35
+ FakeWeb.register_uri(:get, twitter_url(url, options[:login], options[:password]), fwoptions)
36
+ end
37
+
38
+ def stub_post(url, filename)
39
+ FakeWeb.register_uri(:post, twitter_url(url), :body => fixture_file(filename))
40
+ end
41
+
42
+ def stub_put(url, filename)
43
+ FakeWeb.register_uri(:put, twitter_url(url), :body => fixture_file(filename))
44
+ end
45
+
46
+
47
+ class RedisSpecHelper
48
+ TEST_OPTIONS = {:db => 11}
49
+
50
+ def self.reset
51
+ Ohm.connect(TEST_OPTIONS)
52
+ Ohm.flush
53
+ end
54
+ end
55
+
@@ -0,0 +1,19 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe Tweetable do
4
+ before do
5
+ Tweetable.config({:max_message_count=>10})
6
+ RedisSpecHelper.reset
7
+ end
8
+
9
+ context 'when configuring' do
10
+ it "should use default config values" do
11
+ Tweetable.config.should == Tweetable::DEFAULT_CONFIG
12
+ end
13
+
14
+ it "should update the config" do
15
+ Tweetable.config({:max_message_count=>101})
16
+ Tweetable.config[:max_message_count].should == 101
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe Tweetable::TwitterClient do
4
+ before do
5
+ RedisSpecHelper.reset
6
+ stub_get('/1/account/rate_limit_status.json', 'rate_limit_status.json', {:login => 'l', :password => 'p'})
7
+ stub_get('/1/account/verify_credentials.json', 'verify_credentials.json', {:login => 'l', :password => 'p'})
8
+
9
+ @twitter = Tweetable::TwitterClient.new
10
+ end
11
+
12
+ context 'when not logged in' do
13
+ it "should require login" do
14
+ expect {
15
+ @twitter.verify_credentials
16
+ }.should raise_exception(Tweetable::TweetableAuthError)
17
+ end
18
+
19
+ it "should raise exception with nil authorization" do
20
+ expect {
21
+ @twitter.authorize(nil, nil, nil)
22
+ }.should raise_exception(Tweetable::TweetableAuthError)
23
+ end
24
+
25
+ end
26
+
27
+ context 'when logged in' do
28
+ before do
29
+ @twitter.login('l', 'p')
30
+ end
31
+
32
+ it "should verify credentials of valid user" do
33
+ info = @twitter.verify_credentials
34
+ info.name.should == 'Peter T. Brown'
35
+ end
36
+
37
+ it "should get rate limit status" do
38
+ @twitter.status.should include(:hourly_limit)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe Tweetable::TwitterStreamingClient, 'when streaming' do
4
+ before do
5
+ RedisSpecHelper.reset
6
+ @twitter = Tweetable::TwitterStreamingClient.new('flippyhead', 'apple2406')
7
+ end
8
+
9
+ # it "should stream sample" do
10
+ # message = nil
11
+ # @twitter.sample do |m|
12
+ # message = m
13
+ # break
14
+ # end
15
+ #
16
+ # message.should include(:text)
17
+ # end
18
+ end
data/spec/user_spec.rb ADDED
@@ -0,0 +1,143 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ attrs = {:screen_name => 'flippyhead', :user_id => '13705052', :created_at => Time.now.utc.to_s, :updated_at => Time.now.utc.to_s}
4
+
5
+ describe Tweetable::User do
6
+ before do
7
+ RedisSpecHelper.reset
8
+ @user = Tweetable::User.create(attrs)
9
+
10
+ Tweetable.login('l', 'p')
11
+ end
12
+
13
+ context "when building and saving" do
14
+ it "should store a user item with screen_name, user_id, and created_at attributes" do
15
+ @user.should be_valid
16
+ end
17
+
18
+ it "should save user info after modification" do
19
+ @user.user_id = 12345
20
+ @user.save
21
+ Tweetable::User.find(:screen_name => attrs[:screen_name]).first.user_id.should == '12345'
22
+ end
23
+
24
+ it "should set created_at" do
25
+ Tweetable::User.find(:screen_name => attrs[:screen_name]).first.created_at.should == attrs[:created_at]
26
+ end
27
+
28
+ it "should not save user info without calling save" do
29
+ @user.user_id = '12345'
30
+ Tweetable::User.find(:screen_name => attrs[:screen_name]).first.user_id.should == attrs[:user_id]
31
+ end
32
+
33
+ it "should find stored user by screen_name" do
34
+ Tweetable::User.find(:screen_name => attrs[:screen_name]).first.screen_name.should == attrs[:screen_name]
35
+ end
36
+
37
+ end
38
+
39
+ context "when updating info" do
40
+ before do
41
+ stub_get('/1/users/show/flippyhead.json', 'flippyhead.json', {:login => 'l', :password => 'p'})
42
+ stub_get('/1/users/show/13705052.json', 'flippyhead.json', {:login => 'l', :password => 'p'})
43
+ end
44
+
45
+ it "should get using just screen_name" do
46
+ @user.update_info
47
+ @user.user_id.should == 13705052
48
+ end
49
+
50
+ it "should save after fetching" do
51
+ @user.should_receive(:save)
52
+ @user.update_info
53
+ end
54
+
55
+ it "should get user_id" do
56
+ @user.update_info
57
+ Tweetable::User.find(:screen_name => attrs[:screen_name]).first.user_id.should == attrs[:user_id]
58
+ end
59
+
60
+ it "should get friend count" do
61
+ @user.update_info
62
+ @user.friends_count.should > 0
63
+ end
64
+
65
+ it "should get profile image url" do
66
+ @user.update_info
67
+ @user.profile_image_url.should == 'http://a3.twimg.com/profile_images/74792235/screen-capture-2_normal.png'
68
+ end
69
+
70
+ it "should get follower counts" do
71
+ @user.update_info
72
+ @user.friends_count.should > 0
73
+ end
74
+
75
+ # it "should find stored user by screen_name regardless of case" do
76
+ # user = Tweetable::User.create(:screen_name => attrs[:screen_name].upcase)
77
+ # user.update_info
78
+ # users = Tweetable::User.find(:screen_name => attrs[:screen_name].downcase)
79
+ # users.first.screen_name.should == attrs[:screen_name]
80
+ # end
81
+ end
82
+
83
+ context 'when updating friends and followers' do
84
+ before do
85
+ stub_get('/1/followers/ids.json?screen_name=flippyhead&page=1', 'follower_ids.json', {:login => 'l', :password => 'p'})
86
+ stub_get('/1/friends/ids.json?screen_name=flippyhead&page=1', 'friend_ids.json', {:login => 'l', :password => 'p'})
87
+ end
88
+
89
+ it "should update friend_ids" do
90
+ @user.update_friend_ids
91
+ @user.friend_ids.size.should > 0
92
+ end
93
+
94
+ it "should update follower_ids" do
95
+ @user.update_follower_ids
96
+ @user.follower_ids.size.should > 0
97
+ end
98
+ end
99
+
100
+ context 'when updating messages' do
101
+ before do
102
+ stub_get('/1/statuses/friends_timeline.json?screen_name=flippyhead&count=10', 'friends_timeline.json', {:login => 'l', :password => 'p'})
103
+ stub_get('/1/statuses/user_timeline.json?screen_name=flippyhead&count=10', 'user_timeline.json', {:login => 'l', :password => 'p'})
104
+ stub_get('/1/statuses/user_timeline.json?screen_name=flippyhead&count=10&since_id=11572672967', 'blank.json', {:login => 'l', :password => 'p'})
105
+ end
106
+
107
+ it "should return new messages" do
108
+ @user.update_messages.size.should > 0
109
+ end
110
+
111
+ it "should store created_at date" do
112
+ @user.update_messages
113
+ @user.messages.first.created_at.should_not be_nil
114
+ end
115
+
116
+ it "should build message objects" do
117
+ @user.update_messages
118
+ @user.messages.first.should be_instance_of Tweetable::Message
119
+ @user.messages.first.text.should_not be_blank
120
+ end
121
+
122
+ it "should only get created since last message" do
123
+ @user.update_messages.size.should > 0
124
+ @user.update_messages.size.should == 0
125
+ end
126
+
127
+ it "should not duplicate messages" do
128
+ @user.update_messages.size.should > 0
129
+ @user.update_messages.size.should == 0
130
+ end
131
+
132
+ it "should build friend message objects" do
133
+ @user.update_friend_messages
134
+ @user.friend_messages.first.should be_instance_of Tweetable::Message
135
+ @user.friend_messages.first.text.should_not be_blank
136
+ end
137
+
138
+ it "should create associated users for friend messages" do
139
+ @user.update_friend_messages
140
+ @user.friend_messages.first.from_user.should_not be_nil
141
+ end
142
+ end
143
+ end