tuomas-tweetwine 0.2.2 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +7 -0
- data/Rakefile +1 -0
- data/bin/tweetwine +50 -38
- data/lib/tweetwine/client.rb +6 -5
- data/lib/tweetwine/io.rb +1 -1
- data/lib/tweetwine/meta.rb +1 -1
- data/lib/tweetwine/rest_client_wrapper.rb +24 -4
- data/lib/tweetwine/url_shortener.rb +3 -2
- data/lib/tweetwine/util.rb +1 -1
- data/test/client_test.rb +340 -332
- data/test/io_test.rb +140 -143
- data/test/options_test.rb +1 -1
- data/test/rest_client_wrapper_test.rb +42 -5
- data/test/startup_config_test.rb +56 -54
- data/test/url_shortener_test.rb +135 -102
- data/test/util_test.rb +16 -18
- metadata +5 -4
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
=== 0.2.4 released 2009-09-16
|
2
|
+
|
3
|
+
* Retry connection upon connection reset, trying maximum of three times.
|
4
|
+
* Display proper version info on Ruby 1.8 when using option "-v".
|
5
|
+
* Minor code cleanups.
|
6
|
+
* Release 0.2.3 is skipped due to my error in tagging the wrong commit.
|
7
|
+
|
1
8
|
=== 0.2.2 released 2009-09-03
|
2
9
|
|
3
10
|
* Highlight hashtags in statuses.
|
data/Rakefile
CHANGED
data/bin/tweetwine
CHANGED
@@ -15,51 +15,63 @@ require "tweetwine"
|
|
15
15
|
|
16
16
|
include Tweetwine
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
OptionParser.new do |opt|
|
24
|
-
opt.banner =<<-END
|
18
|
+
cmd_parser = lambda do |args|
|
19
|
+
options = {}
|
20
|
+
begin
|
21
|
+
OptionParser.new do |opt|
|
22
|
+
opt.banner =<<-END
|
25
23
|
Usage: tweetwine [options...] [command]
|
26
24
|
|
27
25
|
Commands: #{Client::COMMANDS.join(", ")}
|
28
26
|
|
29
27
|
Options:
|
30
28
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
59
|
-
options
|
29
|
+
END
|
30
|
+
opt.on("-a", "--auth USERNAME:PASSWORD", "Authentication") do |arg|
|
31
|
+
options[:username], options[:password] = arg.split(":", 2)
|
32
|
+
end
|
33
|
+
opt.on("-c", "--colorize", "Colorize output with ANSI escape codes") do
|
34
|
+
options[:colorize] = true
|
35
|
+
end
|
36
|
+
opt.on("-n", "--num N", Integer, "The number of statuses to fetch, defaults to #{Client::DEFAULT_NUM_STATUSES}") do |arg|
|
37
|
+
options[:num_statuses] = arg
|
38
|
+
end
|
39
|
+
opt.on("--no-url-shorten", "Do not shorten URLs for status update") do
|
40
|
+
options[:shorten_urls] = { :enable => false }
|
41
|
+
end
|
42
|
+
opt.on("-p", "--page N", Integer, "The page number of the statuses to fetch, defaults to #{Client::DEFAULT_PAGE_NUM}") do |arg|
|
43
|
+
options[:page_num] = arg
|
44
|
+
end
|
45
|
+
opt.on("-v", "--version", "Show version information and exit") do
|
46
|
+
puts "#{File.basename($0)} #{Tweetwine::VERSION}"
|
47
|
+
exit(EXIT_VERSION)
|
48
|
+
end
|
49
|
+
opt.on_tail("-h", "--help", "Show this help message and exit") do
|
50
|
+
puts opt
|
51
|
+
exit(EXIT_HELP)
|
52
|
+
end
|
53
|
+
end.parse!(args)
|
54
|
+
rescue OptionParser::ParseError => e
|
55
|
+
raise ArgumentError, e.message
|
60
56
|
end
|
61
|
-
|
62
|
-
|
57
|
+
options
|
58
|
+
end
|
59
|
+
|
60
|
+
def create_dependencies(options)
|
61
|
+
io = Tweetwine::IO.new(options)
|
62
|
+
rest_client = RestClientWrapper.new(io)
|
63
|
+
url_shortener = lambda { |opts| UrlShortener.new(rest_client, opts) }
|
64
|
+
{
|
65
|
+
:io => io,
|
66
|
+
:rest_client => rest_client,
|
67
|
+
:url_shortener => url_shortener
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
begin
|
72
|
+
config = StartupConfig.new(Client::COMMANDS)
|
73
|
+
config.parse(ARGV, ENV["HOME"] + "/.tweetwine", &cmd_parser)
|
74
|
+
client = Client.new(create_dependencies(config.options), config.options)
|
63
75
|
client.send(config.command, *config.args)
|
64
76
|
rescue ArgumentError, ClientError => e
|
65
77
|
puts "Error: #{e.message}"
|
data/lib/tweetwine/client.rb
CHANGED
@@ -11,15 +11,16 @@ module Tweetwine
|
|
11
11
|
DEFAULT_PAGE_NUM = 1
|
12
12
|
MAX_STATUS_LENGTH = 140
|
13
13
|
|
14
|
-
def initialize(
|
15
|
-
@io = io
|
14
|
+
def initialize(dependencies, options)
|
15
|
+
@io = dependencies[:io]
|
16
|
+
@rest_client = dependencies[:rest_client]
|
16
17
|
@username = options[:username].to_s
|
17
18
|
raise ArgumentError, "No authentication data given" if @username.empty?
|
18
19
|
@base_url = "https://#{@username}:#{options[:password]}@twitter.com/"
|
19
20
|
@num_statuses = Util.parse_int_gt(options[:num_statuses], DEFAULT_NUM_STATUSES, 1, "number of statuses_to_show")
|
20
21
|
@page_num = Util.parse_int_gt(options[:page_num], DEFAULT_PAGE_NUM, 1, "page number")
|
21
22
|
@url_shortener = if options[:shorten_urls] && options[:shorten_urls][:enable]
|
22
|
-
|
23
|
+
dependencies[:url_shortener].call(options[:shorten_urls])
|
23
24
|
else
|
24
25
|
nil
|
25
26
|
end
|
@@ -110,11 +111,11 @@ module Tweetwine
|
|
110
111
|
end
|
111
112
|
|
112
113
|
def get(body_url)
|
113
|
-
|
114
|
+
@rest_client.get @base_url + body_url
|
114
115
|
end
|
115
116
|
|
116
117
|
def post(body_url, body)
|
117
|
-
|
118
|
+
@rest_client.post @base_url + body_url, body
|
118
119
|
end
|
119
120
|
|
120
121
|
class StatusUpdateFactory
|
data/lib/tweetwine/io.rb
CHANGED
data/lib/tweetwine/meta.rb
CHANGED
@@ -6,12 +6,32 @@ module Tweetwine
|
|
6
6
|
class RestClientWrapper
|
7
7
|
instance_methods.each { |m| undef_method m unless m =~ /(^__|^send$|^object_id$)/ }
|
8
8
|
|
9
|
+
MAX_RETRIES = 3
|
10
|
+
RETRY_BASE_WAIT_TIMEOUT = 4
|
11
|
+
|
12
|
+
def initialize(io)
|
13
|
+
@io = io
|
14
|
+
end
|
15
|
+
|
9
16
|
protected
|
10
17
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
14
|
-
|
18
|
+
def method_missing(name, *args, &block)
|
19
|
+
tries = 0
|
20
|
+
begin
|
21
|
+
tries += 1
|
22
|
+
RestClient.send(name, *args, &block)
|
23
|
+
rescue Errno::ECONNRESET => e
|
24
|
+
if tries < MAX_RETRIES
|
25
|
+
timeout = RETRY_BASE_WAIT_TIMEOUT**tries
|
26
|
+
@io.warn("Could not connect -- retrying in #{timeout} seconds")
|
27
|
+
sleep timeout
|
28
|
+
retry
|
29
|
+
else
|
30
|
+
raise ClientError, e
|
31
|
+
end
|
32
|
+
rescue RestClient::Exception, SocketError, SystemCallError => e
|
33
|
+
raise ClientError, e
|
34
|
+
end
|
15
35
|
end
|
16
36
|
end
|
17
37
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Tweetwine
|
2
2
|
class UrlShortener
|
3
|
-
def initialize(options)
|
3
|
+
def initialize(rest_client, options)
|
4
|
+
@rest_client = rest_client
|
4
5
|
options = Options.new(options, "URL shortening")
|
5
6
|
@method = (options[:method] || :get).to_sym
|
6
7
|
@service_url = options.require :service_url
|
@@ -29,7 +30,7 @@ module Tweetwine
|
|
29
30
|
else
|
30
31
|
raise "Unrecognized HTTP request method"
|
31
32
|
end
|
32
|
-
response =
|
33
|
+
response = @rest_client.send(@method, *rest)
|
33
34
|
doc = Nokogiri::HTML(response)
|
34
35
|
doc.xpath(@xpath_selector).first.to_s
|
35
36
|
end
|
data/lib/tweetwine/util.rb
CHANGED
data/test/client_test.rb
CHANGED
@@ -6,323 +6,182 @@ Mocha::Configuration.allow(:stubbing_non_existent_method)
|
|
6
6
|
module Tweetwine
|
7
7
|
|
8
8
|
class ClientTest < Test::Unit::TestCase
|
9
|
-
context "
|
9
|
+
context "A client instance" do
|
10
10
|
setup do
|
11
11
|
@io = mock()
|
12
|
+
@rest_client = mock()
|
13
|
+
@url_shortener = mock()
|
14
|
+
url_shortener = lambda { |options| @url_shortener }
|
15
|
+
@deps = {
|
16
|
+
:io => @io,
|
17
|
+
:rest_client => @rest_client,
|
18
|
+
:url_shortener => url_shortener
|
19
|
+
}
|
12
20
|
end
|
13
21
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
should "use default number of statuses if not configured otherwise" do
|
22
|
-
@client = Client.new(@io, { :username => "foo", :password => "bar" })
|
23
|
-
assert_equal Client::DEFAULT_NUM_STATUSES, @client.num_statuses
|
24
|
-
end
|
25
|
-
|
26
|
-
should "use configured number of statuses if in allowed range" do
|
27
|
-
@client = Client.new(@io, { :username => "foo", :password => "bar", :num_statuses => 12 })
|
28
|
-
assert_equal 12, @client.num_statuses
|
29
|
-
end
|
30
|
-
|
31
|
-
should "raise an exception for configured number of statuses if not in allowed range" do
|
32
|
-
assert_raise(ArgumentError) { Client.new(@io, { :username => "foo", :password => "bar", :num_statuses => 0 }) }
|
33
|
-
end
|
34
|
-
|
35
|
-
should "use default page number if not configured otherwise" do
|
36
|
-
@client = Client.new(@io, { :username => "foo", :password => "bar" })
|
37
|
-
assert_equal Client::DEFAULT_PAGE_NUM, @client.page_num
|
38
|
-
end
|
22
|
+
context "upon initialization" do
|
23
|
+
should "raise exception when no authentication data is given" do
|
24
|
+
assert_raise(ArgumentError) { Client.new(@deps, {}) }
|
25
|
+
assert_raise(ArgumentError) { Client.new(@deps, { :password => "bar" }) }
|
26
|
+
assert_raise(ArgumentError) { Client.new(@deps, { :username => "", :password => "bar" }) }
|
27
|
+
assert_nothing_raised { Client.new(@deps, { :username => "foo", :password => "bar" }) }
|
28
|
+
end
|
39
29
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
30
|
+
should "use default number of statuses if not configured otherwise" do
|
31
|
+
@client = Client.new(@deps, { :username => "foo", :password => "bar" })
|
32
|
+
assert_equal Client::DEFAULT_NUM_STATUSES, @client.num_statuses
|
33
|
+
end
|
44
34
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
35
|
+
should "use configured number of statuses if in allowed range" do
|
36
|
+
@client = Client.new(@deps, { :username => "foo", :password => "bar", :num_statuses => 12 })
|
37
|
+
assert_equal 12, @client.num_statuses
|
38
|
+
end
|
49
39
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
@username = "spiky"
|
54
|
-
@password = "lullaby"
|
55
|
-
@client = Client.new(@io, { :username => @username, :password => @password })
|
56
|
-
@base_url = "https://#{@username}:#{@password}@twitter.com"
|
57
|
-
@statuses_query_params = "count=#{Client::DEFAULT_NUM_STATUSES}&page=#{Client::DEFAULT_PAGE_NUM}"
|
58
|
-
@users_query_params = "page=#{Client::DEFAULT_PAGE_NUM}"
|
59
|
-
end
|
40
|
+
should "raise an exception for configured number of statuses if not in allowed range" do
|
41
|
+
assert_raise(ArgumentError) { Client.new(@deps, { :username => "foo", :password => "bar", :num_statuses => 0 }) }
|
42
|
+
end
|
60
43
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
:status => {
|
66
|
-
:created_at => Time.at(1).to_s,
|
67
|
-
:text => "wassup?",
|
68
|
-
:in_reply_to => nil
|
69
|
-
}
|
70
|
-
},
|
71
|
-
{
|
72
|
-
:user => "lulzwoo",
|
73
|
-
:status => {
|
74
|
-
:created_at => Time.at(1).to_s,
|
75
|
-
:text => "nuttin'",
|
76
|
-
:in_reply_to => nil
|
77
|
-
}
|
78
|
-
}
|
79
|
-
)
|
80
|
-
RestClientWrapper.expects(:get) \
|
81
|
-
.with("#{@base_url}/statuses/friends_timeline.json?#{@statuses_query_params}") \
|
82
|
-
.returns(status_records.to_json)
|
83
|
-
@io.expects(:show_record).with(gen_records[0])
|
84
|
-
@io.expects(:show_record).with(gen_records[1])
|
85
|
-
@client.home
|
86
|
-
end
|
44
|
+
should "use default page number if not configured otherwise" do
|
45
|
+
@client = Client.new(@deps, { :username => "foo", :password => "bar" })
|
46
|
+
assert_equal Client::DEFAULT_PAGE_NUM, @client.page_num
|
47
|
+
end
|
87
48
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
:status => {
|
93
|
-
:created_at => Time.at(1).to_s,
|
94
|
-
:text => "wassup, @#{@username}?",
|
95
|
-
:in_reply_to => @username
|
96
|
-
}
|
97
|
-
},
|
98
|
-
{
|
99
|
-
:user => "lulzwoo",
|
100
|
-
:status => {
|
101
|
-
:created_at => Time.at(1).to_s,
|
102
|
-
:text => "@#{@username}, doing nuttin'",
|
103
|
-
:in_reply_to => @username
|
104
|
-
}
|
105
|
-
}
|
106
|
-
)
|
107
|
-
RestClientWrapper.expects(:get) \
|
108
|
-
.with("#{@base_url}/statuses/mentions.json?#{@statuses_query_params}") \
|
109
|
-
.returns(status_records.to_json)
|
110
|
-
@io.expects(:show_record).with(gen_records[0])
|
111
|
-
@io.expects(:show_record).with(gen_records[1])
|
112
|
-
@client.mentions
|
113
|
-
end
|
49
|
+
should "use configured page number if in allowed range" do
|
50
|
+
@client = Client.new(@deps, { :username => "foo", :password => "bar", :page_num => 12 })
|
51
|
+
assert_equal 12, @client.page_num
|
52
|
+
end
|
114
53
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
{
|
119
|
-
:user => user,
|
120
|
-
:status => {
|
121
|
-
:created_at => Time.at(1).to_s,
|
122
|
-
:text => "wassup?",
|
123
|
-
:in_reply_to => nil
|
124
|
-
}
|
125
|
-
}
|
126
|
-
)
|
127
|
-
RestClientWrapper.expects(:get) \
|
128
|
-
.with("#{@base_url}/statuses/user_timeline/#{user}.json?#{@statuses_query_params}") \
|
129
|
-
.returns(status_records.to_json)
|
130
|
-
@io.expects(:show_record).with(gen_records[0])
|
131
|
-
@client.user(user)
|
54
|
+
should "raise an exception for configured page number if not in allowed range" do
|
55
|
+
assert_raise(ArgumentError) { Client.new(@deps, { :username => "foo", :password => "bar", :page_num => 0 }) }
|
56
|
+
end
|
132
57
|
end
|
133
58
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
}
|
144
|
-
)
|
145
|
-
RestClientWrapper.expects(:get) \
|
146
|
-
.with("#{@base_url}/statuses/user_timeline/#{@username}.json?#{@statuses_query_params}") \
|
147
|
-
.returns(status_records.to_json)
|
148
|
-
@io.expects(:show_record).with(gen_records[0])
|
149
|
-
@client.user
|
150
|
-
end
|
59
|
+
context "at runtime" do
|
60
|
+
setup do
|
61
|
+
@username = "spiky"
|
62
|
+
@password = "lullaby"
|
63
|
+
@client = Client.new(@deps, { :username => @username, :password => @password })
|
64
|
+
@base_url = "https://#{@username}:#{@password}@twitter.com"
|
65
|
+
@statuses_query_params = "count=#{Client::DEFAULT_NUM_STATUSES}&page=#{Client::DEFAULT_PAGE_NUM}"
|
66
|
+
@users_query_params = "page=#{Client::DEFAULT_PAGE_NUM}"
|
67
|
+
end
|
151
68
|
|
152
|
-
|
153
|
-
should "post a status update via argument, when positive confirmation" do
|
154
|
-
status = "wondering around"
|
69
|
+
should "fetch friends' statuses (home view)" do
|
155
70
|
status_records, gen_records = create_test_statuses(
|
156
71
|
{
|
157
|
-
:user =>
|
72
|
+
:user => "zanzibar",
|
158
73
|
:status => {
|
159
74
|
:created_at => Time.at(1).to_s,
|
160
|
-
:text =>
|
75
|
+
:text => "wassup?",
|
76
|
+
:in_reply_to => nil
|
77
|
+
}
|
78
|
+
},
|
79
|
+
{
|
80
|
+
:user => "lulzwoo",
|
81
|
+
:status => {
|
82
|
+
:created_at => Time.at(1).to_s,
|
83
|
+
:text => "nuttin'",
|
161
84
|
:in_reply_to => nil
|
162
85
|
}
|
163
86
|
}
|
164
87
|
)
|
165
|
-
|
166
|
-
.with("#{@base_url}/statuses/
|
167
|
-
.returns(status_records
|
168
|
-
@io.expects(:confirm).with("Really send?").returns(true)
|
169
|
-
@io.expects(:show_status_preview).with(status)
|
170
|
-
@io.expects(:info).with("Sent status update.\n\n")
|
88
|
+
@rest_client.expects(:get) \
|
89
|
+
.with("#{@base_url}/statuses/friends_timeline.json?#{@statuses_query_params}") \
|
90
|
+
.returns(status_records.to_json)
|
171
91
|
@io.expects(:show_record).with(gen_records[0])
|
172
|
-
@
|
92
|
+
@io.expects(:show_record).with(gen_records[1])
|
93
|
+
@client.home
|
173
94
|
end
|
174
95
|
|
175
|
-
should "
|
176
|
-
status = "wondering around"
|
96
|
+
should "fetch mentions" do
|
177
97
|
status_records, gen_records = create_test_statuses(
|
178
|
-
{
|
98
|
+
{
|
99
|
+
:user => "zanzibar",
|
179
100
|
:status => {
|
180
101
|
:created_at => Time.at(1).to_s,
|
181
|
-
:text =>
|
182
|
-
:in_reply_to =>
|
102
|
+
:text => "wassup, @#{@username}?",
|
103
|
+
:in_reply_to => @username
|
104
|
+
}
|
105
|
+
},
|
106
|
+
{
|
107
|
+
:user => "lulzwoo",
|
108
|
+
:status => {
|
109
|
+
:created_at => Time.at(1).to_s,
|
110
|
+
:text => "@#{@username}, doing nuttin'",
|
111
|
+
:in_reply_to => @username
|
183
112
|
}
|
184
113
|
}
|
185
114
|
)
|
186
|
-
|
187
|
-
.with("#{@base_url}/statuses/
|
188
|
-
.returns(status_records
|
189
|
-
@io.expects(:prompt).with("Status update").returns(status)
|
190
|
-
@io.expects(:show_status_preview).with(status)
|
191
|
-
@io.expects(:confirm).with("Really send?").returns(true)
|
192
|
-
@io.expects(:info).with("Sent status update.\n\n")
|
115
|
+
@rest_client.expects(:get) \
|
116
|
+
.with("#{@base_url}/statuses/mentions.json?#{@statuses_query_params}") \
|
117
|
+
.returns(status_records.to_json)
|
193
118
|
@io.expects(:show_record).with(gen_records[0])
|
194
|
-
@
|
195
|
-
|
196
|
-
|
197
|
-
should "cancel a status update via argument, when negative confirmation" do
|
198
|
-
status = "wondering around"
|
199
|
-
RestClientWrapper.expects(:post).never
|
200
|
-
@io.expects(:show_status_preview).with(status)
|
201
|
-
@io.expects(:confirm).with("Really send?").returns(false)
|
202
|
-
@io.expects(:info).with("Cancelled.")
|
203
|
-
@io.expects(:show_record).never
|
204
|
-
@client.update(status)
|
205
|
-
end
|
206
|
-
|
207
|
-
should "cancel a status update via prompt, when negative confirmation" do
|
208
|
-
status = "wondering around"
|
209
|
-
RestClientWrapper.expects(:post).never
|
210
|
-
@io.expects(:prompt).with("Status update").returns(status)
|
211
|
-
@io.expects(:show_status_preview).with(status)
|
212
|
-
@io.expects(:confirm).with("Really send?").returns(false)
|
213
|
-
@io.expects(:info).with("Cancelled.")
|
214
|
-
@io.expects(:show_record).never
|
215
|
-
@client.update
|
216
|
-
end
|
217
|
-
|
218
|
-
should "cancel a status update via argument, when empty status" do
|
219
|
-
RestClientWrapper.expects(:post).never
|
220
|
-
@io.expects(:confirm).never
|
221
|
-
@io.expects(:info).with("Cancelled.")
|
222
|
-
@io.expects(:show_record).never
|
223
|
-
@client.update("")
|
119
|
+
@io.expects(:show_record).with(gen_records[1])
|
120
|
+
@client.mentions
|
224
121
|
end
|
225
122
|
|
226
|
-
should "
|
227
|
-
|
228
|
-
@io.expects(:prompt).with("Status update").returns("")
|
229
|
-
@io.expects(:confirm).never
|
230
|
-
@io.expects(:info).with("Cancelled.")
|
231
|
-
@io.expects(:show_record).never
|
232
|
-
@client.update
|
233
|
-
end
|
234
|
-
|
235
|
-
should "remove excess whitespace around a status update" do
|
236
|
-
whitespaced_status = " oh, i was sloppy \t "
|
237
|
-
stripped_status = "oh, i was sloppy"
|
123
|
+
should "fetch a specific user's statuses, when the user identified by given argument" do
|
124
|
+
user = "spoonman"
|
238
125
|
status_records, gen_records = create_test_statuses(
|
239
|
-
{
|
126
|
+
{
|
127
|
+
:user => user,
|
240
128
|
:status => {
|
241
129
|
:created_at => Time.at(1).to_s,
|
242
|
-
:text =>
|
130
|
+
:text => "wassup?",
|
243
131
|
:in_reply_to => nil
|
244
132
|
}
|
245
133
|
}
|
246
134
|
)
|
247
|
-
|
248
|
-
.with("#{@base_url}/statuses/
|
249
|
-
.returns(status_records
|
250
|
-
@io.expects(:show_status_preview).with(stripped_status)
|
251
|
-
@io.expects(:confirm).with("Really send?").returns(true)
|
252
|
-
@io.expects(:info).with("Sent status update.\n\n")
|
135
|
+
@rest_client.expects(:get) \
|
136
|
+
.with("#{@base_url}/statuses/user_timeline/#{user}.json?#{@statuses_query_params}") \
|
137
|
+
.returns(status_records.to_json)
|
253
138
|
@io.expects(:show_record).with(gen_records[0])
|
254
|
-
@client.
|
139
|
+
@client.user(user)
|
255
140
|
end
|
256
141
|
|
257
|
-
should "
|
258
|
-
long_status = "x aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll mmm nnn ooo ppp qqq rrr sss ttt uuu vvv www xxx yyy zzz 111 222 333 444 555 666 777 888 999 000"
|
259
|
-
truncated_status = "x aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll mmm nnn ooo ppp qqq rrr sss ttt uuu vvv www xxx yyy zzz 111 222 333 444 555 666 777 888 99"
|
142
|
+
should "fetch a specific user's statuses, with the user being the authenticated user itself when given no argument" do
|
260
143
|
status_records, gen_records = create_test_statuses(
|
261
|
-
{
|
144
|
+
{
|
145
|
+
:user => @username,
|
262
146
|
:status => {
|
263
147
|
:created_at => Time.at(1).to_s,
|
264
|
-
:text =>
|
148
|
+
:text => "wassup?",
|
265
149
|
:in_reply_to => nil
|
266
150
|
}
|
267
151
|
}
|
268
152
|
)
|
269
|
-
|
270
|
-
.with("#{@base_url}/statuses/
|
271
|
-
.returns(status_records
|
272
|
-
@io.expects(:warn).with("Status will be truncated.")
|
273
|
-
@io.expects(:show_status_preview).with(truncated_status)
|
274
|
-
@io.expects(:confirm).with("Really send?").returns(true)
|
275
|
-
@io.expects(:info).with("Sent status update.\n\n")
|
153
|
+
@rest_client.expects(:get) \
|
154
|
+
.with("#{@base_url}/statuses/user_timeline/#{@username}.json?#{@statuses_query_params}") \
|
155
|
+
.returns(status_records.to_json)
|
276
156
|
@io.expects(:show_record).with(gen_records[0])
|
277
|
-
@client.
|
157
|
+
@client.user
|
278
158
|
end
|
279
159
|
|
280
|
-
context "
|
281
|
-
|
282
|
-
|
283
|
-
:username => @username,
|
284
|
-
:password => @password,
|
285
|
-
:shorten_urls => {
|
286
|
-
:enable => true,
|
287
|
-
:service_url => "http://shorten.it/create",
|
288
|
-
:method => "post",
|
289
|
-
:url_param_name => "url",
|
290
|
-
:xpath_selector => "//input[@id='short_url']/@value"
|
291
|
-
}
|
292
|
-
})
|
293
|
-
@url_shortener = @client.instance_variable_get(:@url_shortener)
|
294
|
-
end
|
295
|
-
|
296
|
-
should "shorten URLs, avoiding truncation with long URLs" do
|
297
|
-
long_urls = ["http://www.google.fi/search?q=ruby+nokogiri&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a", "http://www.w3.org/TR/1999/REC-xpath-19991116"]
|
298
|
-
long_status = long_urls.join(" and ")
|
299
|
-
short_urls = ["http://shorten.it/2k7i8", "http://shorten.it/2k7mk"]
|
300
|
-
shortened_status = short_urls.join(" and ")
|
160
|
+
context "for posting status updates" do
|
161
|
+
should "post a status update via argument, when positive confirmation" do
|
162
|
+
status = "wondering around"
|
301
163
|
status_records, gen_records = create_test_statuses(
|
302
|
-
{
|
164
|
+
{
|
165
|
+
:user => @username,
|
303
166
|
:status => {
|
304
167
|
:created_at => Time.at(1).to_s,
|
305
|
-
:text =>
|
168
|
+
:text => status,
|
306
169
|
:in_reply_to => nil
|
307
170
|
}
|
308
171
|
}
|
309
172
|
)
|
310
|
-
|
311
|
-
.with("#{@base_url}/statuses/update.json", {:status =>
|
173
|
+
@rest_client.expects(:post) \
|
174
|
+
.with("#{@base_url}/statuses/update.json", {:status => status}) \
|
312
175
|
.returns(status_records[0].to_json)
|
313
|
-
@url_shortener.expects(:shorten).with(long_urls.first).returns(short_urls.first)
|
314
|
-
@url_shortener.expects(:shorten).with(long_urls.last).returns(short_urls.last)
|
315
|
-
@io.expects(:show_status_preview).with(shortened_status)
|
316
176
|
@io.expects(:confirm).with("Really send?").returns(true)
|
177
|
+
@io.expects(:show_status_preview).with(status)
|
317
178
|
@io.expects(:info).with("Sent status update.\n\n")
|
318
179
|
@io.expects(:show_record).with(gen_records[0])
|
319
|
-
@client.update(
|
180
|
+
@client.update(status)
|
320
181
|
end
|
321
182
|
|
322
|
-
should "
|
323
|
-
|
324
|
-
status = long_urls.join(" and ")
|
325
|
-
short_urls = [nil, ""]
|
183
|
+
should "post a status update via prompt, when positive confirmation" do
|
184
|
+
status = "wondering around"
|
326
185
|
status_records, gen_records = create_test_statuses(
|
327
186
|
{ :user => @username,
|
328
187
|
:status => {
|
@@ -332,134 +191,283 @@ class ClientTest < Test::Unit::TestCase
|
|
332
191
|
}
|
333
192
|
}
|
334
193
|
)
|
335
|
-
|
194
|
+
@rest_client.expects(:post) \
|
336
195
|
.with("#{@base_url}/statuses/update.json", {:status => status}) \
|
337
196
|
.returns(status_records[0].to_json)
|
338
|
-
@
|
339
|
-
@url_shortener.expects(:shorten).with(long_urls.last).returns(short_urls.last)
|
197
|
+
@io.expects(:prompt).with("Status update").returns(status)
|
340
198
|
@io.expects(:show_status_preview).with(status)
|
341
199
|
@io.expects(:confirm).with("Really send?").returns(true)
|
342
200
|
@io.expects(:info).with("Sent status update.\n\n")
|
343
201
|
@io.expects(:show_record).with(gen_records[0])
|
202
|
+
@client.update
|
203
|
+
end
|
204
|
+
|
205
|
+
should "cancel a status update via argument, when negative confirmation" do
|
206
|
+
status = "wondering around"
|
207
|
+
@rest_client.expects(:post).never
|
208
|
+
@io.expects(:show_status_preview).with(status)
|
209
|
+
@io.expects(:confirm).with("Really send?").returns(false)
|
210
|
+
@io.expects(:info).with("Cancelled.")
|
211
|
+
@io.expects(:show_record).never
|
344
212
|
@client.update(status)
|
345
213
|
end
|
346
214
|
|
347
|
-
should "
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
215
|
+
should "cancel a status update via prompt, when negative confirmation" do
|
216
|
+
status = "wondering around"
|
217
|
+
@rest_client.expects(:post).never
|
218
|
+
@io.expects(:prompt).with("Status update").returns(status)
|
219
|
+
@io.expects(:show_status_preview).with(status)
|
220
|
+
@io.expects(:confirm).with("Really send?").returns(false)
|
221
|
+
@io.expects(:info).with("Cancelled.")
|
222
|
+
@io.expects(:show_record).never
|
223
|
+
@client.update
|
224
|
+
end
|
225
|
+
|
226
|
+
should "cancel a status update via argument, when empty status" do
|
227
|
+
@rest_client.expects(:post).never
|
228
|
+
@io.expects(:confirm).never
|
229
|
+
@io.expects(:info).with("Cancelled.")
|
230
|
+
@io.expects(:show_record).never
|
231
|
+
@client.update("")
|
232
|
+
end
|
233
|
+
|
234
|
+
should "cancel a status update via prompt, when empty status" do
|
235
|
+
@rest_client.expects(:post).never
|
236
|
+
@io.expects(:prompt).with("Status update").returns("")
|
237
|
+
@io.expects(:confirm).never
|
238
|
+
@io.expects(:info).with("Cancelled.")
|
239
|
+
@io.expects(:show_record).never
|
240
|
+
@client.update
|
241
|
+
end
|
242
|
+
|
243
|
+
should "remove excess whitespace around a status update" do
|
244
|
+
whitespaced_status = " oh, i was sloppy \t "
|
245
|
+
stripped_status = "oh, i was sloppy"
|
352
246
|
status_records, gen_records = create_test_statuses(
|
353
247
|
{ :user => @username,
|
354
248
|
:status => {
|
355
249
|
:created_at => Time.at(1).to_s,
|
356
|
-
:text =>
|
250
|
+
:text => stripped_status,
|
357
251
|
:in_reply_to => nil
|
358
252
|
}
|
359
253
|
}
|
360
254
|
)
|
361
|
-
|
362
|
-
.with("#{@base_url}/statuses/update.json", {:status =>
|
255
|
+
@rest_client.expects(:post) \
|
256
|
+
.with("#{@base_url}/statuses/update.json", {:status => stripped_status}) \
|
363
257
|
.returns(status_records[0].to_json)
|
364
|
-
@
|
365
|
-
@io.expects(:
|
258
|
+
@io.expects(:show_status_preview).with(stripped_status)
|
259
|
+
@io.expects(:confirm).with("Really send?").returns(true)
|
260
|
+
@io.expects(:info).with("Sent status update.\n\n")
|
261
|
+
@io.expects(:show_record).with(gen_records[0])
|
262
|
+
@client.update(whitespaced_status)
|
263
|
+
end
|
264
|
+
|
265
|
+
should "truncate a status update with too long argument and warn the user" do
|
266
|
+
long_status = "x aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll mmm nnn ooo ppp qqq rrr sss ttt uuu vvv www xxx yyy zzz 111 222 333 444 555 666 777 888 999 000"
|
267
|
+
truncated_status = "x aaa bbb ccc ddd eee fff ggg hhh iii jjj kkk lll mmm nnn ooo ppp qqq rrr sss ttt uuu vvv www xxx yyy zzz 111 222 333 444 555 666 777 888 99"
|
268
|
+
status_records, gen_records = create_test_statuses(
|
269
|
+
{ :user => @username,
|
270
|
+
:status => {
|
271
|
+
:created_at => Time.at(1).to_s,
|
272
|
+
:text => truncated_status,
|
273
|
+
:in_reply_to => nil
|
274
|
+
}
|
275
|
+
}
|
276
|
+
)
|
277
|
+
@rest_client.expects(:post) \
|
278
|
+
.with("#{@base_url}/statuses/update.json", {:status => truncated_status}) \
|
279
|
+
.returns(status_records[0].to_json)
|
280
|
+
@io.expects(:warn).with("Status will be truncated.")
|
281
|
+
@io.expects(:show_status_preview).with(truncated_status)
|
366
282
|
@io.expects(:confirm).with("Really send?").returns(true)
|
367
283
|
@io.expects(:info).with("Sent status update.\n\n")
|
368
284
|
@io.expects(:show_record).with(gen_records[0])
|
369
285
|
@client.update(long_status)
|
370
286
|
end
|
371
287
|
|
372
|
-
context "
|
288
|
+
context "with URL shortening enabled" do
|
373
289
|
setup do
|
374
|
-
@
|
375
|
-
|
376
|
-
|
290
|
+
@client = Client.new(@deps, {
|
291
|
+
:username => @username,
|
292
|
+
:password => @password,
|
293
|
+
:shorten_urls => {
|
294
|
+
:enable => true,
|
295
|
+
:service_url => "http://shorten.it/create",
|
296
|
+
:method => "post",
|
297
|
+
:url_param_name => "url",
|
298
|
+
:xpath_selector => "//input[@id='short_url']/@value"
|
299
|
+
}
|
300
|
+
})
|
301
|
+
end
|
302
|
+
|
303
|
+
should "shorten URLs, avoiding truncation with long URLs" do
|
304
|
+
long_urls = ["http://www.google.fi/search?q=ruby+nokogiri&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a", "http://www.w3.org/TR/1999/REC-xpath-19991116"]
|
305
|
+
long_status = long_urls.join(" and ")
|
306
|
+
short_urls = ["http://shorten.it/2k7i8", "http://shorten.it/2k7mk"]
|
307
|
+
shortened_status = short_urls.join(" and ")
|
308
|
+
status_records, gen_records = create_test_statuses(
|
377
309
|
{ :user => @username,
|
378
310
|
:status => {
|
379
311
|
:created_at => Time.at(1).to_s,
|
380
|
-
:text =>
|
312
|
+
:text => shortened_status,
|
381
313
|
:in_reply_to => nil
|
382
314
|
}
|
383
315
|
}
|
384
316
|
)
|
317
|
+
@rest_client.expects(:post) \
|
318
|
+
.with("#{@base_url}/statuses/update.json", {:status => shortened_status}) \
|
319
|
+
.returns(status_records[0].to_json)
|
320
|
+
@url_shortener.expects(:shorten).with(long_urls.first).returns(short_urls.first)
|
321
|
+
@url_shortener.expects(:shorten).with(long_urls.last).returns(short_urls.last)
|
322
|
+
@io.expects(:show_status_preview).with(shortened_status)
|
323
|
+
@io.expects(:confirm).with("Really send?").returns(true)
|
324
|
+
@io.expects(:info).with("Sent status update.\n\n")
|
325
|
+
@io.expects(:show_record).with(gen_records[0])
|
326
|
+
@client.update(long_status)
|
385
327
|
end
|
386
328
|
|
387
|
-
should "
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
329
|
+
should "discard obviously invalid shortened URLs, using originals instead" do
|
330
|
+
long_urls = ["http://www.google.fi/", "http://www.w3.org/TR/1999/REC-xpath-19991116"]
|
331
|
+
status = long_urls.join(" and ")
|
332
|
+
short_urls = [nil, ""]
|
333
|
+
status_records, gen_records = create_test_statuses(
|
334
|
+
{ :user => @username,
|
335
|
+
:status => {
|
336
|
+
:created_at => Time.at(1).to_s,
|
337
|
+
:text => status,
|
338
|
+
:in_reply_to => nil
|
339
|
+
}
|
340
|
+
}
|
341
|
+
)
|
342
|
+
@rest_client.expects(:post) \
|
343
|
+
.with("#{@base_url}/statuses/update.json", {:status => status}) \
|
344
|
+
.returns(status_records[0].to_json)
|
345
|
+
@url_shortener.expects(:shorten).with(long_urls.first).returns(short_urls.first)
|
346
|
+
@url_shortener.expects(:shorten).with(long_urls.last).returns(short_urls.last)
|
347
|
+
@io.expects(:show_status_preview).with(status)
|
394
348
|
@io.expects(:confirm).with("Really send?").returns(true)
|
395
349
|
@io.expects(:info).with("Sent status update.\n\n")
|
396
|
-
@io.expects(:show_record).with(
|
397
|
-
@client.update(
|
350
|
+
@io.expects(:show_record).with(gen_records[0])
|
351
|
+
@client.update(status)
|
398
352
|
end
|
399
353
|
|
400
|
-
should "
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
354
|
+
should "reuse a shortened URL for duplicate long URLs" do
|
355
|
+
long_urls = ["http://www.w3.org/TR/1999/REC-xpath-19991116"] * 2
|
356
|
+
long_status = long_urls.join(" and ")
|
357
|
+
short_url = "http://shorten.it/2k7mk"
|
358
|
+
short_status = ([short_url] * 2).join(" and ")
|
359
|
+
status_records, gen_records = create_test_statuses(
|
360
|
+
{ :user => @username,
|
361
|
+
:status => {
|
362
|
+
:created_at => Time.at(1).to_s,
|
363
|
+
:text => short_status,
|
364
|
+
:in_reply_to => nil
|
365
|
+
}
|
366
|
+
}
|
367
|
+
)
|
368
|
+
@rest_client.expects(:post) \
|
369
|
+
.with("#{@base_url}/statuses/update.json", {:status => short_status}) \
|
370
|
+
.returns(status_records[0].to_json)
|
371
|
+
@url_shortener.expects(:shorten).with(long_urls.first).returns(short_url)
|
372
|
+
@io.expects(:show_status_preview).with(short_status)
|
407
373
|
@io.expects(:confirm).with("Really send?").returns(true)
|
408
374
|
@io.expects(:info).with("Sent status update.\n\n")
|
409
|
-
@io.expects(:show_record).with(
|
410
|
-
@client.update(
|
375
|
+
@io.expects(:show_record).with(gen_records[0])
|
376
|
+
@client.update(long_status)
|
377
|
+
end
|
378
|
+
|
379
|
+
context "in erroneous situations" do
|
380
|
+
setup do
|
381
|
+
@url = "http://www.w3.org/TR/1999/REC-xpath-19991116"
|
382
|
+
@status = "skimming through #{@url}"
|
383
|
+
@status_records, @gen_records = create_test_statuses(
|
384
|
+
{ :user => @username,
|
385
|
+
:status => {
|
386
|
+
:created_at => Time.at(1).to_s,
|
387
|
+
:text => @status,
|
388
|
+
:in_reply_to => nil
|
389
|
+
}
|
390
|
+
}
|
391
|
+
)
|
392
|
+
end
|
393
|
+
|
394
|
+
should "skip shortening URLs if required libraries are not found" do
|
395
|
+
@rest_client.expects(:post) \
|
396
|
+
.with("#{@base_url}/statuses/update.json", {:status => @status}) \
|
397
|
+
.returns(@status_records[0].to_json)
|
398
|
+
@url_shortener.expects(:shorten).with(@url).raises(LoadError, "gem not found")
|
399
|
+
@io.expects(:warn)
|
400
|
+
@io.expects(:show_status_preview).with(@status)
|
401
|
+
@io.expects(:confirm).with("Really send?").returns(true)
|
402
|
+
@io.expects(:info).with("Sent status update.\n\n")
|
403
|
+
@io.expects(:show_record).with(@gen_records[0])
|
404
|
+
@client.update(@status)
|
405
|
+
end
|
406
|
+
|
407
|
+
should "skip shortening URLs upon connection error to the URL shortening service" do
|
408
|
+
@rest_client.expects(:post) \
|
409
|
+
.with("#{@base_url}/statuses/update.json", {:status => @status}) \
|
410
|
+
.returns(@status_records[0].to_json)
|
411
|
+
@url_shortener.expects(:shorten).with(@url).raises(ClientError, "connection error")
|
412
|
+
@io.expects(:warn)
|
413
|
+
@io.expects(:show_status_preview).with(@status)
|
414
|
+
@io.expects(:confirm).with("Really send?").returns(true)
|
415
|
+
@io.expects(:info).with("Sent status update.\n\n")
|
416
|
+
@io.expects(:show_record).with(@gen_records[0])
|
417
|
+
@client.update(@status)
|
418
|
+
end
|
411
419
|
end
|
412
420
|
end
|
413
421
|
end
|
414
|
-
end
|
415
422
|
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
423
|
+
should "fetch friends" do
|
424
|
+
user_records, gen_records = create_test_users(
|
425
|
+
{
|
426
|
+
:user => "zanzibar",
|
427
|
+
:status => {
|
428
|
+
:created_at => Time.at(1).to_s,
|
429
|
+
:text => "wassup, @foo?",
|
430
|
+
:in_reply_to => "foo"
|
431
|
+
}
|
432
|
+
},
|
433
|
+
{
|
434
|
+
:user => "lulzwoo",
|
435
|
+
:status => {
|
436
|
+
:created_at => Time.at(1).to_s,
|
437
|
+
:text => "@foo, doing nuttin'",
|
438
|
+
:in_reply_to => "foo"
|
439
|
+
}
|
432
440
|
}
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
end
|
441
|
+
)
|
442
|
+
@rest_client.expects(:get) \
|
443
|
+
.with("#{@base_url}/statuses/friends/#{@username}.json?#{@users_query_params}") \
|
444
|
+
.returns(user_records.to_json)
|
445
|
+
@io.expects(:show_record).with(gen_records[0])
|
446
|
+
@io.expects(:show_record).with(gen_records[1])
|
447
|
+
@client.friends
|
448
|
+
end
|
442
449
|
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
450
|
+
should "fetch followers" do
|
451
|
+
user_records, gen_records = create_test_users(
|
452
|
+
{
|
453
|
+
:user => "zanzibar",
|
454
|
+
:status => {
|
455
|
+
:created_at => Time.at(1).to_s,
|
456
|
+
:text => "wassup, @foo?",
|
457
|
+
:in_reply_to => "foo"
|
458
|
+
}
|
459
|
+
},
|
460
|
+
{
|
461
|
+
:user => "lulzwoo"
|
451
462
|
}
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
@io.expects(:show_record).with(gen_records[0])
|
461
|
-
@io.expects(:show_record).with(gen_records[1])
|
462
|
-
@client.followers
|
463
|
+
)
|
464
|
+
@rest_client.expects(:get) \
|
465
|
+
.with("#{@base_url}/statuses/followers/#{@username}.json?#{@users_query_params}") \
|
466
|
+
.returns(user_records.to_json)
|
467
|
+
@io.expects(:show_record).with(gen_records[0])
|
468
|
+
@io.expects(:show_record).with(gen_records[1])
|
469
|
+
@client.followers
|
470
|
+
end
|
463
471
|
end
|
464
472
|
end
|
465
473
|
end
|