dschn-twitter 0.3.7.2 → 0.4.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.
- 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
|