handcrafted-twitter 0.4.0 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/{History.txt → History} +16 -0
- data/{License.txt → License} +0 -0
- data/{Manifest.txt → Manifest} +14 -16
- data/{README.txt → README} +0 -0
- data/Rakefile +41 -3
- data/bin/twitter +1 -2
- data/examples/direct_messages.rb +1 -0
- data/examples/favorites.rb +4 -4
- data/examples/replies.rb +1 -0
- data/examples/search.rb +1 -0
- data/examples/sent_messages.rb +1 -0
- data/examples/timeline.rb +1 -0
- data/lib/twitter.rb +13 -2
- data/lib/twitter/base.rb +52 -19
- data/lib/twitter/cli.rb +13 -7
- data/lib/twitter/cli/helpers.rb +20 -8
- data/lib/twitter/direct_message.rb +7 -7
- data/lib/twitter/rate_limit_status.rb +4 -4
- data/lib/twitter/search.rb +10 -3
- data/lib/twitter/search_result.rb +83 -0
- data/lib/twitter/search_result_info.rb +82 -0
- data/lib/twitter/status.rb +8 -8
- data/lib/twitter/user.rb +18 -18
- data/lib/twitter/version.rb +1 -7
- data/spec/base_spec.rb +32 -2
- data/spec/cli/helper_spec.rb +21 -7
- data/spec/fixtures/follower_ids.xml +11 -0
- data/spec/fixtures/friend_ids.xml +12 -0
- data/spec/fixtures/friendship_already_exists.xml +5 -0
- data/spec/fixtures/friendship_created.xml +12 -0
- data/spec/fixtures/search_result_info.yml +147 -0
- data/spec/search_spec.rb +12 -1
- data/spec/spec_helper.rb +12 -1
- data/twitter.gemspec +17 -21
- data/website/index.html +4 -1
- metadata +49 -46
- data/config/hoe.rb +0 -74
- data/config/requirements.rb +0 -17
- data/script/destroy +0 -14
- data/script/generate +0 -14
- data/script/txt2html +0 -74
- data/setup.rb +0 -1585
- data/tasks/deployment.rake +0 -50
- data/tasks/environment.rake +0 -7
- data/tasks/website.rake +0 -17
data/{History.txt → History}
RENAMED
@@ -1,3 +1,19 @@
|
|
1
|
+
0.4.1 - January 1, 2009
|
2
|
+
* 4 minor enhancements and 2 bug fixes:
|
3
|
+
* Added better exception handling (Billy Gray)
|
4
|
+
* Added page to search (Michael Ivey)
|
5
|
+
* Adding an option to display tweets on CLI in reverse order (oldest first). (Cameron Booth)
|
6
|
+
* Added in_reply_to_status_id option for replying to statuses (anthonycrumley)
|
7
|
+
* Fixed a bug where the @config was improperly set (K. Adam Christensen)
|
8
|
+
* Fix verify_credentials to include a format (breaks in laconica). (dustin)
|
9
|
+
|
10
|
+
0.4.0 - December 23, 2008
|
11
|
+
* 3 major changes
|
12
|
+
* Removed active support as dependency
|
13
|
+
* Removed CLI dependencies from install dependency list
|
14
|
+
(they are now only installed by you manually)
|
15
|
+
* Switched to echoe for gem managment
|
16
|
+
|
1
17
|
0.3.7 - August 26, 2008
|
2
18
|
* Fixed source param not getting through
|
3
19
|
|
data/{License.txt → License}
RENAMED
File without changes
|
data/{Manifest.txt → Manifest}
RENAMED
@@ -1,11 +1,4 @@
|
|
1
|
-
History.txt
|
2
|
-
License.txt
|
3
|
-
Manifest.txt
|
4
|
-
README.txt
|
5
|
-
Rakefile
|
6
1
|
bin/twitter
|
7
|
-
config/hoe.rb
|
8
|
-
config/requirements.rb
|
9
2
|
examples/blocks.rb
|
10
3
|
examples/direct_messages.rb
|
11
4
|
examples/favorites.rb
|
@@ -20,9 +13,8 @@ examples/sent_messages.rb
|
|
20
13
|
examples/timeline.rb
|
21
14
|
examples/twitter.rb
|
22
15
|
examples/verify_credentials.rb
|
23
|
-
|
16
|
+
History
|
24
17
|
lib/twitter/base.rb
|
25
|
-
lib/twitter/cli.rb
|
26
18
|
lib/twitter/cli/config.rb
|
27
19
|
lib/twitter/cli/helpers.rb
|
28
20
|
lib/twitter/cli/migrations/20080722194500_create_accounts.rb
|
@@ -32,27 +24,36 @@ lib/twitter/cli/migrations/20080722214606_create_configurations.rb
|
|
32
24
|
lib/twitter/cli/models/account.rb
|
33
25
|
lib/twitter/cli/models/configuration.rb
|
34
26
|
lib/twitter/cli/models/tweet.rb
|
27
|
+
lib/twitter/cli.rb
|
35
28
|
lib/twitter/direct_message.rb
|
36
29
|
lib/twitter/easy_class_maker.rb
|
37
30
|
lib/twitter/rate_limit_status.rb
|
38
31
|
lib/twitter/search.rb
|
32
|
+
lib/twitter/search_result.rb
|
33
|
+
lib/twitter/search_result_info.rb
|
39
34
|
lib/twitter/status.rb
|
40
35
|
lib/twitter/user.rb
|
41
36
|
lib/twitter/version.rb
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
37
|
+
lib/twitter.rb
|
38
|
+
License
|
39
|
+
Manifest
|
40
|
+
Rakefile
|
41
|
+
README
|
46
42
|
spec/base_spec.rb
|
47
43
|
spec/cli/helper_spec.rb
|
48
44
|
spec/direct_message_spec.rb
|
45
|
+
spec/fixtures/follower_ids.xml
|
49
46
|
spec/fixtures/followers.xml
|
47
|
+
spec/fixtures/friend_ids.xml
|
50
48
|
spec/fixtures/friends.xml
|
51
49
|
spec/fixtures/friends_for.xml
|
52
50
|
spec/fixtures/friends_lite.xml
|
53
51
|
spec/fixtures/friends_timeline.xml
|
52
|
+
spec/fixtures/friendship_already_exists.xml
|
53
|
+
spec/fixtures/friendship_created.xml
|
54
54
|
spec/fixtures/public_timeline.xml
|
55
55
|
spec/fixtures/rate_limit_status.xml
|
56
|
+
spec/fixtures/search_result_info.yml
|
56
57
|
spec/fixtures/search_results.json
|
57
58
|
spec/fixtures/status.xml
|
58
59
|
spec/fixtures/user.xml
|
@@ -62,9 +63,6 @@ spec/spec.opts
|
|
62
63
|
spec/spec_helper.rb
|
63
64
|
spec/status_spec.rb
|
64
65
|
spec/user_spec.rb
|
65
|
-
tasks/deployment.rake
|
66
|
-
tasks/environment.rake
|
67
|
-
tasks/website.rake
|
68
66
|
twitter.gemspec
|
69
67
|
website/css/common.css
|
70
68
|
website/images/terminal_output.png
|
data/{README.txt → README}
RENAMED
File without changes
|
data/Rakefile
CHANGED
@@ -1,4 +1,42 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
ProjectName = 'twitter'
|
2
|
+
WebsitePath = "jnunemaker@rubyforge.org:/var/www/gforge-projects/#{ProjectName}"
|
3
3
|
|
4
|
-
|
4
|
+
require 'rubygems'
|
5
|
+
require 'rake'
|
6
|
+
require 'echoe'
|
7
|
+
require 'spec/rake/spectask'
|
8
|
+
require "lib/#{ProjectName}/version"
|
9
|
+
|
10
|
+
Echoe.new(ProjectName, Twitter::Version) do |p|
|
11
|
+
p.description = "a command line interface for twitter, also a library which wraps the twitter api"
|
12
|
+
p.url = "http://#{ProjectName}.rubyforge.org"
|
13
|
+
p.author = "John Nunemaker"
|
14
|
+
p.email = "nunemaker@gmail.com"
|
15
|
+
p.extra_deps = [['hpricot', '>= 0.6'], ['activesupport', '>= 2.1'], ['httparty', '>= 0.2.4']]
|
16
|
+
p.need_tar_gz = false
|
17
|
+
p.docs_host = WebsitePath
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'Upload website files to rubyforge'
|
21
|
+
task :website do
|
22
|
+
sh %{rsync -av website/ #{WebsitePath}}
|
23
|
+
Rake::Task['website_docs'].invoke
|
24
|
+
end
|
25
|
+
|
26
|
+
task :website_docs do
|
27
|
+
Rake::Task['redocs'].invoke
|
28
|
+
sh %{rsync -av doc/ #{WebsitePath}/docs}
|
29
|
+
end
|
30
|
+
|
31
|
+
desc 'Preps the gem for a new release'
|
32
|
+
task :prepare do
|
33
|
+
%w[manifest build_gemspec].each do |task|
|
34
|
+
Rake::Task[task].invoke
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Rake::Task[:default].prerequisites.clear
|
39
|
+
task :default => :spec
|
40
|
+
Spec::Rake::SpecTask.new do |t|
|
41
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
42
|
+
end
|
data/bin/twitter
CHANGED
@@ -10,6 +10,5 @@ if ARGV[0] && ARGV[0] == 'd' && !STDIN.tty?
|
|
10
10
|
ARGV[2] = "#{STDIN.read}#{ARGV[2]}"
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
require 'twitter'
|
13
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'twitter'))
|
15
14
|
require 'twitter/cli'
|
data/examples/direct_messages.rb
CHANGED
data/examples/favorites.rb
CHANGED
@@ -4,13 +4,13 @@ config = YAML::load(open(ENV['HOME'] + '/.twitter'))
|
|
4
4
|
|
5
5
|
twitter = Twitter::Base.new(config['email'], config['password'])
|
6
6
|
|
7
|
-
puts '
|
8
|
-
twitter.
|
7
|
+
puts 'CREATE'
|
8
|
+
puts twitter.create_favorite(865416114).text
|
9
9
|
puts
|
10
10
|
puts
|
11
11
|
|
12
|
-
puts '
|
13
|
-
puts
|
12
|
+
puts 'FAVORITES'
|
13
|
+
twitter.favorites.each { |f| puts f.text }
|
14
14
|
puts
|
15
15
|
puts
|
16
16
|
|
data/examples/replies.rb
CHANGED
data/examples/search.rb
CHANGED
@@ -2,6 +2,7 @@ require 'rubygems'
|
|
2
2
|
require File.join(File.dirname(__FILE__), '..', 'lib', 'twitter')
|
3
3
|
|
4
4
|
Twitter::Search.new('httparty').each { |r| puts r.inspect,'' }
|
5
|
+
Twitter::Search.new('httparty').page(2).each { |r| puts r.inspect, '' }
|
5
6
|
|
6
7
|
# search = Twitter::Search.new
|
7
8
|
# search.from('jnunemaker').to('oaknd1').each { |r| puts r.inspect, '' }
|
data/examples/sent_messages.rb
CHANGED
data/examples/timeline.rb
CHANGED
data/lib/twitter.rb
CHANGED
@@ -1,6 +1,12 @@
|
|
1
|
-
|
1
|
+
require 'uri'
|
2
|
+
require 'cgi'
|
3
|
+
require 'net/http'
|
4
|
+
require 'yaml'
|
5
|
+
require 'time'
|
6
|
+
require 'rubygems'
|
7
|
+
require 'hpricot'
|
2
8
|
|
3
|
-
$:.unshift(File.
|
9
|
+
$:.unshift(File.dirname(__FILE__))
|
4
10
|
require 'twitter/version'
|
5
11
|
require 'twitter/easy_class_maker'
|
6
12
|
require 'twitter/base'
|
@@ -9,6 +15,8 @@ require 'twitter/search'
|
|
9
15
|
require 'twitter/status'
|
10
16
|
require 'twitter/direct_message'
|
11
17
|
require 'twitter/rate_limit_status'
|
18
|
+
require 'twitter/search_result_info'
|
19
|
+
require 'twitter/search_result'
|
12
20
|
|
13
21
|
module Twitter
|
14
22
|
class Unavailable < StandardError; end
|
@@ -16,6 +24,9 @@ module Twitter
|
|
16
24
|
class BadResponse < StandardError; end
|
17
25
|
class UnknownTimeline < ArgumentError; end
|
18
26
|
class RateExceeded < StandardError; end
|
27
|
+
class CantFindUsers < ArgumentError; end
|
28
|
+
class AlreadyFollowing < StandardError; end
|
29
|
+
class CantFollowUser < StandardError; end
|
19
30
|
|
20
31
|
SourceName = 'twittergem'
|
21
32
|
end
|
data/lib/twitter/base.rb
CHANGED
@@ -12,8 +12,10 @@ module Twitter
|
|
12
12
|
# Identi.ca example:
|
13
13
|
# Twitter.new('email/username', 'password', :api_host => 'identi.ca/api')
|
14
14
|
def initialize(email, password, options={})
|
15
|
-
@config, @config[:email], @config[:password] = {}, email, password
|
16
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]
|
17
19
|
end
|
18
20
|
|
19
21
|
# Returns an array of statuses for a timeline; Defaults to your friends timeline.
|
@@ -33,6 +35,13 @@ module Twitter
|
|
33
35
|
friends(options.merge({:id => id}))
|
34
36
|
end
|
35
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
|
+
|
36
45
|
# Returns an array of users who are following you
|
37
46
|
def followers(options={})
|
38
47
|
users(call(:followers, {:args => parse_options(options)}))
|
@@ -42,6 +51,13 @@ module Twitter
|
|
42
51
|
followers(options.merge({:id => id}))
|
43
52
|
end
|
44
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
|
+
|
45
61
|
# Returns a single status for a given id
|
46
62
|
def status(id)
|
47
63
|
statuses(call("show/#{id}")).first
|
@@ -159,6 +175,7 @@ module Twitter
|
|
159
175
|
def post(status, options={})
|
160
176
|
form_data = {'status' => status}
|
161
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]
|
162
179
|
Status.new_from_xml(request('statuses/update.xml', :auth => true, :method => :post, :form_data => form_data))
|
163
180
|
end
|
164
181
|
alias :update :post
|
@@ -166,7 +183,7 @@ module Twitter
|
|
166
183
|
# Verifies the credentials for the auth user.
|
167
184
|
# raises Twitter::CantConnect on failure.
|
168
185
|
def verify_credentials
|
169
|
-
request('account/verify_credentials', :auth => true)
|
186
|
+
request('account/verify_credentials.xml', :auth => true)
|
170
187
|
end
|
171
188
|
|
172
189
|
private
|
@@ -184,28 +201,18 @@ module Twitter
|
|
184
201
|
#
|
185
202
|
# ie: call(:public_timeline, :auth => false)
|
186
203
|
def call(method, options={})
|
187
|
-
options
|
204
|
+
options = { :auth => true, :args => {} }.merge(options)
|
188
205
|
# Following line needed as lite=false doesn't work in the API: http://tinyurl.com/yo3h5d
|
189
206
|
options[:args].delete(:lite) unless options[:args][:lite]
|
190
207
|
args = options.delete(:args)
|
191
208
|
request(build_path("statuses/#{method.to_s}.xml", args), options)
|
192
209
|
end
|
193
210
|
|
194
|
-
|
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
|
-
|
211
|
+
def response(path, options={})
|
205
212
|
uri = URI.parse("http://#{@api_host}")
|
206
213
|
|
207
214
|
begin
|
208
|
-
response = Net::HTTP.start(uri.host,
|
215
|
+
response = Net::HTTP::Proxy(@proxy_host, @proxy_port).start(uri.host, uri.port) do |http|
|
209
216
|
klass = Net::HTTP.const_get options[:method].to_s.downcase.capitalize
|
210
217
|
req = klass.new("#{uri.path}/#{path}", options[:headers])
|
211
218
|
req.basic_auth(@config[:email], @config[:password]) if options[:auth]
|
@@ -217,7 +224,24 @@ module Twitter
|
|
217
224
|
rescue => error
|
218
225
|
raise CantConnect, error.message
|
219
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
|
220
240
|
|
241
|
+
handle_response!(response(path, options))
|
242
|
+
end
|
243
|
+
|
244
|
+
def handle_response!(response)
|
221
245
|
if %w[200 304].include?(response.code)
|
222
246
|
response = parse(response.body)
|
223
247
|
raise RateExceeded if (response/:hash/:error).text =~ /Rate limit exceeded/
|
@@ -226,14 +250,23 @@ module Twitter
|
|
226
250
|
raise Unavailable, response.message
|
227
251
|
elsif response.code == '401'
|
228
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}"
|
229
258
|
else
|
230
259
|
raise CantConnect, "Twitter is returning a #{response.code}: #{response.message}"
|
231
260
|
end
|
232
|
-
end
|
261
|
+
end
|
233
262
|
|
234
263
|
# Given a path and a hash, build a full path with the hash turned into a query string
|
235
264
|
def build_path(path, options)
|
236
|
-
|
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
|
+
|
237
270
|
path
|
238
271
|
end
|
239
272
|
|
@@ -245,7 +278,7 @@ module Twitter
|
|
245
278
|
|
246
279
|
# Converts a string response into an Hpricot xml element.
|
247
280
|
def parse(response)
|
248
|
-
|
281
|
+
Hpricot.XML(response || '')
|
249
282
|
end
|
250
283
|
end
|
251
|
-
end
|
284
|
+
end
|
data/lib/twitter/cli.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
|
2
3
|
gem 'main', '>= 2.8.2'
|
3
4
|
gem 'highline', '>= 1.4.0'
|
4
|
-
gem 'activerecord', '
|
5
|
+
gem 'activerecord', '= 2.2.2'
|
5
6
|
gem 'sqlite3-ruby', '>= 1.2.1'
|
7
|
+
|
6
8
|
require 'main'
|
7
9
|
require 'highline/import'
|
8
10
|
require 'activerecord'
|
@@ -177,7 +179,7 @@ Main {
|
|
177
179
|
end
|
178
180
|
post_thread.join
|
179
181
|
progress_thread.join
|
180
|
-
say "Got it! New
|
182
|
+
say "Got it! New tweet created at: #{status.created_at}\n"
|
181
183
|
end
|
182
184
|
end
|
183
185
|
end
|
@@ -215,7 +217,7 @@ Main {
|
|
215
217
|
end
|
216
218
|
|
217
219
|
mode 'follow' do
|
218
|
-
description "Allows you to
|
220
|
+
description "Allows you to add notifications for a user (aka Follow Them)"
|
219
221
|
argument('username') {
|
220
222
|
required
|
221
223
|
description 'username or id of twitterrer to follow'
|
@@ -275,21 +277,25 @@ Main {
|
|
275
277
|
option('force', 'f') {
|
276
278
|
description "Ignore since_id and show first page of results even if there aren't new ones"
|
277
279
|
}
|
280
|
+
option('reverse', 'r') {
|
281
|
+
description 'Reverse the output so the oldest tweets are at the top'
|
282
|
+
}
|
278
283
|
|
279
284
|
def run
|
280
285
|
do_work do
|
281
286
|
timeline = params['timeline'].value == 'me' ? 'user' : params['timeline'].value
|
282
287
|
options, since_id = {}, Configuration["#{timeline}_since_id"]
|
283
|
-
options[:since_id] = since_id if !since_id.
|
288
|
+
options[:since_id] = since_id if !since_id.nil? && !params['force'].given?
|
289
|
+
reverse = params['reverse'].given? ? true : false
|
284
290
|
cache = [:friends, :user].include?(timeline)
|
285
291
|
collection = base.timeline(timeline.to_sym, options)
|
286
|
-
output_tweets(collection, {:cache => cache, :since_prefix => timeline})
|
292
|
+
output_tweets(collection, {:cache => cache, :since_prefix => timeline, :reverse => reverse})
|
287
293
|
end
|
288
294
|
end
|
289
295
|
end
|
290
296
|
|
291
297
|
mode 'replies' do
|
292
|
-
description 'Allows you to view all @replies
|
298
|
+
description 'Allows you to view all @replies sent to you'
|
293
299
|
option('force', 'f') {
|
294
300
|
description "Ignore since_id and show first page of replies even if there aren't new ones"
|
295
301
|
}
|
@@ -297,7 +303,7 @@ Main {
|
|
297
303
|
def run
|
298
304
|
do_work do
|
299
305
|
options, since_id = {}, Configuration["replies_since_id"]
|
300
|
-
options[:since_id] = since_id if !since_id.
|
306
|
+
options[:since_id] = since_id if !since_id.nil? && !params['force'].given?
|
301
307
|
collection = base.replies(options)
|
302
308
|
output_tweets(collection, {:since_prefix => 'replies'})
|
303
309
|
end
|