dschn-twitter 0.3.7.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.rb +21 -0
  24. data/lib/twitter/base.rb +260 -0
  25. data/lib/twitter/cli.rb +328 -0
  26. data/lib/twitter/cli/config.rb +9 -0
  27. data/lib/twitter/cli/helpers.rb +97 -0
  28. data/lib/twitter/cli/migrations/20080722194500_create_accounts.rb +13 -0
  29. data/lib/twitter/cli/migrations/20080722194508_create_tweets.rb +16 -0
  30. data/lib/twitter/cli/migrations/20080722214605_add_account_id_to_tweets.rb +9 -0
  31. data/lib/twitter/cli/migrations/20080722214606_create_configurations.rb +13 -0
  32. data/lib/twitter/cli/models/account.rb +33 -0
  33. data/lib/twitter/cli/models/configuration.rb +13 -0
  34. data/lib/twitter/cli/models/tweet.rb +20 -0
  35. data/lib/twitter/direct_message.rb +22 -0
  36. data/lib/twitter/easy_class_maker.rb +43 -0
  37. data/lib/twitter/rate_limit_status.rb +19 -0
  38. data/lib/twitter/search.rb +94 -0
  39. data/lib/twitter/status.rb +22 -0
  40. data/lib/twitter/user.rb +37 -0
  41. data/lib/twitter/version.rb +9 -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 +109 -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 +49 -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 +180 -0
