gilesbowkett-twitter 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/History +126 -0
  2. data/License +19 -0
  3. data/Manifest +69 -0
  4. data/README +84 -0
  5. data/Rakefile +42 -0
  6. data/bin/twitter +14 -0
  7. data/examples/blocks.rb +15 -0
  8. data/examples/direct_messages.rb +29 -0
  9. data/examples/favorites.rb +20 -0
  10. data/examples/friends_followers.rb +25 -0
  11. data/examples/friendships.rb +13 -0
  12. data/examples/identica_timeline.rb +7 -0
  13. data/examples/location.rb +8 -0
  14. data/examples/posting.rb +9 -0
  15. data/examples/replies.rb +27 -0
  16. data/examples/search.rb +18 -0
  17. data/examples/sent_messages.rb +27 -0
  18. data/examples/timeline.rb +34 -0
  19. data/examples/twitter.rb +27 -0
  20. data/examples/verify_credentials.rb +13 -0
  21. data/lib/twitter/base.rb +284 -0
  22. data/lib/twitter/cli/config.rb +9 -0
  23. data/lib/twitter/cli/helpers.rb +109 -0
  24. data/lib/twitter/cli/migrations/20080722194500_create_accounts.rb +13 -0
  25. data/lib/twitter/cli/migrations/20080722194508_create_tweets.rb +16 -0
  26. data/lib/twitter/cli/migrations/20080722214605_add_account_id_to_tweets.rb +9 -0
  27. data/lib/twitter/cli/migrations/20080722214606_create_configurations.rb +13 -0
  28. data/lib/twitter/cli/models/account.rb +33 -0
  29. data/lib/twitter/cli/models/configuration.rb +13 -0
  30. data/lib/twitter/cli/models/tweet.rb +20 -0
  31. data/lib/twitter/cli.rb +334 -0
  32. data/lib/twitter/direct_message.rb +30 -0
  33. data/lib/twitter/easy_class_maker.rb +43 -0
  34. data/lib/twitter/rate_limit_status.rb +19 -0
  35. data/lib/twitter/search.rb +101 -0
  36. data/lib/twitter/search_result.rb +83 -0
  37. data/lib/twitter/search_result_info.rb +82 -0
  38. data/lib/twitter/status.rb +22 -0
  39. data/lib/twitter/user.rb +37 -0
  40. data/lib/twitter/version.rb +3 -0
  41. data/lib/twitter.rb +32 -0
  42. data/spec/base_spec.rb +139 -0
  43. data/spec/cli/helper_spec.rb +49 -0
  44. data/spec/direct_message_spec.rb +40 -0
  45. data/spec/fixtures/follower_ids.xml +11 -0
  46. data/spec/fixtures/followers.xml +706 -0
  47. data/spec/fixtures/friend_ids.xml +12 -0
  48. data/spec/fixtures/friends.xml +609 -0
  49. data/spec/fixtures/friends_for.xml +584 -0
  50. data/spec/fixtures/friends_lite.xml +192 -0
  51. data/spec/fixtures/friends_timeline.xml +66 -0
  52. data/spec/fixtures/friendship_already_exists.xml +5 -0
  53. data/spec/fixtures/friendship_created.xml +12 -0
  54. data/spec/fixtures/public_timeline.xml +148 -0
  55. data/spec/fixtures/rate_limit_status.xml +7 -0
  56. data/spec/fixtures/search_result_info.yml +147 -0
  57. data/spec/fixtures/search_results.json +1 -0
  58. data/spec/fixtures/status.xml +25 -0
  59. data/spec/fixtures/user.xml +38 -0
  60. data/spec/fixtures/user_timeline.xml +465 -0
  61. data/spec/search_spec.rb +100 -0
  62. data/spec/spec.opts +1 -0
  63. data/spec/spec_helper.rb +23 -0
  64. data/spec/status_spec.rb +40 -0
  65. data/spec/user_spec.rb +42 -0
  66. data/twitter.gemspec +45 -0
  67. data/website/css/common.css +47 -0
  68. data/website/images/terminal_output.png +0 -0
  69. data/website/index.html +147 -0
  70. metadata +188 -0
