gilesbowkett-twitter 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- data/History +126 -0
- data/License +19 -0
- data/Manifest +69 -0
- data/README +84 -0
- data/Rakefile +42 -0
- data/bin/twitter +14 -0
- data/examples/blocks.rb +15 -0
- data/examples/direct_messages.rb +29 -0
- data/examples/favorites.rb +20 -0
- data/examples/friends_followers.rb +25 -0
- data/examples/friendships.rb +13 -0
- data/examples/identica_timeline.rb +7 -0
- data/examples/location.rb +8 -0
- data/examples/posting.rb +9 -0
- data/examples/replies.rb +27 -0
- data/examples/search.rb +18 -0
- data/examples/sent_messages.rb +27 -0
- data/examples/timeline.rb +34 -0
- data/examples/twitter.rb +27 -0
- data/examples/verify_credentials.rb +13 -0
- data/lib/twitter/base.rb +284 -0
- data/lib/twitter/cli/config.rb +9 -0
- data/lib/twitter/cli/helpers.rb +109 -0
- data/lib/twitter/cli/migrations/20080722194500_create_accounts.rb +13 -0
- data/lib/twitter/cli/migrations/20080722194508_create_tweets.rb +16 -0
- data/lib/twitter/cli/migrations/20080722214605_add_account_id_to_tweets.rb +9 -0
- data/lib/twitter/cli/migrations/20080722214606_create_configurations.rb +13 -0
- data/lib/twitter/cli/models/account.rb +33 -0
- data/lib/twitter/cli/models/configuration.rb +13 -0
- data/lib/twitter/cli/models/tweet.rb +20 -0
- data/lib/twitter/cli.rb +334 -0
- data/lib/twitter/direct_message.rb +30 -0
- data/lib/twitter/easy_class_maker.rb +43 -0
- data/lib/twitter/rate_limit_status.rb +19 -0
- data/lib/twitter/search.rb +101 -0
- data/lib/twitter/search_result.rb +83 -0
- data/lib/twitter/search_result_info.rb +82 -0
- data/lib/twitter/status.rb +22 -0
- data/lib/twitter/user.rb +37 -0
- data/lib/twitter/version.rb +3 -0
- data/lib/twitter.rb +32 -0
- data/spec/base_spec.rb +139 -0
- data/spec/cli/helper_spec.rb +49 -0
- data/spec/direct_message_spec.rb +40 -0
- data/spec/fixtures/follower_ids.xml +11 -0
- data/spec/fixtures/followers.xml +706 -0
- data/spec/fixtures/friend_ids.xml +12 -0
- data/spec/fixtures/friends.xml +609 -0
- data/spec/fixtures/friends_for.xml +584 -0
- data/spec/fixtures/friends_lite.xml +192 -0
- data/spec/fixtures/friends_timeline.xml +66 -0
- data/spec/fixtures/friendship_already_exists.xml +5 -0
- data/spec/fixtures/friendship_created.xml +12 -0
- data/spec/fixtures/public_timeline.xml +148 -0
- data/spec/fixtures/rate_limit_status.xml +7 -0
- data/spec/fixtures/search_result_info.yml +147 -0
- data/spec/fixtures/search_results.json +1 -0
- data/spec/fixtures/status.xml +25 -0
- data/spec/fixtures/user.xml +38 -0
- data/spec/fixtures/user_timeline.xml +465 -0
- data/spec/search_spec.rb +100 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/status_spec.rb +40 -0
- data/spec/user_spec.rb +42 -0
- data/twitter.gemspec +45 -0
- data/website/css/common.css +47 -0
- data/website/images/terminal_output.png +0 -0
- data/website/index.html +147 -0
- 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
|
data/lib/twitter/user.rb
ADDED
@@ -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
|
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
|