@@ -0,0 +1,328 @@
1
+ require 'rubygems'
2
+ gem 'main', '>= 2.8.2'
3
+ gem 'highline', '>= 1.4.0'
4
+ gem 'activerecord', '>= 2.1'
5
+ gem 'sqlite3-ruby', '>= 1.2.1'
6
+ require 'main'
7
+ require 'highline/import'
8
+ require 'activerecord'
9
+ require 'sqlite3'
10
+
11
+ HighLine.track_eof = false
12
+ CLI_ROOT = File.expand_path(File.join(File.dirname(__FILE__), 'cli'))
13
+ require CLI_ROOT + '/config'
14
+ require CLI_ROOT + '/helpers'
15
+ Dir[CLI_ROOT + '/models/*.rb'].each { |m| require m }
16
+
17
+ include Twitter::CLI::Helpers
18
+
19
+ Main {
20
+ def run
21
+ puts "twitter [command] --help for usage instructions."
22
+ puts "The available commands are: \n install, uninstall, add, remove, list, change, post, befriend, defriend, follow, leave, d and timeline."
23
+ end
24
+
25
+ mode 'install' do
26
+ description 'Creates the sqlite3 database and runs the migrations.'
27
+ def run
28
+ migrate
29
+ attempt_import
30
+ say 'Twitter installed.'
31
+ end
32
+ end
33
+
34
+ mode 'uninstall' do
35
+ description 'Removes the sqlite3 database. There is no undo for this.'
36
+ def run
37
+ FileUtils.rm(Twitter::CLI::Config[:database]) if File.exists?(Twitter::CLI::Config[:database])
38
+ say 'Twitter gem uninstalled.'
39
+ end
40
+ end
41
+
42
+ mode 'add' do
43
+ description 'Adds a new twitter account to the database. Prompts for username and password.'
44
+ argument('username', 'u') {
45
+ optional
46
+ description 'optional username'
47
+ }
48
+ argument('password', 'p') {
49
+ optional
50
+ description 'optional password'
51
+ }
52
+
53
+ def run
54
+ account = Hash.new
55
+ say "Add New Account:"
56
+
57
+ # allows optional username arg
58
+ if params['username'].given?
59
+ account[:username] = params['username'].value
60
+ else
61
+ account[:username] = ask('Username: ') do |q|
62
+ q.validate = /\S+/
63
+ end
64
+ end
65
+
66
+ # allows optional password arg
67
+ if params['password'].given?
68
+ account[:password] = params['password'].value
69
+ else
70
+ account[:password] = ask("Password (won't be displayed): ") do |q|
71
+ q.echo = false
72
+ q.validate = /\S+/
73
+ end
74
+ end
75
+
76
+ do_work do
77
+ base(account[:username], account[:password]).verify_credentials
78
+ Account.add(account)
79
+ say 'Account added.'
80
+ end
81
+ end
82
+ end
83
+
84
+ mode 'remove' do
85
+ description 'Removes a twitter account from the database. If username provided it removes that username else it prompts with list and asks for which one you would like to remove.'
86
+ argument( 'username' ) {
87
+ optional
88
+ description 'username of account you would like to remove'
89
+ }
90
+
91
+ def run
92
+ do_work do
93
+ if params['username'].given?
94
+ account = Account.find_by_username(params['username'].value)
95
+ else
96
+ Account.find(:all, :order => 'username').each do |a|
97
+ say "#{a.id}. #{a}"
98
+ end
99
+ account_id = ask 'Account to remove (enter number): ' do |q|
100
+ q.validate = /\d+/
101
+ end
102
+ end
103
+
104
+ begin
105
+ account = account_id ? Account.find(account_id) : account
106
+ account_name = account.username
107
+ account.destroy
108
+ Account.set_current(Account.first) if Account.new_active_needed?
109
+ say "#{account_name} has been removed.\n"
110
+ rescue ActiveRecord::RecordNotFound
111
+ say "ERROR: Account could not be found. Try again. \n"
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ mode 'list' do
118
+ description 'Lists all the accounts that have been added and puts a * by the current one that is used for posting, etc.'
119
+ def run
120
+ do_work do
121
+ if Account.count == 0
122
+ say 'No accounts have been added.'
123
+ else
124
+ say 'Account List'
125
+ Account.find(:all, :order => 'username').each do |a|
126
+ say a
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ mode 'change' do
134
+ description 'Changes the current account being used for posting etc. to the username provided. If no username is provided, a list is presented and you can choose the account from there.'
135
+ argument( 'username' ) {
136
+ optional
137
+ description 'username of account you would like to switched to'
138
+ }
139
+
140
+ def run
141
+ do_work do
142
+ if params['username'].given?
143
+ new_current = Account.find_by_username(params['username'].value)
144
+ else
145
+ Account.find(:all, :order => 'username').each do |a|
146
+ say "#{a.id}. #{a}"
147
+ end
148
+ new_current = ask 'Change current account to (enter number): ' do |q|
149
+ q.validate = /\d+/
150
+ end
151
+ end
152
+
153
+ begin
154
+ current = Account.set_current(new_current)
155
+ say "#{current} is now the current account.\n"
156
+ rescue ActiveRecord::RecordNotFound
157
+ say "ERROR: Account could not be found. Try again. \n"
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ mode 'post' do
164
+ description "Posts a message to twitter using the current account. The following are all valid examples from the command line:
165
+ $ twitter post 'my update'
166
+ $ twitter post my update with quotes
167
+ $ echo 'my update from stdin' | twitter post"
168
+ def run
169
+ do_work do
170
+ post = ARGV.size > 1 ? ARGV.join(" ") : ARGV.shift
171
+ say "Sending twitter update"
172
+ finished, status = false, nil
173
+ progress_thread = Thread.new { until finished; print "."; $stdout.flush; sleep 0.5; end; }
174
+ post_thread = Thread.new(binding()) do |b|
175
+ status = base.post(post, :source => Twitter::SourceName)
176
+ finished = true
177
+ end
178
+ post_thread.join
179
+ progress_thread.join
180
+ say "Got it! New twitter created at: #{status.created_at}\n"
181
+ end
182
+ end
183
+ end
184
+
185
+ mode 'befriend' do
186
+ description "Allows you to add a user as a friend"
187
+ argument('username') {
188
+ required
189
+ description 'username or id of twitterrer to befriend'
190
+ }
191
+
192
+ def run
193
+ do_work do
194
+ username = params['username'].value
195
+ base.create_friendship(username)
196
+ say "#{username} has been added as a friend. follow notifications with 'twitter follow #{username}'"
197
+ end
198
+ end
199
+ end
200
+
201
+ mode 'defriend' do
202
+ description "Allows you to remove a user from being a friend"
203
+ argument('username') {
204
+ required
205
+ description 'username or id of twitterrer to defriend'
206
+ }
207
+
208
+ def run
209
+ do_work do
210
+ username = params['username'].value
211
+ base.destroy_friendship(username)
212
+ say "#{username} has been removed from your friends"
213
+ end
214
+ end
215
+ end
216
+
217
+ mode 'follow' do
218
+ description "Allows you to turn on notifications for a user"
219
+ argument('username') {
220
+ required
221
+ description 'username or id of twitterrer to follow'
222
+ }
223
+
224
+ def run
225
+ do_work do
226
+ username = params['username'].value
227
+ base.follow(username)
228
+ say "You are now following notifications from #{username}"
229
+ end
230
+ end
231
+ end
232
+
233
+ mode 'leave' do
234
+ description "Allows you to turn off notifications for a user"
235
+ argument('username') {
236
+ required
237
+ description 'username or id of twitterrer to leave'
238
+ }
239
+
240
+ def run
241
+ do_work do
242
+ username = params['username'].value
243
+ base.leave(username)
244
+ say "You are no longer following notifications from #{username}"
245
+ end
246
+ end
247
+ end
248
+
249
+ mode 'd' do
250
+ description "Allows you to direct message a user. The following are all valid examples from the command line:
251
+ $ twitter d jnunemaker 'yo homeboy'
252
+ $ twitter d jnunemaker yo homeboy
253
+ $ echo 'yo homeboy' | twitter d jnunemaker"
254
+ argument('username') {
255
+ required
256
+ description 'username or id of twitterrer to direct message'
257
+ }
258
+
259
+ def run
260
+ do_work do
261
+ username = params['username'].value
262
+ post = ARGV.size > 1 ? ARGV.join(" ") : ARGV.shift
263
+ base.d(username, post)
264
+ say "Direct message sent to #{username}"
265
+ end
266
+ end
267
+ end
268
+
269
+ mode 'timeline' do
270
+ description "Allows you to view your timeline, your friends or the public one"
271
+ argument( 'timeline' ) {
272
+ description 'the timeline you wish to see (friends, public, me)'
273
+ default 'friends'
274
+ }
275
+ option('force', 'f') {
276
+ description "Ignore since_id and show first page of results even if there aren't new ones"
277
+ }
278
+
279
+ def run
280
+ do_work do
281
+ timeline = params['timeline'].value == 'me' ? 'user' : params['timeline'].value
282
+ options, since_id = {}, Configuration["#{timeline}_since_id"]
283
+ options[:since_id] = since_id if !since_id.blank? && !params['force'].given?
284
+ cache = [:friends, :user].include?(timeline)
285
+ collection = base.timeline(timeline.to_sym, options)
286
+ output_tweets(collection, {:cache => cache, :since_prefix => timeline})
287
+ end
288
+ end
289
+ end
290
+
291
+ mode 'replies' do
292
+ description 'Allows you to view all @replies at you'
293
+ option('force', 'f') {
294
+ description "Ignore since_id and show first page of replies even if there aren't new ones"
295
+ }
296
+
297
+ def run
298
+ do_work do
299
+ options, since_id = {}, Configuration["replies_since_id"]
300
+ options[:since_id] = since_id if !since_id.blank? && !params['force'].given?
301
+ collection = base.replies(options)
302
+ output_tweets(collection, {:since_prefix => 'replies'})
303
+ end
304
+ end
305
+ end
306
+
307
+ mode 'clear_config' do
308
+ def run
309
+ do_work do
310
+ count = Configuration.count
311
+ Configuration.destroy_all
312
+ say("#{count} configuration entries cleared.")
313
+ end
314
+ end
315
+ end
316
+
317
+ mode 'open' do
318
+ description 'Opens the given twitter user in a browser window'
319
+ argument('username') {
320
+ required
321
+ description "username or id of twitterrer who's page you would like to see"
322
+ }
323
+
324
+ def run
325
+ `open http://twitter.com/#{params['username'].value}`
326
+ end
327
+ end
328
+ }
@@ -0,0 +1,9 @@
1
+ module Twitter
2
+ module CLI
3
+ Config = {
4
+ :adapter => 'sqlite3',
5
+ :database => File.join(ENV['HOME'], '.twitter.db'),
6
+ :timeout => 5000
7
+ }
8
+ end
9
+ end
@@ -0,0 +1,97 @@
1
+ module Twitter
2
+ module CLI
3
+ module Helpers
4
+ class NoActiveAccount < StandardError; end
5
+ class NoAccounts < StandardError; end
6
+
7
+ def output_tweets(collection, options={})
8
+ options.reverse_merge!({
9
+ :cache => false,
10
+ :since_prefix => '',
11
+ :empty_msg => 'Nothing new since your last check.'
12
+ })
13
+ if collection.size > 0
14
+ justify = collection.collect { |s| s.user.screen_name }.max { |a,b| a.length <=> b.length }.length rescue 0
15
+ indention = ' ' * (justify + 3)
16
+ say("\n#{indention}#{collection.size} new tweet(s) found.\n\n")
17
+ collection.each do |s|
18
+ Tweet.create_from_tweet(current_account, s) if options[:cache]
19
+ occurred_at = Time.parse(s.created_at).strftime('On %b %d at %l:%M%P')
20
+ formatted_time = '-' * occurred_at.length + "\n#{indention}#{occurred_at}"
21
+ formatted_name = s.user.screen_name.rjust(justify + 1)
22
+ formatted_msg = ''
23
+ s.text.split(' ').in_groups_of(6, false) { |row| formatted_msg += row.join(' ') + "\n#{indention}" }
24
+ say "#{CGI::unescapeHTML(formatted_name)}: #{CGI::unescapeHTML(formatted_msg)}#{formatted_time}\n\n"
25
+ end
26
+ Configuration["#{options[:since_prefix]}_since_id"] = collection.first.id
27
+ else
28
+ say(options[:empty_msg])
29
+ end
30
+ end
31
+
32
+ def base(username=current_account.username, password=current_account.password)
33
+ @base ||= Twitter::Base.new(username, password)
34
+ end
35
+
36
+ def current_account
37
+ @current_account ||= Account.active
38
+ raise Account.count == 0 ? NoAccounts : NoActiveAccount if @current_account.blank?
39
+ @current_account
40
+ end
41
+
42
+ def attempt_import(&block)
43
+ tweet_file = File.join(ENV['HOME'], '.twitter')
44
+ if File.exists?(tweet_file)
45
+ say '.twitter file found, attempting import...'
46
+ config = YAML::load(File.read(tweet_file))
47
+ if !config['email'].blank? && !config['password'].blank?
48
+ Account.add(:username => config['email'], :password => config['password'])
49
+ say 'Account imported'
50
+ block.call if block_given?
51
+ true
52
+ else
53
+ say "Either your username or password were blank in your .twitter file so I could not import. Use 'twitter add' to add an account."
54
+ false
55
+ end
56
+ end
57
+ end
58
+
59
+ def do_work(&block)
60
+ connect
61
+ begin
62
+ block.call
63
+ rescue Twitter::RateExceeded
64
+ say("Twitter says you've been making too many requests. Wait for a bit and try again.")
65
+ rescue Twitter::Unavailable
66
+ say("Twitter is unavailable right now. Try again later.")
67
+ rescue Twitter::CantConnect => msg
68
+ say("Can't connect to twitter because: #{msg}")
69
+ rescue Twitter::CLI::Helpers::NoActiveAccount
70
+ say("You have not set an active account. Use 'twitter change' to set one now.")
71
+ rescue Twitter::CLI::Helpers::NoAccounts
72
+ unless attempt_import { block.call }
73
+ say("You have not created any accounts. Use 'twitter add' to create one now.")
74
+ end
75
+ end
76
+ end
77
+
78
+ def connect
79
+ ActiveRecord::Base.logger = Logger.new('/tmp/twitter_ar_logger.log')
80
+ ActiveRecord::Base.establish_connection(Twitter::CLI::Config)
81
+ ActiveRecord::Base.connection
82
+ end
83
+
84
+ def migrate
85
+ connect
86
+ ActiveRecord::Migrator.migrate("#{CLI_ROOT}/migrations/")
87
+ end
88
+
89
+ def connect_and_migrate
90
+ say('Attempting to establish connection...')
91
+ connect
92
+ say('Connection established...migrating database...')
93
+ migrate
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,13 @@
1
+ class CreateAccounts < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :accounts do |t|
4
+ t.string :username, :password
5
+ t.boolean :current
6
+ t.timestamps
7
+ end
8
+ end
9
+
10
+ def self.down
11
+ drop_table :accounts
12
+ end
13
+ end