tweetwine 0.2.5 → 0.2.7
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +30 -17
- data/README.rdoc +16 -17
- data/Rakefile +2 -0
- data/bin/tweetwine +3 -68
- data/example/example_helper.rb +31 -41
- data/example/fixtures/{statuses.json → home.json} +0 -0
- data/example/fixtures/mentions.json +1 -0
- data/example/fixtures/search.json +1 -0
- data/example/fixtures/update.json +1 -0
- data/example/fixtures/user.json +1 -0
- data/example/fixtures/users.json +1 -0
- data/example/search_statuses_example.rb +36 -0
- data/example/show_followers_example.rb +23 -0
- data/example/show_friends_example.rb +23 -0
- data/example/show_home_example.rb +51 -0
- data/example/show_mentions_example.rb +23 -0
- data/example/show_metadata_example.rb +54 -7
- data/example/show_user_example.rb +37 -0
- data/example/update_status_example.rb +65 -0
- data/lib/tweetwine/cli.rb +241 -0
- data/lib/tweetwine/client.rb +94 -57
- data/lib/tweetwine/io.rb +39 -28
- data/lib/tweetwine/meta.rb +1 -1
- data/lib/tweetwine/retrying_http.rb +93 -0
- data/lib/tweetwine/startup_config.rb +14 -15
- data/lib/tweetwine/url_shortener.rb +13 -8
- data/lib/tweetwine/util.rb +14 -0
- data/lib/tweetwine.rb +2 -1
- data/test/cli_test.rb +16 -0
- data/test/client_test.rb +275 -205
- data/test/fixtures/test_config.yaml +2 -1
- data/test/io_test.rb +89 -62
- data/test/retrying_http_test.rb +127 -0
- data/test/startup_config_test.rb +52 -27
- data/test/test_helper.rb +32 -17
- data/test/url_shortener_test.rb +18 -18
- data/test/util_test.rb +145 -47
- metadata +20 -7
- data/example/show_latest_statuses_example.rb +0 -45
- data/lib/tweetwine/rest_client_wrapper.rb +0 -37
- data/test/rest_client_wrapper_test.rb +0 -68
@@ -0,0 +1,37 @@
|
|
1
|
+
require "example_helper"
|
2
|
+
|
3
|
+
FakeWeb.register_uri(:get, "https://#{TEST_AUTH}@twitter.com/statuses/user_timeline/#{TEST_USER}.json?count=20&page=1", :body => fixture("user.json"))
|
4
|
+
|
5
|
+
Feature "show a specific user's latest statuses" do
|
6
|
+
in_order_to "to see what is going on with a specific user"
|
7
|
+
as_a "authenticated user"
|
8
|
+
i_want_to "see the latest statuses of a specific user"
|
9
|
+
|
10
|
+
Scenario "see my latest statuses" do
|
11
|
+
When "application is launched 'user' command and without extra arguments" do
|
12
|
+
@output = launch_cli(%W{-a #{TEST_AUTH} --no-colors user})
|
13
|
+
end
|
14
|
+
|
15
|
+
Then "my the latest statuses are shown" do
|
16
|
+
@output[0].should == "jillv, in reply to chris, 9 hours ago:"
|
17
|
+
@output[1].should == "@chris wait me until the garden"
|
18
|
+
@output[2].should == ""
|
19
|
+
@output[3].should == "jillv, 3 days ago:"
|
20
|
+
@output[4].should == "so boring to wait"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Scenario "see the latest statuses of another user" do
|
25
|
+
When "application is launched 'user' command and the user as an extra argument" do
|
26
|
+
@output = launch_cli(%W{-a #{TEST_AUTH} --no-colors user #{TEST_USER}})
|
27
|
+
end
|
28
|
+
|
29
|
+
Then "the latest statuses of the user are shown" do
|
30
|
+
@output[0].should == "jillv, in reply to chris, 9 hours ago:"
|
31
|
+
@output[1].should == "@chris wait me until the garden"
|
32
|
+
@output[2].should == ""
|
33
|
+
@output[3].should == "jillv, 3 days ago:"
|
34
|
+
@output[4].should == "so boring to wait"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "example_helper"
|
2
|
+
|
3
|
+
FakeWeb.register_uri(:post, "https://#{TEST_AUTH}@twitter.com/statuses/update.json", :body => fixture("update.json"))
|
4
|
+
|
5
|
+
Feature "update my status" do
|
6
|
+
in_order_to "tell something about me to the world"
|
7
|
+
as_a "authenticated user"
|
8
|
+
i_want_to "update my status"
|
9
|
+
|
10
|
+
STATUS = "bored. going to sleep."
|
11
|
+
|
12
|
+
Scenario "update my status from command line with colorization disabled" do
|
13
|
+
When "application is launched 'update' command" do
|
14
|
+
@output = launch_cli(%W{-a #{TEST_AUTH} --no-colors update '#{STATUS}'}, "y")
|
15
|
+
end
|
16
|
+
|
17
|
+
Then "the status sent is shown" do
|
18
|
+
@output[5].should == "#{TEST_USER}, 9 hours ago:"
|
19
|
+
@output[6].should == "#{STATUS}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Scenario "update my status from command line with colorization enabled" do
|
24
|
+
When "application is launched 'update' command" do
|
25
|
+
@output = launch_cli(%W{-a #{TEST_AUTH} --colors update '#{STATUS}'}, "y")
|
26
|
+
end
|
27
|
+
|
28
|
+
Then "the status sent is shown" do
|
29
|
+
@output[5].should == "\e[32m#{TEST_USER}\e[0m, 9 hours ago:"
|
30
|
+
@output[6].should == "#{STATUS}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Scenario "cancel a status from command line" do
|
35
|
+
When "application is launched 'update' command" do
|
36
|
+
@output = launch_cli(%W{-a #{TEST_AUTH} --colors update '#{STATUS}'}, "n")
|
37
|
+
end
|
38
|
+
|
39
|
+
Then "a cancellation message is shown" do
|
40
|
+
@output[3].should =~ /Cancelled./
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
Scenario "update my status from STDIN" do
|
45
|
+
When "application is launched 'update' command" do
|
46
|
+
@output = launch_cli(%W{-a #{TEST_AUTH} --no-colors update}, STATUS, "y")
|
47
|
+
end
|
48
|
+
|
49
|
+
Then "the status sent is shown" do
|
50
|
+
@output[0].should == "Status update: "
|
51
|
+
@output[5].should == "#{TEST_USER}, 9 hours ago:"
|
52
|
+
@output[6].should == "#{STATUS}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
Scenario "cancel a status update from STDIN" do
|
57
|
+
When "application is launched 'update' command" do
|
58
|
+
@output = launch_cli(%W{-a #{TEST_AUTH} --no-colors update}, STATUS, "n")
|
59
|
+
end
|
60
|
+
|
61
|
+
Then "a cancellation message is shown" do
|
62
|
+
@output[3].should =~ /Cancelled./
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,241 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
module Tweetwine
|
4
|
+
class CLI
|
5
|
+
EXIT_HELP = 1
|
6
|
+
EXIT_VERSION = 2
|
7
|
+
EXIT_ERROR = 255
|
8
|
+
|
9
|
+
def self.launch(args, exec_name, config_file, extra_opts = {})
|
10
|
+
new(args, exec_name, config_file, extra_opts, &default_dependencies).execute(args)
|
11
|
+
rescue ArgumentError, HttpError => e
|
12
|
+
puts "Error: #{e.message}"
|
13
|
+
exit(EXIT_ERROR)
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute(args)
|
17
|
+
if @config.command != :help
|
18
|
+
cmd_options = parse_command_options(@config.command, args)
|
19
|
+
@client.send(@config.command, args, cmd_options)
|
20
|
+
else
|
21
|
+
show_help_command_and_exit(args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def self.default_dependencies
|
28
|
+
lambda do |options|
|
29
|
+
io = Tweetwine::IO.new(options)
|
30
|
+
http_client = RetryingHttp::Client.new(io)
|
31
|
+
url_shortener = lambda { |opts| UrlShortener.new(http_client, opts) }
|
32
|
+
Client::Dependencies.new(io, http_client, url_shortener)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(args, exec_name, config_file, extra_opts = {}, &dependencies_blk)
|
37
|
+
@global_option_parser = create_global_option_parser(exec_name)
|
38
|
+
@config = StartupConfig.new(Client::COMMANDS + [:help], Client::DEFAULT_COMMAND, extra_opts)
|
39
|
+
@config.parse(args, config_file, &@global_option_parser)
|
40
|
+
@client = Client.new(dependencies_blk.call(@config.options), @config.options) if @config.command != :help
|
41
|
+
end
|
42
|
+
|
43
|
+
def show_help_command_and_exit(args)
|
44
|
+
help_about_cmd = args.shift
|
45
|
+
if help_about_cmd
|
46
|
+
help_about_cmd = help_about_cmd.to_sym
|
47
|
+
parse_command_options(help_about_cmd, ["-h"]) if Client::COMMANDS.include?(help_about_cmd)
|
48
|
+
end
|
49
|
+
@global_option_parser.call(["-h"])
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.create_option_parser
|
53
|
+
lambda do |args|
|
54
|
+
parsed_options = {}
|
55
|
+
begin
|
56
|
+
parser = OptionParser.new do |opt|
|
57
|
+
opt.on_tail("-h", "--help", "Show this help message and exit") {
|
58
|
+
puts opt
|
59
|
+
exit(EXIT_HELP)
|
60
|
+
}
|
61
|
+
schema = yield parsed_options
|
62
|
+
opt.banner = schema[:help]
|
63
|
+
schema[:opts].each do |opt_schema|
|
64
|
+
opt.on(*option_schema_to_ary(opt_schema), &opt_schema[:action])
|
65
|
+
end if schema[:opts]
|
66
|
+
end.order!(args)
|
67
|
+
rescue OptionParser::ParseError => e
|
68
|
+
raise ArgumentError, e.message
|
69
|
+
end
|
70
|
+
parsed_options
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.option_schema_to_ary(opt_schema)
|
75
|
+
[:short, :long, :type, :desc].inject([]) do |result, key|
|
76
|
+
result << opt_schema[key] if opt_schema[key]
|
77
|
+
result
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def create_global_option_parser(exec_name)
|
82
|
+
self.class.create_option_parser do |parsed|
|
83
|
+
{
|
84
|
+
:help => \
|
85
|
+
"A simple but tasty Twitter agent for command line use, made for fun.
|
86
|
+
|
87
|
+
Usage: #{exec_name} [global_options...] [command] [command_options...]
|
88
|
+
|
89
|
+
[command] is one of
|
90
|
+
* #{Client::COMMANDS[0...-1].join(",\n * ")}, or
|
91
|
+
* #{Client::COMMANDS.last}.
|
92
|
+
|
93
|
+
The default command is #{Client::DEFAULT_COMMAND}.
|
94
|
+
|
95
|
+
[global_options]:
|
96
|
+
",
|
97
|
+
:opts => [
|
98
|
+
{
|
99
|
+
:short => "-a",
|
100
|
+
:long => "--auth USERNAME:PASSWORD",
|
101
|
+
:desc => "Authentication",
|
102
|
+
:action => lambda { |arg| parsed[:username], parsed[:password] = arg.split(":", 2) }
|
103
|
+
},
|
104
|
+
{
|
105
|
+
:short => "-c",
|
106
|
+
:long => "--colors",
|
107
|
+
:desc => "Colorize output with ANSI escape codes",
|
108
|
+
:action => lambda { |arg| parsed[:colors] = true }
|
109
|
+
},
|
110
|
+
{
|
111
|
+
:short => "-n",
|
112
|
+
:long => "--num N",
|
113
|
+
:type => Integer,
|
114
|
+
:desc => "The number of statuses in page, default #{Client::DEFAULT_NUM_STATUSES}",
|
115
|
+
:action => lambda { |arg| parsed[:num_statuses] = arg }
|
116
|
+
},
|
117
|
+
{
|
118
|
+
:long => "--no-colors",
|
119
|
+
:desc => "Do not use ANSI colors",
|
120
|
+
:action => lambda { |arg| parsed[:colors] = false }
|
121
|
+
},
|
122
|
+
{
|
123
|
+
:long => "--no-url-shorten",
|
124
|
+
:desc => "Do not shorten URLs for status update",
|
125
|
+
:action => lambda { |arg| parsed[:shorten_urls] = { :enable => false } }
|
126
|
+
},
|
127
|
+
{
|
128
|
+
:short => "-p",
|
129
|
+
:long => "--page N",
|
130
|
+
:type => Integer,
|
131
|
+
:desc => "The page number for statuses, default #{Client::DEFAULT_PAGE_NUM}",
|
132
|
+
:action => lambda { |arg| parsed[:page_num] = arg }
|
133
|
+
},
|
134
|
+
{
|
135
|
+
:short => "-v",
|
136
|
+
:long => "--version",
|
137
|
+
:desc => "Show version information and exit",
|
138
|
+
:action => lambda do |arg|
|
139
|
+
puts "#{exec_name} #{Tweetwine::VERSION}"
|
140
|
+
exit(EXIT_VERSION)
|
141
|
+
end
|
142
|
+
}
|
143
|
+
]
|
144
|
+
}
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.create_command_option_parser(command_name, schema)
|
149
|
+
create_option_parser do |parsed|
|
150
|
+
{
|
151
|
+
:help => \
|
152
|
+
"#{command_name} [command_options...] #{schema[:help][:rest_args]}
|
153
|
+
|
154
|
+
#{schema[:help][:desc]}
|
155
|
+
|
156
|
+
[command_options]:
|
157
|
+
",
|
158
|
+
:opts => schema[:opts]
|
159
|
+
}
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
command_parser_schemas = {
|
164
|
+
:followers => {
|
165
|
+
:help => {
|
166
|
+
:desc => \
|
167
|
+
"Show the followers of the authenticated user, together with the latest status
|
168
|
+
of each follower."
|
169
|
+
}
|
170
|
+
},
|
171
|
+
:friends => {
|
172
|
+
:help => {
|
173
|
+
:desc => \
|
174
|
+
"Show the friends of the authenticated user, together with the latest status of
|
175
|
+
each friend."
|
176
|
+
}
|
177
|
+
},
|
178
|
+
:home => {
|
179
|
+
:help => {
|
180
|
+
:desc => \
|
181
|
+
"Show the latest statuses of friends and own tweets (the home timeline of the
|
182
|
+
authenticated user)."
|
183
|
+
}
|
184
|
+
},
|
185
|
+
:mentions => {
|
186
|
+
:help => {
|
187
|
+
:desc => \
|
188
|
+
"Show the latest statuses that mention the authenticated user."
|
189
|
+
}
|
190
|
+
},
|
191
|
+
:search => {
|
192
|
+
:help => {
|
193
|
+
:rest_args => "word_1 [word_2...]",
|
194
|
+
:desc => \
|
195
|
+
"Search the latest public statuses with one or more words."
|
196
|
+
},
|
197
|
+
:opts => [
|
198
|
+
{
|
199
|
+
:short => "-a",
|
200
|
+
:long => "--and",
|
201
|
+
:desc => "All words must match",
|
202
|
+
:action => lambda { |arg| parsed[:bin_op] = :and }
|
203
|
+
},
|
204
|
+
{
|
205
|
+
:short => "-o",
|
206
|
+
:long => "--or",
|
207
|
+
:desc => "Any word matches",
|
208
|
+
:action => lambda { |arg| parsed[:bin_op] = :or }
|
209
|
+
}
|
210
|
+
]
|
211
|
+
},
|
212
|
+
:update => {
|
213
|
+
:help => {
|
214
|
+
:rest_args => "[status]",
|
215
|
+
:desc => \
|
216
|
+
"Send a status update, but confirm the action first before actually sending.
|
217
|
+
The status update can either be given as an argument or via STDIN if no
|
218
|
+
[status] is given."
|
219
|
+
}
|
220
|
+
},
|
221
|
+
:user => {
|
222
|
+
:help => {
|
223
|
+
:rest_args => "[username]",
|
224
|
+
:desc => \
|
225
|
+
"Show a specific user's latest statuses. The user is identified with [username]
|
226
|
+
argument; if the argument is absent, the authenticated user's statuses are
|
227
|
+
shown."
|
228
|
+
}
|
229
|
+
}
|
230
|
+
}
|
231
|
+
|
232
|
+
COMMAND_OPTION_PARSERS = Client::COMMANDS.inject({}) do |result, cmd|
|
233
|
+
result[cmd] = create_command_option_parser(cmd, command_parser_schemas[cmd])
|
234
|
+
result
|
235
|
+
end
|
236
|
+
|
237
|
+
def parse_command_options(command, args)
|
238
|
+
COMMAND_OPTION_PARSERS[command].call(args)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
data/lib/tweetwine/client.rb
CHANGED
@@ -3,22 +3,23 @@ require "uri"
|
|
3
3
|
|
4
4
|
module Tweetwine
|
5
5
|
class Client
|
6
|
-
Dependencies = Struct.new :io, :
|
6
|
+
Dependencies = Struct.new :io, :http_client, :url_shortener
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
COMMANDS = [:home, :mentions, :user, :update, :friends, :followers]
|
8
|
+
COMMANDS = [:followers, :friends, :home, :mentions, :search, :update, :user]
|
9
|
+
DEFAULT_COMMAND = :home
|
11
10
|
|
12
11
|
DEFAULT_NUM_STATUSES = 20
|
13
12
|
DEFAULT_PAGE_NUM = 1
|
14
13
|
MAX_STATUS_LENGTH = 140
|
15
14
|
|
15
|
+
attr_reader :num_statuses, :page_num
|
16
|
+
|
16
17
|
def initialize(dependencies, options)
|
17
18
|
@io = dependencies.io
|
18
|
-
@rest_client = dependencies.rest_client
|
19
19
|
@username = options[:username].to_s
|
20
20
|
raise ArgumentError, "No authentication data given" if @username.empty?
|
21
|
-
@
|
21
|
+
@http_client = dependencies.http_client
|
22
|
+
@http_resource = @http_client.as_resource("https://twitter.com", :user => @username, :password => options[:password])
|
22
23
|
@num_statuses = Util.parse_int_gt(options[:num_statuses], DEFAULT_NUM_STATUSES, 1, "number of statuses_to_show")
|
23
24
|
@page_num = Util.parse_int_gt(options[:page_num], DEFAULT_PAGE_NUM, 1, "page number")
|
24
25
|
@url_shortener = if options[:shorten_urls] && options[:shorten_urls][:enable]
|
@@ -29,95 +30,131 @@ module Tweetwine
|
|
29
30
|
@status_update_factory = StatusUpdateFactory.new(@io, @url_shortener)
|
30
31
|
end
|
31
32
|
|
32
|
-
def home
|
33
|
-
|
33
|
+
def home(args = [], options = nil)
|
34
|
+
response = get_from_rest_api("statuses/home_timeline", :num_statuses, :page)
|
35
|
+
show_statuses_from_rest_api(*response)
|
34
36
|
end
|
35
37
|
|
36
|
-
def mentions
|
37
|
-
|
38
|
+
def mentions(args = [], options = nil)
|
39
|
+
response = get_from_rest_api("statuses/mentions", :num_statuses, :page)
|
40
|
+
show_statuses_from_rest_api(*response)
|
38
41
|
end
|
39
42
|
|
40
|
-
def user(
|
41
|
-
|
43
|
+
def user(args = [], options = nil)
|
44
|
+
user = if args.empty? then @username else args.first end
|
45
|
+
response = get_from_rest_api("statuses/user_timeline/#{user}", :num_statuses, :page)
|
46
|
+
show_statuses_from_rest_api(*response)
|
42
47
|
end
|
43
48
|
|
44
|
-
def update(
|
45
|
-
new_status =
|
49
|
+
def update(args = [], options = nil)
|
50
|
+
new_status = if args.empty? then nil else args.join(" ") end
|
51
|
+
new_status = @status_update_factory.create(new_status)
|
46
52
|
completed = false
|
47
53
|
unless new_status.empty?
|
48
54
|
@io.show_status_preview(new_status)
|
49
55
|
if @io.confirm("Really send?")
|
50
|
-
|
56
|
+
response = post_to_rest_api("statuses/update", :status => new_status.to_s)
|
51
57
|
@io.info "Sent status update.\n\n"
|
52
|
-
|
58
|
+
show_statuses_from_rest_api(response)
|
53
59
|
completed = true
|
54
60
|
end
|
55
61
|
end
|
56
62
|
@io.info "Cancelled." unless completed
|
57
63
|
end
|
58
64
|
|
59
|
-
def friends
|
60
|
-
|
65
|
+
def friends(args = [], options = nil)
|
66
|
+
response = get_from_rest_api("statuses/friends/#{@username}")
|
67
|
+
show_users_from_rest_api(*response)
|
68
|
+
end
|
69
|
+
|
70
|
+
def followers(args = [], options = nil)
|
71
|
+
response = get_from_rest_api("statuses/followers/#{@username}")
|
72
|
+
show_users_from_rest_api(*response)
|
61
73
|
end
|
62
74
|
|
63
|
-
def
|
64
|
-
|
75
|
+
def search(args = [], options = nil)
|
76
|
+
raise ArgumentError, "No search word" if args.empty?
|
77
|
+
query = if options && options[:bin_op] == :or then args.join(" OR ") else args.join(" ") end
|
78
|
+
response = get_from_search_api(query, :num_statuses, :page)
|
79
|
+
show_statuses_from_search_api(*response["results"])
|
65
80
|
end
|
66
81
|
|
67
82
|
private
|
68
83
|
|
69
|
-
def
|
70
|
-
|
71
|
-
|
84
|
+
def get_from_rest_api(sub_url, *query_opts)
|
85
|
+
query_str = query_options_to_string(query_opts, :page => "page", :num_statuses => "count")
|
86
|
+
url_suffix = unless query_str.empty? then "?" << query_str else "" end
|
87
|
+
JSON.parse(@http_resource[sub_url + ".json" + url_suffix].get)
|
72
88
|
end
|
73
89
|
|
74
|
-
def
|
75
|
-
|
90
|
+
def post_to_rest_api(sub_url, payload)
|
91
|
+
JSON.parse(@http_resource[sub_url + ".json"].post(payload))
|
92
|
+
end
|
93
|
+
|
94
|
+
def get_from_search_api(query, *query_opts)
|
95
|
+
query_str = "q=#{Util.percent_encode(query)}&" \
|
96
|
+
<< query_options_to_string(query_opts, :page => "page", :num_statuses => "rpp")
|
97
|
+
JSON.parse(@http_client.get("http://search.twitter.com/search.json?#{query_str}"))
|
98
|
+
end
|
99
|
+
|
100
|
+
def query_options_to_string(query_opts, key_mappings)
|
101
|
+
pairs = []
|
76
102
|
query_opts.each do |opt|
|
77
103
|
case opt
|
78
104
|
when :page
|
79
|
-
|
105
|
+
pairs << "#{key_mappings[:page]}=#{@page_num}"
|
80
106
|
when :num_statuses
|
81
|
-
|
82
|
-
#
|
107
|
+
pairs << "#{key_mappings[:num_statuses]}=#{@num_statuses}"
|
108
|
+
# else: ignore unknown query options
|
83
109
|
end
|
84
110
|
end
|
85
|
-
|
111
|
+
pairs.join("&")
|
86
112
|
end
|
87
113
|
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
user_data, status_data = yield entry
|
99
|
-
@io.show_record(parse_response(user_data, status_data))
|
100
|
-
end
|
114
|
+
def show_statuses_from_rest_api(*responses)
|
115
|
+
show_records(
|
116
|
+
responses,
|
117
|
+
{
|
118
|
+
:from_user => ["user", "screen_name"],
|
119
|
+
:to_user => "in_reply_to_screen_name",
|
120
|
+
:created_at => "created_at",
|
121
|
+
:status => "text"
|
122
|
+
}
|
123
|
+
)
|
101
124
|
end
|
102
125
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
:
|
108
|
-
:
|
109
|
-
:
|
126
|
+
def show_users_from_rest_api(*responses)
|
127
|
+
show_records(
|
128
|
+
responses,
|
129
|
+
{
|
130
|
+
:from_user => "screen_name",
|
131
|
+
:to_user => ["status", "in_reply_to_screen_name"],
|
132
|
+
:created_at => ["status", "created_at"],
|
133
|
+
:status => ["status", "text"]
|
110
134
|
}
|
111
|
-
|
112
|
-
record
|
135
|
+
)
|
113
136
|
end
|
114
137
|
|
115
|
-
def
|
116
|
-
|
138
|
+
def show_statuses_from_search_api(*responses)
|
139
|
+
show_records(
|
140
|
+
responses,
|
141
|
+
{
|
142
|
+
:from_user => "from_user",
|
143
|
+
:to_user => "to_user",
|
144
|
+
:created_at => "created_at",
|
145
|
+
:status => "text"
|
146
|
+
}
|
147
|
+
)
|
117
148
|
end
|
118
149
|
|
119
|
-
def
|
120
|
-
|
150
|
+
def show_records(twitter_records, paths)
|
151
|
+
twitter_records.each do |twitter_record|
|
152
|
+
internal_record = [ :from_user, :to_user, :created_at, :status ].inject({}) do |result, key|
|
153
|
+
result[key] = Util.find_hash_path(twitter_record, paths[key])
|
154
|
+
result
|
155
|
+
end
|
156
|
+
@io.show_record(internal_record)
|
157
|
+
end
|
121
158
|
end
|
122
159
|
|
123
160
|
class StatusUpdateFactory
|
@@ -126,7 +163,7 @@ module Tweetwine
|
|
126
163
|
@url_shortener = url_shortener
|
127
164
|
end
|
128
165
|
|
129
|
-
def
|
166
|
+
def create(status)
|
130
167
|
StatusUpdate.new(status, @io, @url_shortener).to_s
|
131
168
|
end
|
132
169
|
end
|
@@ -168,7 +205,7 @@ module Tweetwine
|
|
168
205
|
url_pairs.reject { |pair| pair.last.nil? || pair.last.empty? }.each do |url_pair|
|
169
206
|
status.gsub!(url_pair.first, url_pair.last)
|
170
207
|
end
|
171
|
-
rescue
|
208
|
+
rescue HttpError, LoadError => e
|
172
209
|
@io.warn "#{e}. Skipping URL shortening..."
|
173
210
|
end
|
174
211
|
end
|