netshade-twitter 0.4.2.1
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.rb +34 -0
- data/lib/twitter/base.rb +284 -0
- data/lib/twitter/cli.rb +334 -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/direct_message.rb +22 -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/spec/base_spec.rb +139 -0
- data/spec/cli/helper_spec.rb +49 -0
- data/spec/direct_message_spec.rb +35 -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 +42 -0
- data/website/css/common.css +47 -0
- data/website/images/terminal_output.png +0 -0
- data/website/index.html +147 -0
- metadata +177 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
3
|
+
config = YAML::load(open(ENV['HOME'] + '/.twitter'))
|
4
|
+
|
5
|
+
twitter = Twitter::Base.new(config['email'], config['password'])
|
6
|
+
|
7
|
+
puts twitter.create_friendship('orderedlist').name
|
8
|
+
puts twitter.follow('orderedlist').name
|
9
|
+
puts twitter.leave('orderedlist').name
|
10
|
+
puts twitter.destroy_friendship('orderedlist').name
|
11
|
+
|
12
|
+
puts twitter.friendship_exists?('jnunemaker', 'orderedlist').inspect
|
13
|
+
puts twitter.friendship_exists?('jnunemaker', 'ze').inspect
|
@@ -0,0 +1,7 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
3
|
+
config = YAML::load(open(ENV['HOME'] + '/.twitter'))
|
4
|
+
|
5
|
+
identica = Twitter::Base.new(config['email'], config['password'], :api_host => 'identi.ca/api')
|
6
|
+
|
7
|
+
identica.timeline(:public).each { |s| puts s.text, s.user.name, '' }
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
3
|
+
config = YAML::load(open(ENV['HOME'] + '/.twitter'))
|
4
|
+
|
5
|
+
twitter = Twitter::Base.new(config['email'], config['password'])
|
6
|
+
|
7
|
+
puts twitter.update_location('Hollywood, CA').location
|
8
|
+
puts twitter.update_delivery_device('none')
|
data/examples/posting.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
3
|
+
config = YAML::load(open(ENV['HOME'] + '/.twitter'))
|
4
|
+
|
5
|
+
twitter = Twitter::Base.new(config['email'], config['password'])
|
6
|
+
puts twitter.post("This is a test from the example file").inspect
|
7
|
+
|
8
|
+
# sending a direct message
|
9
|
+
# puts twitter.d('jnunemaker', 'this is a test').inspect
|
data/examples/replies.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'activesupport'
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
4
|
+
config = YAML::load(open(ENV['HOME'] + '/.twitter'))
|
5
|
+
|
6
|
+
twitter = Twitter::Base.new(config['email'], config['password'])
|
7
|
+
|
8
|
+
puts 'SINCE'
|
9
|
+
twitter.replies(:since => Time.now - 5.day).each do |s|
|
10
|
+
puts "- #{s.text}"
|
11
|
+
end
|
12
|
+
puts
|
13
|
+
puts
|
14
|
+
|
15
|
+
puts 'SINCE_ID'
|
16
|
+
twitter.replies(:since_id => 863081345).each do |s|
|
17
|
+
puts "- #{s.text}"
|
18
|
+
end
|
19
|
+
puts
|
20
|
+
puts
|
21
|
+
|
22
|
+
puts 'PAGE'
|
23
|
+
twitter.replies(:page => 1).each do |s|
|
24
|
+
puts "- #{s.text}"
|
25
|
+
end
|
26
|
+
puts
|
27
|
+
puts
|
data/examples/search.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
3
|
+
|
4
|
+
Twitter::Search.new('httparty').each { |r| puts r.inspect,'' }
|
5
|
+
Twitter::Search.new('httparty').page(2).each { |r| puts r.inspect, '' }
|
6
|
+
|
7
|
+
# search = Twitter::Search.new
|
8
|
+
# search.from('jnunemaker').to('oaknd1').each { |r| puts r.inspect, '' }
|
9
|
+
# pp search.result
|
10
|
+
# search.clear
|
11
|
+
|
12
|
+
# search.from('jnunemaker').to('oaknd1').since(814529437).containing('milk').each { |r| puts r.inspect, '' }
|
13
|
+
# search.clear
|
14
|
+
#
|
15
|
+
# search.geocode('40.757929', '-73.985506', '50mi').containing('holland').each { |r| puts r.inspect, '' }
|
16
|
+
# search.clear
|
17
|
+
|
18
|
+
# pp search.from('jnunemaker').fetch()
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'activesupport'
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
4
|
+
config = YAML::load(open(ENV['HOME'] + '/.twitter'))
|
5
|
+
|
6
|
+
twitter = Twitter::Base.new(config['email'], config['password'])
|
7
|
+
|
8
|
+
puts 'SINCE'
|
9
|
+
twitter.sent_messages(:since => Time.now - 5.day).each do |s|
|
10
|
+
puts "- #{s.text}"
|
11
|
+
end
|
12
|
+
puts
|
13
|
+
puts
|
14
|
+
|
15
|
+
puts 'SINCE_ID'
|
16
|
+
twitter.sent_messages(:since_id => 33505386).each do |s|
|
17
|
+
puts "- #{s.text}"
|
18
|
+
end
|
19
|
+
puts
|
20
|
+
puts
|
21
|
+
|
22
|
+
puts 'PAGE'
|
23
|
+
twitter.sent_messages(:page => 1).each do |s|
|
24
|
+
puts "- #{s.text}"
|
25
|
+
end
|
26
|
+
puts
|
27
|
+
puts
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'activesupport'
|
3
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
4
|
+
config = YAML::load(open(ENV['HOME'] + '/.twitter'))
|
5
|
+
|
6
|
+
twitter = Twitter::Base.new(config['email'], config['password'])
|
7
|
+
|
8
|
+
puts 'SINCE'
|
9
|
+
twitter.timeline(:user, :since => Time.now - 1.day).each do |s|
|
10
|
+
puts "- #{s.text}"
|
11
|
+
end
|
12
|
+
puts
|
13
|
+
puts
|
14
|
+
|
15
|
+
puts 'SINCE_ID'
|
16
|
+
twitter.timeline(:user, :since_id => 865547074).each do |s|
|
17
|
+
puts "- #{s.text}"
|
18
|
+
end
|
19
|
+
puts
|
20
|
+
puts
|
21
|
+
|
22
|
+
puts 'COUNT'
|
23
|
+
twitter.timeline(:user, :count => 1).each do |s|
|
24
|
+
puts "- #{s.text}"
|
25
|
+
end
|
26
|
+
puts
|
27
|
+
puts
|
28
|
+
|
29
|
+
puts 'PAGE'
|
30
|
+
twitter.timeline(:user, :page => 1).each do |s|
|
31
|
+
puts "- #{s.text}"
|
32
|
+
end
|
33
|
+
puts
|
34
|
+
puts
|
data/examples/twitter.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
3
|
+
config = YAML::load(open(ENV['HOME'] + '/.twitter'))
|
4
|
+
|
5
|
+
puts "Public Timeline", "=" * 50
|
6
|
+
Twitter::Base.new(config['email'], config['password']).timeline(:public).each do |s|
|
7
|
+
puts s.text, s.user.name
|
8
|
+
puts
|
9
|
+
end
|
10
|
+
|
11
|
+
puts '', "Friends Timeline", "=" * 50
|
12
|
+
Twitter::Base.new(config['email'], config['password']).timeline.each do |s|
|
13
|
+
puts s.text, s.user.name
|
14
|
+
puts
|
15
|
+
end
|
16
|
+
|
17
|
+
puts '', "Friends", "=" * 50
|
18
|
+
Twitter::Base.new(config['email'], config['password']).friends.each do |u|
|
19
|
+
puts u.name, u.status.text
|
20
|
+
puts
|
21
|
+
end
|
22
|
+
|
23
|
+
puts '', "Followers", "=" * 50
|
24
|
+
Twitter::Base.new(config['email'], config['password']).followers.each do |u|
|
25
|
+
puts u.name, u.status.text
|
26
|
+
puts
|
27
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
3
|
+
config = YAML::load(open(ENV['HOME'] + '/.twitter'))
|
4
|
+
|
5
|
+
twitter = Twitter::Base.new(config['email'], config['password'])
|
6
|
+
|
7
|
+
puts twitter.verify_credentials
|
8
|
+
|
9
|
+
begin
|
10
|
+
Twitter::Base.new('asdf', 'foobar').verify_credentials
|
11
|
+
rescue => error
|
12
|
+
puts error.message
|
13
|
+
end
|
data/lib/twitter.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'cgi'
|
3
|
+
require 'net/http'
|
4
|
+
require 'yaml'
|
5
|
+
require 'time'
|
6
|
+
require 'rubygems'
|
7
|
+
unless defined?(Hpricot)
|
8
|
+
require 'hpricot'
|
9
|
+
end
|
10
|
+
|
11
|
+
$:.unshift(File.dirname(__FILE__))
|
12
|
+
require 'twitter/version'
|
13
|
+
require 'twitter/easy_class_maker'
|
14
|
+
require 'twitter/base'
|
15
|
+
require 'twitter/user'
|
16
|
+
require 'twitter/search'
|
17
|
+
require 'twitter/status'
|
18
|
+
require 'twitter/direct_message'
|
19
|
+
require 'twitter/rate_limit_status'
|
20
|
+
require 'twitter/search_result_info'
|
21
|
+
require 'twitter/search_result'
|
22
|
+
|
23
|
+
module Twitter
|
24
|
+
class Unavailable < StandardError; end
|
25
|
+
class CantConnect < StandardError; end
|
26
|
+
class BadResponse < StandardError; end
|
27
|
+
class UnknownTimeline < ArgumentError; end
|
28
|
+
class RateExceeded < StandardError; end
|
29
|
+
class CantFindUsers < ArgumentError; end
|
30
|
+
class AlreadyFollowing < StandardError; end
|
31
|
+
class CantFollowUser < StandardError; end
|
32
|
+
|
33
|
+
SourceName = 'twittergem'
|
34
|
+
end
|
data/lib/twitter/base.rb
ADDED
@@ -0,0 +1,284 @@
|
|
1
|
+
# This is the base class for the twitter library. It makes all the requests
|
2
|
+
# to twitter, parses the xml (using hpricot) and returns ruby objects to play with.
|
3
|
+
#
|
4
|
+
# For complete documentation on the options, check out the twitter api docs.
|
5
|
+
# http://groups.google.com/group/twitter-development-talk/web/api-documentation
|
6
|
+
module Twitter
|
7
|
+
class Base
|
8
|
+
# Initializes the configuration for making requests to twitter
|
9
|
+
# Twitter example:
|
10
|
+
# Twitter.new('email/username', 'password')
|
11
|
+
#
|
12
|
+
# Identi.ca example:
|
13
|
+
# Twitter.new('email/username', 'password', :api_host => 'identi.ca/api')
|
14
|
+
def initialize(email, password, options={})
|
15
|
+
@api_host = options.delete(:api_host) || 'twitter.com'
|
16
|
+
@config, @config[:email], @config[:password] = options, email, password
|
17
|
+
@proxy_host = options[:proxy_host]
|
18
|
+
@proxy_port = options[:proxy_port]
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns an array of statuses for a timeline; Defaults to your friends timeline.
|
22
|
+
def timeline(which=:friends, options={})
|
23
|
+
raise UnknownTimeline unless [:friends, :public, :user].include?(which)
|
24
|
+
auth = which.to_s.include?('public') ? false : true
|
25
|
+
statuses(call("#{which}_timeline", :auth => auth, :since => options[:since], :args => parse_options(options)))
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns an array of users who are in your friends list
|
29
|
+
def friends(options={})
|
30
|
+
users(call(:friends, {:args => parse_options(options)}))
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns an array of users who are friends for the id or username passed in
|
34
|
+
def friends_for(id, options={})
|
35
|
+
friends(options.merge({:id => id}))
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns an array of user ids who are friends for the account or the option id/username passed in
|
39
|
+
def friend_ids(id_or_screenname = nil)
|
40
|
+
path = id_or_screenname ? "friends/ids/#{id_or_screenname}.xml" : "friends/ids.xml"
|
41
|
+
doc = request(path, :auth => true)
|
42
|
+
(doc/:id).inject([]) {|ids, id| ids << id.innerHTML; ids}
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns an array of users who are following you
|
46
|
+
def followers(options={})
|
47
|
+
users(call(:followers, {:args => parse_options(options)}))
|
48
|
+
end
|
49
|
+
|
50
|
+
def followers_for(id, options={})
|
51
|
+
followers(options.merge({:id => id}))
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns an array of user ids who are followers for the account or the option id/username passed in
|
55
|
+
def follower_ids(id_or_screenname = nil)
|
56
|
+
path = id_or_screenname ? "followers/ids/#{id_or_screenname}.xml" : "followers/ids.xml"
|
57
|
+
doc = request(path, :auth => true)
|
58
|
+
(doc/:id).inject([]) {|ids, id| ids << id.innerHTML; ids}
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns a single status for a given id
|
62
|
+
def status(id)
|
63
|
+
statuses(call("show/#{id}")).first
|
64
|
+
end
|
65
|
+
|
66
|
+
# returns all the profile information and the last status for a user
|
67
|
+
def user(id_or_screenname)
|
68
|
+
users(request("users/show/#{id_or_screenname}.xml", :auth => true)).first
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns an array of statuses that are replies
|
72
|
+
def replies(options={})
|
73
|
+
statuses(call(:replies, :since => options[:since], :args => parse_options(options)))
|
74
|
+
end
|
75
|
+
|
76
|
+
# Destroys a status by id
|
77
|
+
def destroy(id)
|
78
|
+
call("destroy/#{id}")
|
79
|
+
end
|
80
|
+
|
81
|
+
def rate_limit_status
|
82
|
+
RateLimitStatus.new_from_xml request("account/rate_limit_status.xml", :auth => true)
|
83
|
+
end
|
84
|
+
|
85
|
+
# waiting for twitter to correctly implement this in the api as it is documented
|
86
|
+
def featured
|
87
|
+
users(call(:featured))
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns an array of all the direct messages for the authenticated user
|
91
|
+
def direct_messages(options={})
|
92
|
+
doc = request(build_path('direct_messages.xml', parse_options(options)), {:auth => true, :since => options[:since]})
|
93
|
+
(doc/:direct_message).inject([]) { |dms, dm| dms << DirectMessage.new_from_xml(dm); dms }
|
94
|
+
end
|
95
|
+
alias :received_messages :direct_messages
|
96
|
+
|
97
|
+
# Returns direct messages sent by auth user
|
98
|
+
def sent_messages(options={})
|
99
|
+
doc = request(build_path('direct_messages/sent.xml', parse_options(options)), {:auth => true, :since => options[:since]})
|
100
|
+
(doc/:direct_message).inject([]) { |dms, dm| dms << DirectMessage.new_from_xml(dm); dms }
|
101
|
+
end
|
102
|
+
|
103
|
+
# destroys a give direct message by id if the auth user is a recipient
|
104
|
+
def destroy_direct_message(id)
|
105
|
+
DirectMessage.new_from_xml(request("direct_messages/destroy/#{id}.xml", :auth => true, :method => :post))
|
106
|
+
end
|
107
|
+
|
108
|
+
# Sends a direct message <code>text</code> to <code>user</code>
|
109
|
+
def d(user, text)
|
110
|
+
DirectMessage.new_from_xml(request('direct_messages/new.xml', :auth => true, :method => :post, :form_data => {'text' => text, 'user' => user}))
|
111
|
+
end
|
112
|
+
|
113
|
+
# Befriends id_or_screenname for the auth user
|
114
|
+
def create_friendship(id_or_screenname)
|
115
|
+
users(request("friendships/create/#{id_or_screenname}.xml", :auth => true, :method => :post)).first
|
116
|
+
end
|
117
|
+
|
118
|
+
# Defriends id_or_screenname for the auth user
|
119
|
+
def destroy_friendship(id_or_screenname)
|
120
|
+
users(request("friendships/destroy/#{id_or_screenname}.xml", :auth => true, :method => :post)).first
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns true if friendship exists, false if it doesn't.
|
124
|
+
def friendship_exists?(user_a, user_b)
|
125
|
+
doc = request(build_path("friendships/exists.xml", {:user_a => user_a, :user_b => user_b}), :auth => true)
|
126
|
+
doc.at('friends').innerHTML == 'true' ? true : false
|
127
|
+
end
|
128
|
+
|
129
|
+
# Updates your location and returns Twitter::User object
|
130
|
+
def update_location(location)
|
131
|
+
users(request(build_path('account/update_location.xml', {'location' => location}), :auth => true, :method => :post)).first
|
132
|
+
end
|
133
|
+
|
134
|
+
# Updates your deliver device and returns Twitter::User object
|
135
|
+
def update_delivery_device(device)
|
136
|
+
users(request(build_path('account/update_delivery_device.xml', {'device' => device}), :auth => true, :method => :post)).first
|
137
|
+
end
|
138
|
+
|
139
|
+
# Turns notifications by id_or_screenname on for auth user.
|
140
|
+
def follow(id_or_screenname)
|
141
|
+
users(request("notifications/follow/#{id_or_screenname}.xml", :auth => true, :method => :post)).first
|
142
|
+
end
|
143
|
+
|
144
|
+
# Turns notifications by id_or_screenname off for auth user.
|
145
|
+
def leave(id_or_screenname)
|
146
|
+
users(request("notifications/leave/#{id_or_screenname}.xml", :auth => true, :method => :post)).first
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns the most recent favorite statuses for the autenticating user
|
150
|
+
def favorites(options={})
|
151
|
+
statuses(request(build_path('favorites.xml', parse_options(options)), :auth => true))
|
152
|
+
end
|
153
|
+
|
154
|
+
# Favorites the status specified by id for the auth user
|
155
|
+
def create_favorite(id)
|
156
|
+
statuses(request("favorites/create/#{id}.xml", :auth => true, :method => :post)).first
|
157
|
+
end
|
158
|
+
|
159
|
+
# Un-favorites the status specified by id for the auth user
|
160
|
+
def destroy_favorite(id)
|
161
|
+
statuses(request("favorites/destroy/#{id}.xml", :auth => true, :method => :post)).first
|
162
|
+
end
|
163
|
+
|
164
|
+
# Blocks the user specified by id for the auth user
|
165
|
+
def block(id)
|
166
|
+
users(request("blocks/create/#{id}.xml", :auth => true, :method => :post)).first
|
167
|
+
end
|
168
|
+
|
169
|
+
# Unblocks the user specified by id for the auth user
|
170
|
+
def unblock(id)
|
171
|
+
users(request("blocks/destroy/#{id}.xml", :auth => true, :method => :post)).first
|
172
|
+
end
|
173
|
+
|
174
|
+
# Posts a new update to twitter for auth user.
|
175
|
+
def post(status, options={})
|
176
|
+
form_data = {'status' => status}
|
177
|
+
form_data.merge!({'source' => options[:source]}) if options[:source]
|
178
|
+
form_data.merge!({'in_reply_to_status_id' => options[:in_reply_to_status_id]}) if options[:in_reply_to_status_id]
|
179
|
+
Status.new_from_xml(request('statuses/update.xml', :auth => true, :method => :post, :form_data => form_data))
|
180
|
+
end
|
181
|
+
alias :update :post
|
182
|
+
|
183
|
+
# Verifies the credentials for the auth user.
|
184
|
+
# raises Twitter::CantConnect on failure.
|
185
|
+
def verify_credentials
|
186
|
+
request('account/verify_credentials.xml', :auth => true)
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
# Converts an hpricot doc to an array of statuses
|
191
|
+
def statuses(doc)
|
192
|
+
(doc/:status).inject([]) { |statuses, status| statuses << Status.new_from_xml(status); statuses }
|
193
|
+
end
|
194
|
+
|
195
|
+
# Converts an hpricot doc to an array of users
|
196
|
+
def users(doc)
|
197
|
+
(doc/:user).inject([]) { |users, user| users << User.new_from_xml(user); users }
|
198
|
+
end
|
199
|
+
|
200
|
+
# Calls whatever api method requested that deals with statuses
|
201
|
+
#
|
202
|
+
# ie: call(:public_timeline, :auth => false)
|
203
|
+
def call(method, options={})
|
204
|
+
options = { :auth => true, :args => {} }.merge(options)
|
205
|
+
# Following line needed as lite=false doesn't work in the API: http://tinyurl.com/yo3h5d
|
206
|
+
options[:args].delete(:lite) unless options[:args][:lite]
|
207
|
+
args = options.delete(:args)
|
208
|
+
request(build_path("statuses/#{method.to_s}.xml", args), options)
|
209
|
+
end
|
210
|
+
|
211
|
+
def response(path, options={})
|
212
|
+
uri = URI.parse("http://#{@api_host}")
|
213
|
+
|
214
|
+
begin
|
215
|
+
response = Net::HTTP::Proxy(@proxy_host, @proxy_port).start(uri.host, uri.port) do |http|
|
216
|
+
klass = Net::HTTP.const_get options[:method].to_s.downcase.capitalize
|
217
|
+
req = klass.new("#{uri.path}/#{path}", options[:headers])
|
218
|
+
req.basic_auth(@config[:email], @config[:password]) if options[:auth]
|
219
|
+
if options[:method].to_s == 'post' && options[:form_data]
|
220
|
+
req.set_form_data(options[:form_data])
|
221
|
+
end
|
222
|
+
http.request(req)
|
223
|
+
end
|
224
|
+
rescue => error
|
225
|
+
raise CantConnect, error.message
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# Makes a request to twitter.
|
230
|
+
def request(path, options={})
|
231
|
+
options = {
|
232
|
+
:headers => { "User-Agent" => @config[:email] },
|
233
|
+
:method => :get,
|
234
|
+
}.merge(options)
|
235
|
+
|
236
|
+
unless options[:since].nil?
|
237
|
+
since = options[:since].kind_of?(Date) ? options[:since].strftime('%a, %d-%b-%y %T GMT') : options[:since].to_s
|
238
|
+
options[:headers]["If-Modified-Since"] = since
|
239
|
+
end
|
240
|
+
|
241
|
+
handle_response!(response(path, options))
|
242
|
+
end
|
243
|
+
|
244
|
+
def handle_response!(response)
|
245
|
+
if %w[200 304].include?(response.code)
|
246
|
+
response = parse(response.body)
|
247
|
+
raise RateExceeded if (response/:hash/:error).text =~ /Rate limit exceeded/
|
248
|
+
response
|
249
|
+
elsif response.code == '503'
|
250
|
+
raise Unavailable, response.message
|
251
|
+
elsif response.code == '401'
|
252
|
+
raise CantConnect, 'Authentication failed. Check your username and password'
|
253
|
+
elsif response.code == '403'
|
254
|
+
error_message = (parse(response.body)/:hash/:error).text
|
255
|
+
raise CantFindUsers, error_message if error_message =~ /Could not find both specified users/
|
256
|
+
raise AlreadyFollowing, error_message if error_message =~ /already on your list/
|
257
|
+
raise CantFollowUser, "Response code #{response.code}: #{response.message} #{error_message}"
|
258
|
+
else
|
259
|
+
raise CantConnect, "Twitter is returning a #{response.code}: #{response.message}"
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
# Given a path and a hash, build a full path with the hash turned into a query string
|
264
|
+
def build_path(path, options)
|
265
|
+
unless options.nil?
|
266
|
+
query = options.inject('') { |str, h| str += "#{CGI.escape(h[0].to_s)}=#{CGI.escape(h[1].to_s)}&"; str }
|
267
|
+
path += "?#{query}"
|
268
|
+
end
|
269
|
+
|
270
|
+
path
|
271
|
+
end
|
272
|
+
|
273
|
+
# Tries to get all the options in the correct format before making the request
|
274
|
+
def parse_options(options)
|
275
|
+
options[:since] = options[:since].kind_of?(Date) ? options[:since].strftime('%a, %d-%b-%y %T GMT') : options[:since].to_s if options[:since]
|
276
|
+
options
|
277
|
+
end
|
278
|
+
|
279
|
+
# Converts a string response into an Hpricot xml element.
|
280
|
+
def parse(response)
|
281
|
+
Hpricot.XML(response || '')
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|