@@ -0,0 +1,22 @@
1
+ module Twitter
2
+ class Status
3
+ include EasyClassMaker
4
+
5
+ attributes :created_at, :id, :text, :user, :source, :truncated, :in_reply_to_status_id, :in_reply_to_user_id, :favorited
6
+
7
+ # Creates a new status from a piece of xml
8
+ def self.new_from_xml(xml)
9
+ s = new
10
+ s.id = (xml).at('id').innerHTML
11
+ s.created_at = (xml).at('created_at').innerHTML
12
+ s.text = (xml).get_elements_by_tag_name('text').innerHTML
13
+ s.source = (xml).at('source').innerHTML
14
+ s.truncated = (xml).at('truncated').innerHTML == 'false' ? false : true
15
+ s.favorited = (xml).at('favorited').innerHTML == 'false' ? false : true
16
+ s.in_reply_to_status_id = (xml).at('in_reply_to_status_id').innerHTML
17
+ s.in_reply_to_user_id = (xml).at('in_reply_to_user_id').innerHTML
18
+ s.user = User.new_from_xml(xml.at('user')) if (xml).at('user')
19
+ s
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ module Twitter
2
+ class User
3
+ include EasyClassMaker
4
+
5
+ attributes :id, :name, :screen_name, :status, :location, :description, :url,
6
+ :profile_image_url, :profile_background_color, :profile_text_color, :profile_link_color,
7
+ :profile_sidebar_fill_color, :profile_sidebar_border_color, :friends_count, :followers_count,
8
+ :favourites_count, :statuses_count, :utc_offset , :protected
9
+
10
+ # Creates a new user from a piece of xml
11
+ def self.new_from_xml(xml)
12
+ u = new
13
+ u.id = (xml).at('id').innerHTML
14
+ u.name = (xml).at('name').innerHTML
15
+ u.screen_name = (xml).at('screen_name').innerHTML
16
+ u.location = (xml).at('location').innerHTML
17
+ u.description = (xml).at('description').innerHTML
18
+ u.url = (xml).at('url').innerHTML
19
+ u.profile_image_url = (xml).at('profile_image_url').innerHTML
20
+
21
+ # optional, not always present
22
+ u.profile_background_color = (xml).at('profile_background_color').innerHTML if (xml).at('profile_background_color')
23
+ u.profile_text_color = (xml).at('profile_text_color').innerHTML if (xml).at('profile_text_color')
24
+ u.profile_link_color = (xml).at('profile_link_color').innerHTML if (xml).at('profile_link_color')
25
+ u.profile_sidebar_fill_color = (xml).at('profile_sidebar_fill_color').innerHTML if (xml).at('profile_sidebar_fill_color')
26
+ u.profile_sidebar_border_color = (xml).at('profile_sidebar_border_color').innerHTML if (xml).at('profile_sidebar_border_color')
27
+ u.friends_count = (xml).at('friends_count').innerHTML if (xml).at('friends_count')
28
+ u.followers_count = (xml).at('followers_count').innerHTML if (xml).at('followers_count')
29
+ u.favourites_count = (xml).at('favourites_count').innerHTML if (xml).at('favourites_count')
30
+ u.statuses_count = (xml).at('statuses_count').innerHTML if (xml).at('statuses_count')
31
+ u.utc_offset = (xml).at('utc_offset').innerHTML if (xml).at('utc_offset')
32
+ u.protected = (xml).at('protected').innerHTML == 'false' ? false : true if (xml).at('protected')
33
+ u.status = Status.new_from_xml(xml.at('status')) if (xml).at('status')
34
+ u
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module Twitter #:nodoc:
2
+ Version = '0.4.2'
3
+ end
data/lib/twitter.rb ADDED
@@ -0,0 +1,32 @@
1
+ require 'uri'
2
+ require 'cgi'
3
+ require 'net/http'
4
+ require 'yaml'
5
+ require 'time'
6
+ require 'rubygems'
7
+ require 'hpricot'
8
+
9
+ $:.unshift(File.dirname(__FILE__))
10
+ require 'twitter/version'
11
+ require 'twitter/easy_class_maker'
12
+ require 'twitter/base'
13
+ require 'twitter/user'
14
+ require 'twitter/search'
15
+ require 'twitter/status'
16
+ require 'twitter/direct_message'
17
+ require 'twitter/rate_limit_status'
18
+ require 'twitter/search_result_info'
19
+ require 'twitter/search_result'
20
+
21
+ module Twitter
22
+ class Unavailable < StandardError; end
23
+ class CantConnect < StandardError; end
24
+ class BadResponse < StandardError; end
25
+ class UnknownTimeline < ArgumentError; end
26
+ class RateExceeded < StandardError; end
27
+ class CantFindUsers < ArgumentError; end
28
+ class AlreadyFollowing < StandardError; end
29
+ class CantFollowUser < StandardError; end
30
+
31
+ SourceName = 'twittergem'
32
+ end
data/spec/base_spec.rb ADDED
@@ -0,0 +1,139 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe "Twitter::Base" do
4
+ before do
5
+ @base = Twitter::Base.new('foo', 'bar')
6
+ end
7
+
8
+ describe "being initialized" do
9
+ it "should require email and password" do
10
+ lambda { Twitter::Base.new }.should raise_error(ArgumentError)
11
+ end
12
+ end
13
+
14
+ describe "timelines" do
15
+ it "should bomb if given invalid timeline" do
16
+ lambda { @base.timeline(:fakeyoutey) }.should raise_error(Twitter::UnknownTimeline)
17
+ end
18
+
19
+ it "should default to friends timeline" do
20
+ @base.should_receive(:call).with("friends_timeline", {:auth=>true, :args=>{}, :since=>nil})
21
+ @base.should_receive(:statuses)
22
+ @base.timeline
23
+ end
24
+
25
+ it "should be able to retrieve friends timeline" do
26
+ data = open(File.dirname(__FILE__) + '/fixtures/friends_timeline.xml').read
27
+ @base.should_receive(:request).and_return(Hpricot::XML(data))
28
+ @base.timeline(:friends).size.should == 3
29
+ end
30
+
31
+ it "should be able to retrieve public timeline" do
32
+ data = open(File.dirname(__FILE__) + '/fixtures/public_timeline.xml').read
33
+ @base.should_receive(:request).and_return(Hpricot::XML(data))
34
+ @base.timeline(:public).size.should == 6
35
+ end
36
+
37
+ it "should be able to retrieve user timeline" do
38
+ data = open(File.dirname(__FILE__) + '/fixtures/user_timeline.xml').read
39
+ @base.should_receive(:request).and_return(Hpricot::XML(data))
40
+ @base.timeline(:user).size.should == 19
41
+ end
42
+ end
43
+
44
+ describe "friends and followers" do
45
+ it "should be able to get friends" do
46
+ data = open(File.dirname(__FILE__) + '/fixtures/friends.xml').read
47
+ @base.should_receive(:request).and_return(Hpricot::XML(data))
48
+ @base.friends.size.should == 25
49
+ end
50
+
51
+ it "should be able to get friends without latest status" do
52
+ data = open(File.dirname(__FILE__) + '/fixtures/friends_lite.xml').read
53
+ @base.should_receive(:request).and_return(Hpricot::XML(data))
54
+ @base.friends(:lite => true).size.should == 15
55
+ end
56
+
57
+ it "should be able to get friend ids" do
58
+ data = open(File.dirname(__FILE__) + '/fixtures/friend_ids.xml').read
59
+ @base.should_receive(:request).and_return(Hpricot::XML(data))
60
+ @base.friend_ids.size.should == 8
61
+ end
62
+
63
+ it "should be able to get friends for another user" do
64
+ data = open(File.dirname(__FILE__) + '/fixtures/friends_for.xml').read
65
+ @base.should_receive(:request).and_return(Hpricot::XML(data))
66
+ timeline = @base.friends_for(20)
67
+ timeline.size.should == 24
68
+ timeline.first.name.should == 'Jack Dorsey'
69
+ end
70
+
71
+ it "should be able to get followers" do
72
+ data = open(File.dirname(__FILE__) + '/fixtures/followers.xml').read
73
+ @base.should_receive(:request).and_return(Hpricot::XML(data))
74
+ timeline = @base.followers
75
+ timeline.size.should == 29
76
+ timeline.first.name.should == 'Blaine Cook'
77
+ end
78
+
79
+ it "should be able to get follower ids" do
80
+ data = open(File.dirname(__FILE__) + '/fixtures/follower_ids.xml').read
81
+ @base.should_receive(:request).and_return(Hpricot::XML(data))
82
+ @base.follower_ids.size.should == 8
83
+ end
84
+
85
+ it "should be able to create a friendship" do
86
+ data = open(File.dirname(__FILE__) + '/fixtures/friendship_created.xml').read
87
+ @base.should_receive(:request).and_return(Hpricot::XML(data))
88
+ user = @base.create_friendship('jnunemaker')
89
+ end
90
+
91
+ it "should bomb if friendship already exists" do
92
+ data = open(File.dirname(__FILE__) + '/fixtures/friendship_already_exists.xml').read
93
+ response = Net::HTTPForbidden.new("1.1", '403', '')
94
+ response.stub!(:body).and_return(data)
95
+ @base.should_receive(:response).and_return(response)
96
+ lambda { @base.create_friendship('billymeltdown') }.should raise_error(Twitter::AlreadyFollowing)
97
+ end
98
+ end
99
+
100
+ it "should be able to get single status" do
101
+ data = open(File.dirname(__FILE__) + '/fixtures/status.xml').read
102
+ @base.should_receive(:request).and_return(Hpricot::XML(data))
103
+ @base.status(803478581).created_at.should == 'Sun May 04 23:36:14 +0000 2008'
104
+ end
105
+
106
+ it "should be able to get single user" do
107
+ data = open(File.dirname(__FILE__) + '/fixtures/user.xml').read
108
+ @base.should_receive(:request).and_return(Hpricot::XML(data))
109
+ @base.user('4243').name.should == 'John Nunemaker'
110
+ end
111
+
112
+ describe "rate limit status" do
113
+ before do
114
+ @data = open(File.dirname(__FILE__) + '/fixtures/rate_limit_status.xml').read
115
+ @base.stub!(:request).and_return(Hpricot::XML(@data))
116
+ end
117
+
118
+ it "should request the status" do
119
+ @base.should_receive(:request).and_return(Hpricot::XML(@data))
120
+ @base.rate_limit_status
121
+ end
122
+
123
+ it "should have an hourly limit" do
124
+ @base.rate_limit_status.hourly_limit.should == 20
125
+ end
126
+
127
+ it "should have a reset time in seconds" do
128
+ @base.rate_limit_status.reset_time_in_seconds.should == 1214757610
129
+ end
130
+
131
+ it "should have a reset time" do
132
+ @base.rate_limit_status.reset_time.should == Time.parse('2008-06-29T16:40:10+00:00')
133
+ end
134
+
135
+ it "should have remaining hits" do
136
+ @base.rate_limit_status.remaining_hits.should == 5
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,49 @@
1
+ require 'ostruct'
2
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
3
+ require File.dirname(__FILE__) + '/../../lib/twitter/cli/helpers'
4
+
5
+ class Configuration; end
6
+
7
+ def say(str)
8
+ puts str
9
+ end
10
+
11
+ class Tweet < OpenStruct
12
+ attr_accessor :id
13
+ end
14
+
15
+ describe Twitter::CLI::Helpers do
16
+ include Twitter::CLI::Helpers
17
+
18
+ describe "outputting tweets" do
19
+ before do
20
+ Configuration.stub!(:[]=).and_return(true)
21
+ @collection = [
22
+ Tweet.new(
23
+ :id => 1,
24
+ :text => 'This is my long message that I want to see formatted ooooh so pretty with a few words on each line so it is easy to scan.',
25
+ :created_at => Time.mktime(2008, 5, 1, 10, 15, 00).strftime('%Y-%m-%d %H:%M:%S'),
26
+ :user => OpenStruct.new(:screen_name => 'jnunemaker')
27
+ ),
28
+ Tweet.new(
29
+ :id => 2,
30
+ :text => 'This is my long message that I want to see formatted ooooh so pretty with a.',
31
+ :created_at => Time.mktime(2008, 4, 1, 10, 15, 00).strftime('%Y-%m-%d %H:%M:%S'),
32
+ :user => OpenStruct.new(:screen_name => 'danielmorrison')
33
+ )
34
+ ]
35
+ end
36
+
37
+ specify "should properly format" do
38
+ stdout_for {
39
+ output_tweets(@collection)
40
+ }.should match(/with a few words[\w\W]*with a\./)
41
+ end
42
+
43
+ specify 'should format in reverse' do
44
+ stdout_for {
45
+ output_tweets(@collection, :reverse => true)
46
+ }.should match(/with a\.[\w\W]*with a few words/)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,40 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe "Twitter::DirectMessage" do
4
+ it "should create new direct message from xml doc" do
5
+ xml = <<EOF
6
+ <direct_message>
7
+ <id>331681</id>
8
+ <text>thanks for revving the twitter gem! had notice that it was broken but didn't have time to patch.</text>
9
+ <sender_id>18713</sender_id>
10
+ <recipient_id>4243</recipient_id>
11
+ <created_at>Sat Mar 10 22:10:37 +0000 2007</created_at>
12
+ <sender_screen_name>al3x</sender_screen_name>
13
+ <recipient_screen_name>jnunemaker</recipient_screen_name>
14
+ <sender>
15
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/64086364/rubyconfpro2_normal.jpg</profile_image_url>
16
+ </sender>
17
+ </direct_message>
18
+ EOF
19
+ d = Twitter::DirectMessage.new do |d|
20
+ d.id = '331681'
21
+ d.text = "thanks for revving the twitter gem! had notice that it was broken but didn't have time to patch."
22
+ d.sender_id = '18713'
23
+ d.recipient_id = '4243'
24
+ d.created_at = 'Sat Mar 10 22:10:37 +0000 2007'
25
+ d.sender_screen_name = 'al3x'
26
+ d.recipient_screen_name = 'jnunemaker'
27
+ d.sender_profile_image_url = 'http://s3.amazonaws.com/twitter_production/profile_images/64086364/rubyconfpro2_normal.jpg'
28
+ end
29
+ d2 = Twitter::DirectMessage.new_from_xml(Hpricot.XML(xml))
30
+
31
+ d.id.should == d2.id
32
+ d.text.should == d2.text
33
+ d.sender_id.should == d2.sender_id
34
+ d.recipient_id.should == d2.recipient_id
35
+ d.created_at.should == d2.created_at
36
+ d.sender_screen_name.should == d2.sender_screen_name
37
+ d.recipient_screen_name.should == d2.recipient_screen_name
38
+ d.sender_profile_image_url.should == d2.sender_profile_image_url
39
+ end
40
+ end
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ids>
3
+ <id>1192</id>
4
+ <id>750823</id>
5
+ <id>813198</id>
6
+ <id>10718</id>
7
+ <id>13046</id>
8
+ <id>79543</id>
9
+ <id>813775</id>
10
+ <id>681473</id>
11
+ </ids>