billymeltdown-twitter 0.3.8.1

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 (72) hide show
  1. data/History.txt +106 -0
  2. data/License.txt +19 -0
  3. data/Manifest.txt +71 -0
  4. data/README.txt +84 -0
  5. data/Rakefile +4 -0
  6. data/bin/twitter +15 -0
  7. data/config/hoe.rb +74 -0
  8. data/config/requirements.rb +17 -0
  9. data/examples/blocks.rb +15 -0
  10. data/examples/direct_messages.rb +28 -0
  11. data/examples/favorites.rb +20 -0
  12. data/examples/friends_followers.rb +25 -0
  13. data/examples/friendships.rb +13 -0
  14. data/examples/identica_timeline.rb +7 -0
  15. data/examples/location.rb +8 -0
  16. data/examples/posting.rb +9 -0
  17. data/examples/replies.rb +26 -0
  18. data/examples/search.rb +17 -0
  19. data/examples/sent_messages.rb +26 -0
  20. data/examples/timeline.rb +33 -0
  21. data/examples/twitter.rb +27 -0
  22. data/examples/verify_credentials.rb +13 -0
  23. data/lib/twitter/base.rb +258 -0
  24. data/lib/twitter/cli/config.rb +9 -0
  25. data/lib/twitter/cli/helpers.rb +97 -0
  26. data/lib/twitter/cli/migrations/20080722194500_create_accounts.rb +13 -0
  27. data/lib/twitter/cli/migrations/20080722194508_create_tweets.rb +16 -0
  28. data/lib/twitter/cli/migrations/20080722214605_add_account_id_to_tweets.rb +9 -0
  29. data/lib/twitter/cli/migrations/20080722214606_create_configurations.rb +13 -0
  30. data/lib/twitter/cli/models/account.rb +33 -0
  31. data/lib/twitter/cli/models/configuration.rb +13 -0
  32. data/lib/twitter/cli/models/tweet.rb +20 -0
  33. data/lib/twitter/cli.rb +328 -0
  34. data/lib/twitter/direct_message.rb +22 -0
  35. data/lib/twitter/easy_class_maker.rb +43 -0
  36. data/lib/twitter/rate_limit_status.rb +19 -0
  37. data/lib/twitter/search.rb +94 -0
  38. data/lib/twitter/status.rb +22 -0
  39. data/lib/twitter/user.rb +37 -0
  40. data/lib/twitter/version.rb +9 -0
  41. data/lib/twitter.rb +25 -0
  42. data/script/destroy +14 -0
  43. data/script/generate +14 -0
  44. data/script/txt2html +74 -0
  45. data/setup.rb +1585 -0
  46. data/spec/base_spec.rb +121 -0
  47. data/spec/cli/helper_spec.rb +35 -0
  48. data/spec/direct_message_spec.rb +35 -0
  49. data/spec/fixtures/followers.xml +706 -0
  50. data/spec/fixtures/friends.xml +609 -0
  51. data/spec/fixtures/friends_for.xml +584 -0
  52. data/spec/fixtures/friends_lite.xml +192 -0
  53. data/spec/fixtures/friends_timeline.xml +66 -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_results.json +1 -0
  57. data/spec/fixtures/status.xml +25 -0
  58. data/spec/fixtures/user.xml +38 -0
  59. data/spec/fixtures/user_timeline.xml +465 -0
  60. data/spec/search_spec.rb +89 -0
  61. data/spec/spec.opts +1 -0
  62. data/spec/spec_helper.rb +12 -0
  63. data/spec/status_spec.rb +40 -0
  64. data/spec/user_spec.rb +42 -0
  65. data/tasks/deployment.rake +50 -0
  66. data/tasks/environment.rake +7 -0
  67. data/tasks/website.rake +17 -0
  68. data/twitter.gemspec +54 -0
  69. data/website/css/common.css +47 -0
  70. data/website/images/terminal_output.png +0 -0
  71. data/website/index.html +156 -0
  72. metadata +189 -0
