tweetwine 0.2.12 → 0.3.0
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 +7 -0
- data/Gemfile +17 -0
- data/README.md +57 -47
- data/Rakefile +17 -26
- data/bin/tweetwine +11 -12
- data/contrib/tweetwine-completion.bash +2 -3
- data/example/application_behavior_example.rb +173 -0
- data/example/example_helper.rb +44 -28
- data/example/fixture/config.yaml +8 -0
- data/example/fixture/shorten_rubygems.html +5 -0
- data/example/fixture/shorten_rubylang.html +5 -0
- data/example/fixture/update_utf8.json +1 -0
- data/example/fixture/update_with_urls.json +1 -0
- data/example/fixture/{update.json → update_without_urls.json} +0 -0
- data/example/search_statuses_example.rb +49 -16
- data/example/show_followers_example.rb +7 -8
- data/example/show_friends_example.rb +7 -8
- data/example/show_home_example.rb +19 -16
- data/example/show_mentions_example.rb +8 -9
- data/example/show_user_example.rb +16 -13
- data/example/update_status_example.rb +143 -26
- data/example/use_http_proxy_example.rb +40 -20
- data/lib/tweetwine/basic_object.rb +19 -0
- data/lib/tweetwine/character_encoding.rb +59 -0
- data/lib/tweetwine/cli.rb +354 -230
- data/lib/tweetwine/config.rb +65 -0
- data/lib/tweetwine/http.rb +120 -0
- data/lib/tweetwine/oauth.rb +104 -0
- data/lib/tweetwine/obfuscate.rb +21 -0
- data/lib/tweetwine/option_parser.rb +31 -0
- data/lib/tweetwine/promise.rb +39 -0
- data/lib/tweetwine/twitter.rb +211 -0
- data/lib/tweetwine/{io.rb → ui.rb} +30 -21
- data/lib/tweetwine/url_shortener.rb +15 -9
- data/lib/tweetwine/util.rb +30 -15
- data/lib/tweetwine.rb +72 -12
- data/man/tweetwine.7 +43 -69
- data/man/tweetwine.7.ronn +57 -47
- data/test/character_encoding_test.rb +87 -0
- data/test/cli_test.rb +19 -6
- data/test/config_test.rb +244 -0
- data/test/fixture/oauth.rb +21 -0
- data/test/fixture/test_config.yaml +4 -4
- data/test/http_test.rb +199 -0
- data/test/oauth_test.rb +77 -0
- data/test/obfuscate_test.rb +16 -0
- data/test/option_parser_test.rb +60 -0
- data/test/promise_test.rb +56 -0
- data/test/test_helper.rb +76 -8
- data/test/twitter_test.rb +625 -0
- data/test/{io_test.rb → ui_test.rb} +92 -74
- data/test/url_shortener_test.rb +115 -135
- data/test/util_test.rb +136 -85
- data/tweetwine.gemspec +53 -0
- metadata +112 -56
- data/example/show_metadata_example.rb +0 -86
- data/lib/tweetwine/client.rb +0 -187
- data/lib/tweetwine/meta.rb +0 -5
- data/lib/tweetwine/options.rb +0 -24
- data/lib/tweetwine/retrying_http.rb +0 -99
- data/lib/tweetwine/startup_config.rb +0 -50
- data/man/tweetwine.1 +0 -109
- data/man/tweetwine.1.ronn +0 -69
- data/test/client_test.rb +0 -544
- data/test/options_test.rb +0 -45
- data/test/retrying_http_test.rb +0 -147
- data/test/startup_config_test.rb +0 -162
@@ -0,0 +1,59 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Tweetwine
|
4
|
+
class CharacterEncoding
|
5
|
+
class << self
|
6
|
+
if "".respond_to?(:encode)
|
7
|
+
def to_utf8(str)
|
8
|
+
result = str.encode('UTF-8')
|
9
|
+
raise TranscodeError, "invalid UTF-8 byte sequence when transcoding '#{str}'" unless result.valid_encoding?
|
10
|
+
result
|
11
|
+
end
|
12
|
+
else
|
13
|
+
def to_utf8(str)
|
14
|
+
if guess_external_encoding != 'UTF-8'
|
15
|
+
begin
|
16
|
+
require "iconv"
|
17
|
+
Iconv.conv('UTF-8//TRANSLIT', guess_external_encoding, str)
|
18
|
+
rescue => e
|
19
|
+
raise TranscodeError, e
|
20
|
+
end
|
21
|
+
else
|
22
|
+
str
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def forget_guess
|
28
|
+
@guess_external_encoding = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def guess_external_encoding
|
34
|
+
@guess_external_encoding ||= begin
|
35
|
+
guess = guess_external_encoding_from_kcode || guess_external_encoding_from_env_lang
|
36
|
+
raise TranscodeError, "could not determine your external encoding" unless guess
|
37
|
+
guess
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def guess_external_encoding_from_kcode
|
42
|
+
guess = nil
|
43
|
+
guess = case $KCODE
|
44
|
+
when 'EUC' then 'EUC-JP'
|
45
|
+
when 'SJIS' then 'SHIFT-JIS'
|
46
|
+
when 'UTF8' then 'UTF-8'
|
47
|
+
else nil
|
48
|
+
end if defined?($KCODE)
|
49
|
+
guess
|
50
|
+
end
|
51
|
+
|
52
|
+
def guess_external_encoding_from_env_lang
|
53
|
+
lang = ENV['LANG']
|
54
|
+
return 'UTF-8' if lang =~ /(utf-8|utf8)\z/i
|
55
|
+
Util.blank?(lang) ? nil : lang
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/tweetwine/cli.rb
CHANGED
@@ -1,254 +1,378 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
require "optparse"
|
4
|
-
|
5
3
|
module Tweetwine
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
4
|
+
module CLI
|
5
|
+
DEFAULT_COMMAND = :home
|
6
|
+
DEFAULT_CONFIG = {
|
7
|
+
:colors => :false,
|
8
|
+
:config_file => "#{(ENV['HOME'] || ENV['USERPROFILE'])}/.tweetwine",
|
9
|
+
:env_lookouts => [:http_proxy],
|
10
|
+
:excludes => [:command],
|
11
|
+
:shorten_urls => {:disable => true},
|
12
|
+
:username => ENV['USER']
|
13
|
+
}.freeze
|
14
|
+
EXEC_NAME = 'tweetwine'
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def start(args = ARGV, overriding_default_conf = nil)
|
18
|
+
init(args, overriding_default_conf)
|
19
|
+
run(args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def config
|
23
|
+
@config ||= read_config
|
24
|
+
end
|
25
|
+
|
26
|
+
def http
|
27
|
+
@http ||= Http::Client.new(config)
|
28
|
+
end
|
29
|
+
|
30
|
+
def oauth
|
31
|
+
@oauth ||= OAuth.new(config[:oauth_access])
|
32
|
+
end
|
33
|
+
|
34
|
+
def twitter
|
35
|
+
@twitter ||= Twitter.new(config)
|
36
|
+
end
|
37
|
+
|
38
|
+
def ui
|
39
|
+
@ui ||= UI.new(config)
|
40
|
+
end
|
41
|
+
|
42
|
+
def url_shortener
|
43
|
+
@url_shorterer ||= UrlShortener.new(config[:shorten_urls])
|
44
|
+
end
|
45
|
+
|
46
|
+
def commands
|
47
|
+
@commands ||= {
|
48
|
+
:primaries => {},
|
49
|
+
:secondaries => {}
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def register_command(cmd_class, names)
|
54
|
+
commands[:primaries][names.first.to_sym] = cmd_class
|
55
|
+
names[1..-1].each { |name| commands[:secondaries][name.to_sym] = cmd_class }
|
56
|
+
end
|
57
|
+
|
58
|
+
def find_command(name)
|
59
|
+
name = name.to_sym
|
60
|
+
commands[:primaries][name] || commands[:secondaries][name]
|
61
|
+
end
|
62
|
+
|
63
|
+
def global_option_parser
|
64
|
+
@global_option_parser ||= OptionParser.new do |parser, options|
|
65
|
+
parser.on '-c', '--colors', 'Enable ANSI colors for output.' do
|
66
|
+
options[:colors] = true
|
67
|
+
end
|
68
|
+
parser.on '-f', '--config <file>', String, "Configuration file (default #{DEFAULT_CONFIG[:config_file]})." do |arg|
|
69
|
+
options[:config_file] = arg
|
70
|
+
end
|
71
|
+
parser.on '-h', '--help', 'Show this help and exit.' do
|
72
|
+
options[:command] = :help
|
73
|
+
end
|
74
|
+
parser.on '--http-proxy <url>', String, 'Enable HTTP(S) proxy.' do |arg|
|
75
|
+
options[:http_proxy] = arg
|
76
|
+
end
|
77
|
+
parser.on '--no-colors', 'Disable ANSI colors for output.' do
|
78
|
+
options[:colors] = false
|
79
|
+
end
|
80
|
+
parser.on '--no-http-proxy', 'Disable HTTP(S) proxy.' do
|
81
|
+
options[:http_proxy] = nil
|
82
|
+
end
|
83
|
+
parser.on '--no-url-shorten', 'Disable URL shortening.' do
|
84
|
+
options[:shorten_urls] ||= {}
|
85
|
+
options[:shorten_urls][:disable] = true
|
86
|
+
end
|
87
|
+
parser.on '-n', '--num <n>', Integer, "Number of statuses per page (default #{Twitter::DEFAULT_NUM_STATUSES})." do |arg|
|
88
|
+
options[:num_statuses] = arg
|
89
|
+
end
|
90
|
+
parser.on '-p', '--page <p>', Integer, "Page number for statuses (default #{Twitter::DEFAULT_PAGE_NUM})." do |arg|
|
91
|
+
options[:page] = arg
|
92
|
+
end
|
93
|
+
parser.on '-u', '--username <user>', String, "User to authenticate (default '#{DEFAULT_CONFIG[:username]}')." do |arg|
|
94
|
+
options[:username] = arg
|
95
|
+
end
|
96
|
+
parser.on '-v', '--version', "Show version and exit." do
|
97
|
+
options[:command] = :version
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def init(args, overriding_default_conf = nil)
|
105
|
+
@config, @http, @oauth, @twitter, @ui, @url_shortener = nil # reset
|
106
|
+
@config = read_config(args, overriding_default_conf)
|
107
|
+
end
|
108
|
+
|
109
|
+
def run(args)
|
110
|
+
proposed_command = config[:command]
|
111
|
+
found_command = find_command proposed_command
|
112
|
+
raise UnknownCommandError, "unknown command: #{proposed_command}" unless found_command
|
113
|
+
found_command.new(args).run
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
117
|
+
def read_config(cmdline_args = [], overriding_default_config = nil)
|
118
|
+
default_config = overriding_default_config ? DEFAULT_CONFIG.merge(overriding_default_config) : DEFAULT_CONFIG
|
119
|
+
config = Config.read(cmdline_args, default_config) do |args|
|
120
|
+
parse_config_from_cmdline(args)
|
121
|
+
end
|
122
|
+
config
|
123
|
+
end
|
124
|
+
|
125
|
+
def parse_config_from_cmdline(args)
|
126
|
+
options = global_option_parser.parse(args)
|
127
|
+
unless options[:command]
|
128
|
+
cmd_via_arg = args.shift
|
129
|
+
options[:command] = cmd_via_arg ? cmd_via_arg.to_sym : DEFAULT_COMMAND
|
130
|
+
end
|
131
|
+
options
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
class Command
|
137
|
+
class << self
|
138
|
+
def inherited(child)
|
139
|
+
# Silence warnings about uninitialized variables if a child does not
|
140
|
+
# set its about, name, or usage.
|
141
|
+
child.instance_eval do
|
142
|
+
@about, @name, @usage = nil
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def about(description = nil)
|
147
|
+
return @about unless description
|
148
|
+
@about = description.chomp
|
149
|
+
end
|
150
|
+
|
151
|
+
def register(*names)
|
152
|
+
@name = names.first
|
153
|
+
CLI.register_command(self, names)
|
154
|
+
end
|
155
|
+
|
156
|
+
def name
|
157
|
+
@name
|
158
|
+
end
|
159
|
+
|
160
|
+
# Usage description for the command, use if overriding #parse.
|
161
|
+
def usage(description = nil)
|
162
|
+
return @usage unless description
|
163
|
+
@usage = description
|
164
|
+
end
|
165
|
+
|
166
|
+
def show_usage(about_cmd = self)
|
167
|
+
about = about_cmd.about
|
168
|
+
name = about_cmd.name
|
169
|
+
usage = about_cmd.usage
|
170
|
+
result = <<-END
|
171
|
+
#{about}
|
172
|
+
|
173
|
+
Usage: #{CLI::EXEC_NAME} #{name} #{usage}
|
174
|
+
END
|
175
|
+
CLI.ui.info result.strip!
|
176
|
+
end
|
177
|
+
|
178
|
+
def abort_with_usage
|
179
|
+
show_usage
|
180
|
+
exit CommandLineError.status_code
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def initialize(args)
|
185
|
+
parsing_succeeded = parse(args)
|
186
|
+
self.class.abort_with_usage unless parsing_succeeded
|
187
|
+
end
|
188
|
+
|
189
|
+
# Default behavior, which succeeds always; override for real argument
|
190
|
+
# parsing if the command needs arguments.
|
191
|
+
def parse(args)
|
192
|
+
true
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
class HelpCommand < Command
|
197
|
+
register "help"
|
198
|
+
about "Show help and exit. Try it with <command> argument."
|
199
|
+
usage <<-END
|
200
|
+
[<command>]
|
201
|
+
|
202
|
+
If <command> is given, show specific help about that command. If no
|
203
|
+
<command> is given, show general help.
|
204
|
+
END
|
205
|
+
|
206
|
+
def parse(args)
|
207
|
+
# Did we arrive here via '-h' option? If so, we cannot have
|
208
|
+
# +proposed_command+ because '-h' does not take an argument. Otherwise,
|
209
|
+
# try to read the argument.
|
210
|
+
proposed_command = args.include?('-h') ? nil : args.shift
|
211
|
+
if proposed_command
|
212
|
+
@command = CLI.find_command proposed_command
|
213
|
+
CLI.ui.error "unknown command: #{proposed_command}\n\n" unless @command
|
214
|
+
@command
|
215
|
+
else
|
216
|
+
@command = nil
|
217
|
+
true
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def run
|
222
|
+
if @command
|
223
|
+
show_command_help
|
22
224
|
else
|
23
|
-
|
225
|
+
show_general_help
|
24
226
|
end
|
25
227
|
end
|
26
228
|
|
27
229
|
private
|
28
230
|
|
29
|
-
def
|
30
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
231
|
+
def show_command_help
|
232
|
+
self.class.show_usage @command
|
233
|
+
end
|
234
|
+
|
235
|
+
def show_general_help
|
236
|
+
command_descriptions = CLI.commands[:primaries].
|
237
|
+
entries.
|
238
|
+
sort { |a, b| a.first.to_s <=> b.first.to_s }.
|
239
|
+
map { |cmd, klass| [cmd, klass.about] }
|
240
|
+
CLI.ui.info <<-END
|
241
|
+
A simple but tasty Twitter agent for command line use, made for fun.
|
242
|
+
|
243
|
+
Usage: #{CLI::EXEC_NAME} [global_options...] [<command>] [command_options...]
|
244
|
+
|
245
|
+
Global options:
|
246
|
+
|
247
|
+
#{CLI.global_option_parser.help}
|
248
|
+
|
249
|
+
Commands:
|
250
|
+
|
251
|
+
#{command_descriptions.map { |cmd, desc| " %-14s%s" % [cmd, desc] }.join("\n") }
|
252
|
+
END
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
class HomeCommand < Command
|
257
|
+
register "home", "h"
|
258
|
+
about "Show authenticated user's home timeline (the default command)."
|
259
|
+
|
260
|
+
def run
|
261
|
+
CLI.twitter.home
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
class FollowersCommand < Command
|
266
|
+
register "followers", "fo"
|
267
|
+
about "Show authenticated user's followers and their latest tweets."
|
268
|
+
|
269
|
+
def run
|
270
|
+
CLI.twitter.followers
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
class FriendsCommand < Command
|
275
|
+
register "friends", "fr"
|
276
|
+
about "Show authenticated user's friends and their latest tweets."
|
277
|
+
|
278
|
+
def run
|
279
|
+
CLI.twitter.friends
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
class MentionsCommand < Command
|
284
|
+
register "mentions", "men", "m"
|
285
|
+
about "Show latest tweets that mention or are replies to the authenticated user."
|
286
|
+
|
287
|
+
def run
|
288
|
+
CLI.twitter.mentions
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
class SearchCommand < Command
|
293
|
+
def self.parser
|
294
|
+
@parser ||= OptionParser.new do |parser, options|
|
295
|
+
parser.on '-a', '--and', 'All words match (default).' do
|
296
|
+
options[:operator] = :and
|
297
|
+
end
|
298
|
+
parser.on '-o', '--or', 'Any word matches.' do
|
299
|
+
options[:operator] = :or
|
71
300
|
end
|
72
|
-
parsed_options
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def self.option_schema_to_ary(opt_schema)
|
77
|
-
[:short, :long, :type, :desc].inject([]) do |result, key|
|
78
|
-
result << opt_schema[key] if opt_schema[key]
|
79
|
-
result
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def create_global_option_parser(exec_name)
|
84
|
-
self.class.create_option_parser do |parsed|
|
85
|
-
{
|
86
|
-
:help => \
|
87
|
-
"A simple but tasty Twitter agent for command line use, made for fun.
|
88
|
-
|
89
|
-
Usage: #{exec_name} [global_options...] [command] [command_options...]
|
90
|
-
|
91
|
-
[command] is one of
|
92
|
-
* #{Client::COMMANDS[0...-1].join(",\n * ")}, or
|
93
|
-
* #{Client::COMMANDS.last}.
|
94
|
-
|
95
|
-
The default command is #{Client::DEFAULT_COMMAND}.
|
96
|
-
|
97
|
-
[global_options]:
|
98
|
-
",
|
99
|
-
:opts => [
|
100
|
-
{
|
101
|
-
:short => "-a",
|
102
|
-
:long => "--auth USERNAME:PASSWORD",
|
103
|
-
:desc => "Authentication",
|
104
|
-
:action => lambda { |arg| parsed[:username], parsed[:password] = arg.split(":", 2) }
|
105
|
-
},
|
106
|
-
{
|
107
|
-
:short => "-c",
|
108
|
-
:long => "--colors",
|
109
|
-
:desc => "Colorize output with ANSI escape codes",
|
110
|
-
:action => lambda { |arg| parsed[:colors] = true }
|
111
|
-
},
|
112
|
-
{
|
113
|
-
:short => "-n",
|
114
|
-
:long => "--num N",
|
115
|
-
:type => Integer,
|
116
|
-
:desc => "The number of statuses in page, default #{Client::DEFAULT_NUM_STATUSES}",
|
117
|
-
:action => lambda { |arg| parsed[:num_statuses] = arg }
|
118
|
-
},
|
119
|
-
{
|
120
|
-
:long => "--no-colors",
|
121
|
-
:desc => "Do not use ANSI colors",
|
122
|
-
:action => lambda { |arg| parsed[:colors] = false }
|
123
|
-
},
|
124
|
-
{
|
125
|
-
:long => "--no-http-proxy",
|
126
|
-
:desc => "Do not use proxy for HTTP and HTTPS",
|
127
|
-
:action => lambda { |arg| parsed[:http_proxy] = nil }
|
128
|
-
},
|
129
|
-
{
|
130
|
-
:long => "--no-url-shorten",
|
131
|
-
:desc => "Do not shorten URLs for status update",
|
132
|
-
:action => lambda { |arg| parsed[:shorten_urls] = { :enable => false } }
|
133
|
-
},
|
134
|
-
{
|
135
|
-
:short => "-p",
|
136
|
-
:long => "--page N",
|
137
|
-
:type => Integer,
|
138
|
-
:desc => "The page number for statuses, default #{Client::DEFAULT_PAGE_NUM}",
|
139
|
-
:action => lambda { |arg| parsed[:page_num] = arg }
|
140
|
-
},
|
141
|
-
{
|
142
|
-
:long => "--http-proxy URL",
|
143
|
-
:type => String,
|
144
|
-
:desc => "Use proxy for HTTP and HTTPS",
|
145
|
-
:action => lambda { |arg| parsed[:http_proxy] = arg }
|
146
|
-
},
|
147
|
-
{
|
148
|
-
:short => "-v",
|
149
|
-
:long => "--version",
|
150
|
-
:desc => "Show version information and exit",
|
151
|
-
:action => lambda do |arg|
|
152
|
-
puts "#{exec_name} #{Tweetwine::VERSION}"
|
153
|
-
exit(EXIT_VERSION)
|
154
|
-
end
|
155
|
-
}
|
156
|
-
]
|
157
|
-
}
|
158
301
|
end
|
159
302
|
end
|
160
303
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
"#{command_name} [command_options...] #{schema[:help][:rest_args]}
|
304
|
+
register "search", "s"
|
305
|
+
about "Search latest public tweets."
|
306
|
+
usage(Promise.new {<<-END
|
307
|
+
[--all | --or] <word>...
|
166
308
|
|
167
|
-
|
309
|
+
Command options:
|
168
310
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
311
|
+
#{parser.help}
|
312
|
+
END
|
313
|
+
})
|
314
|
+
|
315
|
+
def parse(args)
|
316
|
+
options = self.class.parser.parse(args)
|
317
|
+
@operator = options[:operator]
|
318
|
+
@words = args
|
319
|
+
if @words.empty?
|
320
|
+
CLI.ui.error "No search words.\n\n"
|
321
|
+
false
|
322
|
+
else
|
323
|
+
true
|
173
324
|
end
|
174
325
|
end
|
175
326
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
:rest_args => "word_1 [word_2...]",
|
207
|
-
:desc => \
|
208
|
-
"Search the latest public statuses with one or more words."
|
209
|
-
},
|
210
|
-
:opts => [
|
211
|
-
{
|
212
|
-
:short => "-a",
|
213
|
-
:long => "--and",
|
214
|
-
:desc => "All words must match",
|
215
|
-
:action => lambda { |arg| parsed[:bin_op] = :and }
|
216
|
-
},
|
217
|
-
{
|
218
|
-
:short => "-o",
|
219
|
-
:long => "--or",
|
220
|
-
:desc => "Any word matches",
|
221
|
-
:action => lambda { |arg| parsed[:bin_op] = :or }
|
222
|
-
}
|
223
|
-
]
|
224
|
-
},
|
225
|
-
:update => {
|
226
|
-
:help => {
|
227
|
-
:rest_args => "[status]",
|
228
|
-
:desc => \
|
229
|
-
"Send a status update, but confirm the action first before actually sending.
|
230
|
-
The status update can either be given as an argument or via STDIN if no
|
231
|
-
[status] is given."
|
232
|
-
}
|
233
|
-
},
|
234
|
-
:user => {
|
235
|
-
:help => {
|
236
|
-
:rest_args => "[username]",
|
237
|
-
:desc => \
|
238
|
-
"Show a specific user's latest statuses. The user is identified with [username]
|
239
|
-
argument; if the argument is absent, the authenticated user's statuses are
|
240
|
-
shown."
|
241
|
-
}
|
242
|
-
}
|
243
|
-
}
|
327
|
+
def run
|
328
|
+
CLI.twitter.search @words, @operator
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
class UpdateCommand < Command
|
333
|
+
register "update", "up"
|
334
|
+
about "Send new tweet."
|
335
|
+
usage <<-END
|
336
|
+
[<status>]
|
337
|
+
|
338
|
+
If <status> is not given, read the contents for the tweet from STDIN.
|
339
|
+
END
|
340
|
+
|
341
|
+
def parse(args)
|
342
|
+
@msg = args.join(' ')
|
343
|
+
args.clear
|
344
|
+
true
|
345
|
+
end
|
346
|
+
|
347
|
+
def run
|
348
|
+
CLI.twitter.update @msg
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
class UserCommand < Command
|
353
|
+
register "user", "usr"
|
354
|
+
about "Show user's timeline."
|
355
|
+
usage <<-END
|
356
|
+
[<username>]
|
244
357
|
|
245
|
-
|
246
|
-
|
247
|
-
|
358
|
+
If <username> is not given, show authenticated user's timeline.
|
359
|
+
END
|
360
|
+
|
361
|
+
def parse(args)
|
362
|
+
@user = args.empty? ? CLI.config[:username] : args.shift
|
248
363
|
end
|
249
364
|
|
250
|
-
def
|
251
|
-
|
365
|
+
def run
|
366
|
+
CLI.twitter.user(@user)
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
class VersionCommand < Command
|
371
|
+
register "version", "ver", "v"
|
372
|
+
about "Show program version and exit."
|
373
|
+
|
374
|
+
def run
|
375
|
+
CLI.ui.info "tweetwine #{Tweetwine::VERSION}"
|
252
376
|
end
|
253
377
|
end
|
254
378
|
end
|