dschn-twitter 0.3.7.2 → 0.4.1
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} +12 -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/base.rb +37 -27
- data/lib/twitter/cli/helpers.rb +20 -8
- data/lib/twitter/cli.rb +13 -7
- data/lib/twitter/search.rb +10 -3
- data/lib/twitter/version.rb +1 -7
- data/lib/twitter.rb +13 -2
- data/spec/base_spec.rb +20 -2
- data/spec/cli/helper_spec.rb +21 -7
- 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 +40 -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,17 +24,21 @@ 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
|
@@ -51,8 +47,11 @@ spec/fixtures/friends.xml
|
|
51
47
|
spec/fixtures/friends_for.xml
|
52
48
|
spec/fixtures/friends_lite.xml
|
53
49
|
spec/fixtures/friends_timeline.xml
|
50
|
+
spec/fixtures/friendship_already_exists.xml
|
51
|
+
spec/fixtures/friendship_created.xml
|
54
52
|
spec/fixtures/public_timeline.xml
|
55
53
|
spec/fixtures/rate_limit_status.xml
|
54
|
+
spec/fixtures/search_result_info.yml
|
56
55
|
spec/fixtures/search_results.json
|
57
56
|
spec/fixtures/status.xml
|
58
57
|
spec/fixtures/user.xml
|
@@ -62,9 +61,6 @@ spec/spec.opts
|
|
62
61
|
spec/spec_helper.rb
|
63
62
|
spec/status_spec.rb
|
64
63
|
spec/user_spec.rb
|
65
|
-
tasks/deployment.rake
|
66
|
-
tasks/environment.rake
|
67
|
-
tasks/website.rake
|
68
64
|
twitter.gemspec
|
69
65
|
website/css/common.css
|
70
66
|
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/base.rb
CHANGED
@@ -12,16 +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'
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
@config[:timeout] = time
|
21
|
-
end
|
22
|
-
|
23
|
-
def timeout
|
24
|
-
@config[:timeout]
|
16
|
+
@config, @config[:email], @config[:password] = options, email, password
|
17
|
+
@proxy_host = options[:proxy_host]
|
18
|
+
@proxy_port = options[:proxy_port]
|
25
19
|
end
|
26
20
|
|
27
21
|
# Returns an array of statuses for a timeline; Defaults to your friends timeline.
|
@@ -167,6 +161,7 @@ module Twitter
|
|
167
161
|
def post(status, options={})
|
168
162
|
form_data = {'status' => status}
|
169
163
|
form_data.merge!({'source' => options[:source]}) if options[:source]
|
164
|
+
form_data.merge!({'in_reply_to_status_id' => options[:in_reply_to_status_id]}) if options[:in_reply_to_status_id]
|
170
165
|
Status.new_from_xml(request('statuses/update.xml', :auth => true, :method => :post, :form_data => form_data))
|
171
166
|
end
|
172
167
|
alias :update :post
|
@@ -174,7 +169,7 @@ module Twitter
|
|
174
169
|
# Verifies the credentials for the auth user.
|
175
170
|
# raises Twitter::CantConnect on failure.
|
176
171
|
def verify_credentials
|
177
|
-
request('account/verify_credentials', :auth => true)
|
172
|
+
request('account/verify_credentials.xml', :auth => true)
|
178
173
|
end
|
179
174
|
|
180
175
|
private
|
@@ -192,41 +187,47 @@ module Twitter
|
|
192
187
|
#
|
193
188
|
# ie: call(:public_timeline, :auth => false)
|
194
189
|
def call(method, options={})
|
195
|
-
options
|
190
|
+
options = { :auth => true, :args => {} }.merge(options)
|
196
191
|
# Following line needed as lite=false doesn't work in the API: http://tinyurl.com/yo3h5d
|
197
192
|
options[:args].delete(:lite) unless options[:args][:lite]
|
198
193
|
args = options.delete(:args)
|
199
194
|
request(build_path("statuses/#{method.to_s}.xml", args), options)
|
200
195
|
end
|
201
196
|
|
202
|
-
|
203
|
-
def request(path, options={})
|
204
|
-
options.reverse_merge!({
|
205
|
-
:headers => { "User-Agent" => @config[:email] },
|
206
|
-
:method => :get
|
207
|
-
})
|
208
|
-
unless options[:since].blank?
|
209
|
-
since = options[:since].kind_of?(Date) ? options[:since].strftime('%a, %d-%b-%y %T GMT') : options[:since].to_s
|
210
|
-
options[:headers]["If-Modified-Since"] = since
|
211
|
-
end
|
212
|
-
|
197
|
+
def response(path, options={})
|
213
198
|
uri = URI.parse("http://#{@api_host}")
|
214
199
|
|
215
200
|
begin
|
216
|
-
response = Net::HTTP.start(uri.host,
|
201
|
+
response = Net::HTTP::Proxy(@proxy_host, @proxy_port).start(uri.host, uri.port) do |http|
|
217
202
|
klass = Net::HTTP.const_get options[:method].to_s.downcase.capitalize
|
218
203
|
req = klass.new("#{uri.path}/#{path}", options[:headers])
|
219
204
|
req.basic_auth(@config[:email], @config[:password]) if options[:auth]
|
220
205
|
if options[:method].to_s == 'post' && options[:form_data]
|
221
206
|
req.set_form_data(options[:form_data])
|
222
207
|
end
|
223
|
-
http.read_timeout = @config[:timeout] if @config[:timeout]
|
224
208
|
http.request(req)
|
225
209
|
end
|
226
210
|
rescue => error
|
227
211
|
raise CantConnect, error.message
|
228
212
|
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# Makes a request to twitter.
|
216
|
+
def request(path, options={})
|
217
|
+
options = {
|
218
|
+
:headers => { "User-Agent" => @config[:email] },
|
219
|
+
:method => :get,
|
220
|
+
}.merge(options)
|
221
|
+
|
222
|
+
unless options[:since].nil?
|
223
|
+
since = options[:since].kind_of?(Date) ? options[:since].strftime('%a, %d-%b-%y %T GMT') : options[:since].to_s
|
224
|
+
options[:headers]["If-Modified-Since"] = since
|
225
|
+
end
|
229
226
|
|
227
|
+
handle_response!(response(path, options))
|
228
|
+
end
|
229
|
+
|
230
|
+
def handle_response!(response)
|
230
231
|
if %w[200 304].include?(response.code)
|
231
232
|
response = parse(response.body)
|
232
233
|
raise RateExceeded if (response/:hash/:error).text =~ /Rate limit exceeded/
|
@@ -237,14 +238,23 @@ module Twitter
|
|
237
238
|
raise Unavailable, response.message
|
238
239
|
elsif response.code == '401'
|
239
240
|
raise CantConnect, 'Authentication failed. Check your username and password'
|
241
|
+
elsif response.code == '403'
|
242
|
+
error_message = (parse(response.body)/:hash/:error).text
|
243
|
+
raise CantFindUsers, error_message if error_message =~ /Could not find both specified users/
|
244
|
+
raise AlreadyFollowing, error_message if error_message =~ /already on your list/
|
245
|
+
raise CantFollowUser, "Response code #{response.code}: #{response.message} #{error_message}"
|
240
246
|
else
|
241
247
|
raise CantConnect, "Twitter is returning a #{response.code}: #{response.message}"
|
242
248
|
end
|
243
|
-
end
|
249
|
+
end
|
244
250
|
|
245
251
|
# Given a path and a hash, build a full path with the hash turned into a query string
|
246
252
|
def build_path(path, options)
|
247
|
-
|
253
|
+
unless options.nil?
|
254
|
+
query = options.inject('') { |str, h| str += "#{CGI.escape(h[0].to_s)}=#{CGI.escape(h[1].to_s)}&"; str }
|
255
|
+
path += "?#{query}"
|
256
|
+
end
|
257
|
+
|
248
258
|
path
|
249
259
|
end
|
250
260
|
|
@@ -259,4 +269,4 @@ module Twitter
|
|
259
269
|
Hpricot.XML(response || '')
|
260
270
|
end
|
261
271
|
end
|
262
|
-
end
|
272
|
+
end
|
data/lib/twitter/cli/helpers.rb
CHANGED
@@ -5,25 +5,37 @@ module Twitter
|
|
5
5
|
class NoAccounts < StandardError; end
|
6
6
|
|
7
7
|
def output_tweets(collection, options={})
|
8
|
-
options
|
8
|
+
options = {
|
9
9
|
:cache => false,
|
10
10
|
:since_prefix => '',
|
11
|
-
:empty_msg => 'Nothing new since your last check.'
|
12
|
-
|
11
|
+
:empty_msg => 'Nothing new since your last check.',
|
12
|
+
:reverse => false
|
13
|
+
}.merge(options)
|
14
|
+
|
13
15
|
if collection.size > 0
|
14
16
|
justify = collection.collect { |s| s.user.screen_name }.max { |a,b| a.length <=> b.length }.length rescue 0
|
15
17
|
indention = ' ' * (justify + 3)
|
16
18
|
say("\n#{indention}#{collection.size} new tweet(s) found.\n\n")
|
19
|
+
collection.reverse! if options[:reverse]
|
17
20
|
collection.each do |s|
|
18
21
|
Tweet.create_from_tweet(current_account, s) if options[:cache]
|
22
|
+
|
19
23
|
occurred_at = Time.parse(s.created_at).strftime('On %b %d at %l:%M%P')
|
20
24
|
formatted_time = '-' * occurred_at.length + "\n#{indention}#{occurred_at}"
|
21
25
|
formatted_name = s.user.screen_name.rjust(justify + 1)
|
22
26
|
formatted_msg = ''
|
23
|
-
|
24
|
-
|
27
|
+
|
28
|
+
s.text.split(' ').each_with_index do |word, idx|
|
29
|
+
formatted_msg += "#{word} "
|
30
|
+
|
31
|
+
sixth_word = idx != 0 && idx % 6 == 0
|
32
|
+
formatted_msg += "\n#{indention}" if sixth_word
|
33
|
+
end
|
34
|
+
|
35
|
+
say "#{CGI::unescapeHTML(formatted_name)}: #{CGI::unescapeHTML(formatted_msg)}\n#{indention}#{formatted_time}\n\n"
|
25
36
|
end
|
26
|
-
|
37
|
+
|
38
|
+
Configuration["#{options[:since_prefix]}_since_id"] = options[:reverse] ? collection.last.id : collection.first.id
|
27
39
|
else
|
28
40
|
say(options[:empty_msg])
|
29
41
|
end
|
@@ -35,7 +47,7 @@ module Twitter
|
|
35
47
|
|
36
48
|
def current_account
|
37
49
|
@current_account ||= Account.active
|
38
|
-
raise Account.count == 0 ? NoAccounts : NoActiveAccount if @current_account.
|
50
|
+
raise Account.count == 0 ? NoAccounts : NoActiveAccount if @current_account.nil?
|
39
51
|
@current_account
|
40
52
|
end
|
41
53
|
|
@@ -44,7 +56,7 @@ module Twitter
|
|
44
56
|
if File.exists?(tweet_file)
|
45
57
|
say '.twitter file found, attempting import...'
|
46
58
|
config = YAML::load(File.read(tweet_file))
|
47
|
-
if !config['email'].
|
59
|
+
if !config['email'].nil? && !config['password'].nil?
|
48
60
|
Account.add(:username => config['email'], :password => config['password'])
|
49
61
|
say 'Account imported'
|
50
62
|
block.call if block_given?
|
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
|
data/lib/twitter/search.rb
CHANGED
@@ -11,7 +11,7 @@ module Twitter
|
|
11
11
|
|
12
12
|
def initialize(q=nil)
|
13
13
|
clear
|
14
|
-
containing(q)
|
14
|
+
containing(q) if q && q.strip != ''
|
15
15
|
end
|
16
16
|
|
17
17
|
def from(user)
|
@@ -59,6 +59,12 @@ module Twitter
|
|
59
59
|
self
|
60
60
|
end
|
61
61
|
|
62
|
+
# Which page of results to fetch
|
63
|
+
def page(num)
|
64
|
+
@query[:page] = num
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
62
68
|
# Only searches tweets since a given id.
|
63
69
|
# Recommended to use this when possible.
|
64
70
|
def since(since_id)
|
@@ -83,7 +89,7 @@ module Twitter
|
|
83
89
|
# If you want to get results do something other than iterate over them.
|
84
90
|
def fetch
|
85
91
|
@query[:q] = @query[:q].join(' ')
|
86
|
-
self.class.get('/search.json', {:query => @query})
|
92
|
+
SearchResultInfo.new_from_hash(self.class.get('/search.json', {:query => @query}))
|
87
93
|
end
|
88
94
|
|
89
95
|
def each
|
@@ -91,4 +97,5 @@ module Twitter
|
|
91
97
|
@result['results'].each { |r| yield r }
|
92
98
|
end
|
93
99
|
end
|
94
|
-
end
|
100
|
+
end
|
101
|
+
|
data/lib/twitter/version.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/spec/base_spec.rb
CHANGED
@@ -16,7 +16,11 @@ describe "Twitter::Base" do
|
|
16
16
|
lambda { @base.timeline(:fakeyoutey) }.should raise_error(Twitter::UnknownTimeline)
|
17
17
|
end
|
18
18
|
|
19
|
-
it "should default to friends timeline"
|
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
|
20
24
|
|
21
25
|
it "should be able to retrieve friends timeline" do
|
22
26
|
data = open(File.dirname(__FILE__) + '/fixtures/friends_timeline.xml').read
|
@@ -65,6 +69,20 @@ describe "Twitter::Base" do
|
|
65
69
|
timeline.size.should == 29
|
66
70
|
timeline.first.name.should == 'Blaine Cook'
|
67
71
|
end
|
72
|
+
|
73
|
+
it "should be able to create a friendship" do
|
74
|
+
data = open(File.dirname(__FILE__) + '/fixtures/friendship_created.xml').read
|
75
|
+
@base.should_receive(:request).and_return(Hpricot::XML(data))
|
76
|
+
user = @base.create_friendship('jnunemaker')
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should bomb if friendship already exists" do
|
80
|
+
data = open(File.dirname(__FILE__) + '/fixtures/friendship_already_exists.xml').read
|
81
|
+
response = Net::HTTPForbidden.new("1.1", '403', '')
|
82
|
+
response.stub!(:body).and_return(data)
|
83
|
+
@base.should_receive(:response).and_return(response)
|
84
|
+
lambda { @base.create_friendship('billymeltdown') }.should raise_error(Twitter::AlreadyFollowing)
|
85
|
+
end
|
68
86
|
end
|
69
87
|
|
70
88
|
it "should be able to get single status" do
|
@@ -106,4 +124,4 @@ describe "Twitter::Base" do
|
|
106
124
|
@base.rate_limit_status.remaining_hits.should == 5
|
107
125
|
end
|
108
126
|
end
|
109
|
-
end
|
127
|
+
end
|
data/spec/cli/helper_spec.rb
CHANGED
@@ -8,6 +8,10 @@ def say(str)
|
|
8
8
|
puts str
|
9
9
|
end
|
10
10
|
|
11
|
+
class Tweet < OpenStruct
|
12
|
+
attr_accessor :id
|
13
|
+
end
|
14
|
+
|
11
15
|
describe Twitter::CLI::Helpers do
|
12
16
|
include Twitter::CLI::Helpers
|
13
17
|
|
@@ -15,21 +19,31 @@ describe Twitter::CLI::Helpers do
|
|
15
19
|
before do
|
16
20
|
Configuration.stub!(:[]=).and_return(true)
|
17
21
|
@collection = [
|
18
|
-
|
19
|
-
:
|
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.',
|
20
25
|
:created_at => Time.mktime(2008, 5, 1, 10, 15, 00).strftime('%Y-%m-%d %H:%M:%S'),
|
21
|
-
:user
|
26
|
+
:user => OpenStruct.new(:screen_name => 'jnunemaker')
|
22
27
|
),
|
23
|
-
|
24
|
-
:
|
28
|
+
Tweet.new(
|
29
|
+
:id => 2,
|
30
|
+
:text => 'This is my long message that I want to see formatted ooooh so pretty with a.',
|
25
31
|
:created_at => Time.mktime(2008, 4, 1, 10, 15, 00).strftime('%Y-%m-%d %H:%M:%S'),
|
26
|
-
:user
|
32
|
+
:user => OpenStruct.new(:screen_name => 'danielmorrison')
|
27
33
|
)
|
28
34
|
]
|
29
35
|
end
|
30
36
|
|
31
37
|
specify "should properly format" do
|
32
|
-
|
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/)
|
33
47
|
end
|
34
48
|
end
|
35
49
|
end
|