@@ -0,0 +1,20 @@
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 'FAVORITES'
8
+ twitter.favorites.each { |f| puts f.text }
9
+ puts
10
+ puts
11
+
12
+ puts 'CREATE'
13
+ puts twitter.create_favorite(865416114).text
14
+ puts
15
+ puts
16
+
17
+ puts 'DESTROY'
18
+ puts twitter.destroy_favorite(865416114).text
19
+ puts
20
+ puts
@@ -0,0 +1,25 @@
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 "FRIENDS"
8
+ twitter.friends.each { |f| puts f.name }
9
+ puts
10
+ puts
11
+
12
+ puts "FRIENDS FOR"
13
+ twitter.friends_for('orderedlist', :lite => true).each { |f| puts f.name }
14
+ puts
15
+ puts
16
+
17
+ puts "FOLLOWERS"
18
+ twitter.followers(:lite => true).each { |f| puts f.name }
19
+ puts
20
+ puts
21
+
22
+ puts "FOLLOWERS FOR"
23
+ twitter.followers_for('orderedlist', :lite => true).each { |f| puts f.name }
24
+ puts
25
+ puts
@@ -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')
@@ -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
@@ -0,0 +1,26 @@
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 'SINCE'
8
+ twitter.replies(:since => Time.now - 5.day).each do |s|
9
+ puts "- #{s.text}"
10
+ end
11
+ puts
12
+ puts
13
+
14
+ puts 'SINCE_ID'
15
+ twitter.replies(:since_id => 863081345).each do |s|
16
+ puts "- #{s.text}"
17
+ end
18
+ puts
19
+ puts
20
+
21
+ puts 'PAGE'
22
+ twitter.replies(:page => 1).each do |s|
23
+ puts "- #{s.text}"
24
+ end
25
+ puts
26
+ puts
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
3
+
4
+ Twitter::Search.new('httparty').each { |r| puts r.inspect,'' }
5
+
6
+ # search = Twitter::Search.new
7
+ # search.from('jnunemaker').to('oaknd1').each { |r| puts r.inspect, '' }
8
+ # pp search.result
9
+ # search.clear
10
+
11
+ # search.from('jnunemaker').to('oaknd1').since(814529437).containing('milk').each { |r| puts r.inspect, '' }
12
+ # search.clear
13
+ #
14
+ # search.geocode('40.757929', '-73.985506', '50mi').containing('holland').each { |r| puts r.inspect, '' }
15
+ # search.clear
16
+
17
+ # pp search.from('jnunemaker').fetch()
@@ -0,0 +1,26 @@
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 'SINCE'
8
+ twitter.sent_messages(:since => Time.now - 5.day).each do |s|
9
+ puts "- #{s.text}"
10
+ end
11
+ puts
12
+ puts
13
+
14
+ puts 'SINCE_ID'
15
+ twitter.sent_messages(:since_id => 33505386).each do |s|
16
+ puts "- #{s.text}"
17
+ end
18
+ puts
19
+ puts
20
+
21
+ puts 'PAGE'
22
+ twitter.sent_messages(:page => 1).each do |s|
23
+ puts "- #{s.text}"
24
+ end
25
+ puts
26
+ puts
@@ -0,0 +1,33 @@
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 'SINCE'
8
+ twitter.timeline(:user, :since => Time.now - 1.day).each do |s|
9
+ puts "- #{s.text}"
10
+ end
11
+ puts
12
+ puts
13
+
14
+ puts 'SINCE_ID'
15
+ twitter.timeline(:user, :since_id => 865547074).each do |s|
16
+ puts "- #{s.text}"
17
+ end
18
+ puts
19
+ puts
20
+
21
+ puts 'COUNT'
22
+ twitter.timeline(:user, :count => 1).each do |s|
23
+ puts "- #{s.text}"
24
+ end
25
+ puts
26
+ puts
27
+
28
+ puts 'PAGE'
29
+ twitter.timeline(:user, :page => 1).each do |s|
30
+ puts "- #{s.text}"
31
+ end
32
+ puts
33
+ puts
@@ -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
@@ -0,0 +1,258 @@
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
+ @config, @config[:email], @config[:password] = {}, email, password
16
+ @api_host = options.delete(:api_host) || 'twitter.com'
17
+ end
18
+
19
+ # Returns an array of statuses for a timeline; Defaults to your friends timeline.
20
+ def timeline(which=:friends, options={})
21
+ raise UnknownTimeline unless [:friends, :public, :user].include?(which)
22
+ auth = which.to_s.include?('public') ? false : true
23
+ statuses(call("#{which}_timeline", :auth => auth, :since => options[:since], :args => parse_options(options)))
24
+ end
25
+
26
+ # Returns an array of users who are in your friends list
27
+ def friends(options={})
28
+ users(call(:friends, {:args => parse_options(options)}))
29
+ end
30
+
31
+ # Returns an array of users who are friends for the id or username passed in
32
+ def friends_for(id, options={})
33
+ friends(options.merge({:id => id}))
34
+ end
35
+
36
+ # Returns an array of users who are following you
37
+ def followers(options={})
38
+ users(call(:followers, {:args => parse_options(options)}))
39
+ end
40
+
41
+ def followers_for(id, options={})
42
+ followers(options.merge({:id => id}))
43
+ end
44
+
45
+ # Returns a single status for a given id
46
+ def status(id)
47
+ statuses(call("show/#{id}")).first
48
+ end
49
+
50
+ # returns all the profile information and the last status for a user
51
+ def user(id_or_screenname)
52
+ users(request("users/show/#{id_or_screenname}.xml", :auth => true)).first
53
+ end
54
+
55
+ # Returns an array of statuses that are replies
56
+ def replies(options={})
57
+ statuses(call(:replies, :since => options[:since], :args => parse_options(options)))
58
+ end
59
+
60
+ # Destroys a status by id
61
+ def destroy(id)
62
+ call("destroy/#{id}")
63
+ end
64
+
65
+ def rate_limit_status
66
+ RateLimitStatus.new_from_xml request("account/rate_limit_status.xml", :auth => true)
67
+ end
68
+
69
+ # waiting for twitter to correctly implement this in the api as it is documented
70
+ def featured
71
+ users(call(:featured))
72
+ end
73
+
74
+ # Returns an array of all the direct messages for the authenticated user
75
+ def direct_messages(options={})
76
+ doc = request(build_path('direct_messages.xml', parse_options(options)), {:auth => true, :since => options[:since]})
77
+ (doc/:direct_message).inject([]) { |dms, dm| dms << DirectMessage.new_from_xml(dm); dms }
78
+ end
79
+ alias :received_messages :direct_messages
80
+
81
+ # Returns direct messages sent by auth user
82
+ def sent_messages(options={})
83
+ doc = request(build_path('direct_messages/sent.xml', parse_options(options)), {:auth => true, :since => options[:since]})
84
+ (doc/:direct_message).inject([]) { |dms, dm| dms << DirectMessage.new_from_xml(dm); dms }
85
+ end
86
+
87
+ # destroys a give direct message by id if the auth user is a recipient
88
+ def destroy_direct_message(id)
89
+ DirectMessage.new_from_xml(request("direct_messages/destroy/#{id}.xml", :auth => true, :method => :post))
90
+ end
91
+
92
+ # Sends a direct message <code>text</code> to <code>user</code>
93
+ def d(user, text)
94
+ DirectMessage.new_from_xml(request('direct_messages/new.xml', :auth => true, :method => :post, :form_data => {'text' => text, 'user' => user}))
95
+ end
96
+
97
+ # Befriends id_or_screenname for the auth user
98
+ def create_friendship(id_or_screenname)
99
+ users(request("friendships/create/#{id_or_screenname}.xml", :auth => true, :method => :post)).first
100
+ end
101
+
102
+ # Defriends id_or_screenname for the auth user
103
+ def destroy_friendship(id_or_screenname)
104
+ users(request("friendships/destroy/#{id_or_screenname}.xml", :auth => true, :method => :post)).first
105
+ end
106
+
107
+ # Returns true if friendship exists, false if it doesn't.
108
+ def friendship_exists?(user_a, user_b)
109
+ doc = request(build_path("friendships/exists.xml", {:user_a => user_a, :user_b => user_b}), :auth => true)
110
+ doc.at('friends').innerHTML == 'true' ? true : false
111
+ end
112
+
113
+ # Updates your location and returns Twitter::User object
114
+ def update_location(location)
115
+ users(request(build_path('account/update_location.xml', {'location' => location}), :auth => true, :method => :post)).first
116
+ end
117
+
118
+ # Updates your deliver device and returns Twitter::User object
119
+ def update_delivery_device(device)
120
+ users(request(build_path('account/update_delivery_device.xml', {'device' => device}), :auth => true, :method => :post)).first
121
+ end
122
+
123
+ # Turns notifications by id_or_screenname on for auth user.
124
+ def follow(id_or_screenname)
125
+ users(request("notifications/follow/#{id_or_screenname}.xml", :auth => true, :method => :post)).first
126
+ end
127
+
128
+ # Turns notifications by id_or_screenname off for auth user.
129
+ def leave(id_or_screenname)
130
+ users(request("notifications/leave/#{id_or_screenname}.xml", :auth => true, :method => :post)).first
131
+ end
132
+
133
+ # Returns the most recent favorite statuses for the autenticating user
134
+ def favorites(options={})
135
+ statuses(request(build_path('favorites.xml', parse_options(options)), :auth => true))
136
+ end
137
+
138
+ # Favorites the status specified by id for the auth user
139
+ def create_favorite(id)
140
+ statuses(request("favorites/create/#{id}.xml", :auth => true, :method => :post)).first
141
+ end
142
+
143
+ # Un-favorites the status specified by id for the auth user
144
+ def destroy_favorite(id)
145
+ statuses(request("favorites/destroy/#{id}.xml", :auth => true, :method => :post)).first
146
+ end
147
+
148
+ # Blocks the user specified by id for the auth user
149
+ def block(id)
150
+ users(request("blocks/create/#{id}.xml", :auth => true, :method => :post)).first
151
+ end
152
+
153
+ # Unblocks the user specified by id for the auth user
154
+ def unblock(id)
155
+ users(request("blocks/destroy/#{id}.xml", :auth => true, :method => :post)).first
156
+ end
157
+
158
+ # Posts a new update to twitter for auth user.
159
+ def post(status, options={})
160
+ form_data = {'status' => status}
161
+ form_data.merge!({'source' => options[:source]}) if options[:source]
162
+ Status.new_from_xml(request('statuses/update.xml', :auth => true, :method => :post, :form_data => form_data))
163
+ end
164
+ alias :update :post
165
+
166
+ # Verifies the credentials for the auth user.
167
+ # raises Twitter::CantConnect on failure.
168
+ def verify_credentials
169
+ request('account/verify_credentials', :auth => true)
170
+ end
171
+
172
+ private
173
+ # Converts an hpricot doc to an array of statuses
174
+ def statuses(doc)
175
+ (doc/:status).inject([]) { |statuses, status| statuses << Status.new_from_xml(status); statuses }
176
+ end
177
+
178
+ # Converts an hpricot doc to an array of users
179
+ def users(doc)
180
+ (doc/:user).inject([]) { |users, user| users << User.new_from_xml(user); users }
181
+ end
182
+
183
+ # Calls whatever api method requested that deals with statuses
184
+ #
185
+ # ie: call(:public_timeline, :auth => false)
186
+ def call(method, options={})
187
+ options.reverse_merge!({ :auth => true, :args => {} })
188
+ # Following line needed as lite=false doesn't work in the API: http://tinyurl.com/yo3h5d
189
+ options[:args].delete(:lite) unless options[:args][:lite]
190
+ args = options.delete(:args)
191
+ request(build_path("statuses/#{method.to_s}.xml", args), options)
192
+ end
193
+
194
+ # Makes a request to twitter.
195
+ def request(path, options={})
196
+ options.reverse_merge!({
197
+ :headers => { "User-Agent" => @config[:email] },
198
+ :method => :get
199
+ })
200
+ unless options[:since].blank?
201
+ since = options[:since].kind_of?(Date) ? options[:since].strftime('%a, %d-%b-%y %T GMT') : options[:since].to_s
202
+ options[:headers]["If-Modified-Since"] = since
203
+ end
204
+
205
+ uri = URI.parse("http://#{@api_host}")
206
+
207
+ begin
208
+ response = Net::HTTP::Proxy(options[:proxy_host], options[:proxy_port]).start(uri.host, uri.port) do |http|
209
+ klass = Net::HTTP.const_get options[:method].to_s.downcase.capitalize
210
+ req = klass.new("#{uri.path}/#{path}", options[:headers])
211
+ req.basic_auth(@config[:email], @config[:password]) if options[:auth]
212
+ if options[:method].to_s == 'post' && options[:form_data]
213
+ req.set_form_data(options[:form_data])
214
+ end
215
+ http.request(req)
216
+ end
217
+ rescue => error
218
+ raise CantConnect, error.message
219
+ end
220
+
221
+ if %w[200 304].include?(response.code)
222
+ response = parse(response.body)
223
+ raise RateExceeded if (response/:hash/:error).text =~ /Rate limit exceeded/
224
+ response
225
+ elsif response.code == '503'
226
+ raise Unavailable, response.message
227
+ elsif response.code == '401'
228
+ raise CantConnect, 'Authentication failed. Check your username and password'
229
+ elsif response.code == '403'
230
+ # get an Hpricot document
231
+ doc = parse(response.body)
232
+ raise CantFindUsers, (doc/:hash/:error).text if (doc/:hash/:error).text =~ /Could not find both specified users/
233
+ raise AlreadyFollowing, (doc/:hash/:error).text if (doc/:hash/:error).text =~ /already on your list/
234
+ raise YouAreNotFriends, (doc/:hash/:error).text if (doc/:hash/:error).text =~ /You are not friends/
235
+ raise RequestRefused, "Response code #{response.code}: #{response.message}"
236
+ else
237
+ raise CantConnect, "Twitter is returning a #{response.code}: #{response.message}"
238
+ end
239
+ end
240
+
241
+ # Given a path and a hash, build a full path with the hash turned into a query string
242
+ def build_path(path, options)
243
+ path += "?#{options.to_query}" unless options.blank?
244
+ path
245
+ end
246
+
247
+ # Tries to get all the options in the correct format before making the request
248
+ def parse_options(options)
249
+ options[:since] = options[:since].kind_of?(Date) ? options[:since].strftime('%a, %d-%b-%y %T GMT') : options[:since].to_s if options[:since]
250
+ options
251
+ end
252
+
253
+ # Converts a string response into an Hpricot xml element.
254
+ def parse(response)
255
+ Hpricot.XML(response || '')
256
+ end
257
+ end
258
+ end