tweetwine 0.2.5 → 0.2.7
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/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
|