visionmedia-commander 3.1.8 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +13 -0
- data/README.rdoc +27 -0
- data/bin/commander +0 -1
- data/commander.gemspec +2 -2
- data/lib/commander/command.rb +9 -31
- data/lib/commander/help_formatters/terminal/help.erb +6 -4
- data/lib/commander/runner.rb +77 -21
- data/lib/commander/version.rb +1 -1
- data/spec/command_spec.rb +0 -19
- data/spec/runner_spec.rb +49 -7
- metadata +2 -2
data/History.rdoc
CHANGED
@@ -1,4 +1,17 @@
|
|
1
1
|
|
2
|
+
=== 3.2.0 / 2009-03-26
|
3
|
+
|
4
|
+
* Added implied small switches so they appear in help (-h, -v, etc)
|
5
|
+
* Added #inspect back to Commander::Command::Options [#1]
|
6
|
+
* Added inheritance of global options for sub-commands [#7]
|
7
|
+
* Added #require_valid_command
|
8
|
+
* Renamed #call_active_command to #run_active_command
|
9
|
+
* Changed; using same option format as sub-command options for globals [#18]
|
10
|
+
* Changed; program :name is now optional, and is auto-defined when not specified [#21]
|
11
|
+
* Moved #switch_to_sym from Command to Commander::Runner
|
12
|
+
* Moved #seperate_switches_from_description into Commander::Runner [#22]
|
13
|
+
* Removed program :name from commander init template since its not required anymore
|
14
|
+
|
2
15
|
=== 3.1.8 / 2009-03-25
|
3
16
|
|
4
17
|
* Utilizing abort and $stderr instead of using #say [#16]
|
data/README.rdoc
CHANGED
@@ -27,6 +27,7 @@ as well as an object, specifying a method to call, so view the RDoc for more inf
|
|
27
27
|
require 'rubygems'
|
28
28
|
require 'commander'
|
29
29
|
|
30
|
+
# :name is optional, otherwise uses the basename of this executable
|
30
31
|
program :name, 'Foo Bar'
|
31
32
|
program :version, '1.0.0'
|
32
33
|
program :description, 'Stupid command that prints foo or bar.'
|
@@ -221,6 +222,32 @@ you can add additional global options:
|
|
221
222
|
|
222
223
|
This method accepts the same syntax as Commander::Command#option so check it out for documentation.
|
223
224
|
|
225
|
+
All global options regardless of providing a block are accessable at the sub-command level. This
|
226
|
+
means that instead of the following:
|
227
|
+
|
228
|
+
global_option('--verbose') { $verbose = true }
|
229
|
+
...
|
230
|
+
c.when_called do |args, options|
|
231
|
+
say 'foo' if $verbose
|
232
|
+
...
|
233
|
+
|
234
|
+
You may:
|
235
|
+
|
236
|
+
global_option '--verbose'
|
237
|
+
...
|
238
|
+
c.when_called do |args, options|
|
239
|
+
say 'foo' if options.verbose
|
240
|
+
...
|
241
|
+
|
242
|
+
== Tips
|
243
|
+
|
244
|
+
When adding a global or sub-command option, OptionParser implicitly adds a small
|
245
|
+
switch even when not explicitly created, for example -c will be the same as --config
|
246
|
+
in both examples:
|
247
|
+
|
248
|
+
global_option '-c', '--config FILE'
|
249
|
+
global_option '--config FILE'
|
250
|
+
|
224
251
|
== ASCII Tables
|
225
252
|
|
226
253
|
For feature rich ASCII tables for your terminal app check out visionmedia's terminal-table gem at
|
data/bin/commander
CHANGED
data/commander.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{commander}
|
5
|
-
s.version = "3.
|
5
|
+
s.version = "3.2.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["TJ Holowaychuk"]
|
9
|
-
s.date = %q{2009-03-
|
9
|
+
s.date = %q{2009-03-26}
|
10
10
|
s.default_executable = %q{commander}
|
11
11
|
s.description = %q{The complete solution for Ruby command-line executables}
|
12
12
|
s.email = %q{tj@vision-media.ca}
|
data/lib/commander/command.rb
CHANGED
@@ -4,8 +4,8 @@ require 'optparse'
|
|
4
4
|
module Commander
|
5
5
|
class Command
|
6
6
|
|
7
|
-
|
8
|
-
attr_accessor :
|
7
|
+
attr_accessor :name, :examples, :syntax, :description
|
8
|
+
attr_accessor :summary, :proxy_options, :options
|
9
9
|
|
10
10
|
##
|
11
11
|
# Options struct.
|
@@ -28,6 +28,10 @@ module Commander
|
|
28
28
|
def default defaults = {}
|
29
29
|
@table = defaults.merge! @table
|
30
30
|
end
|
31
|
+
|
32
|
+
def inspect
|
33
|
+
"<Commander::Command::Options #{ __hash__.map { |k,v| "#{k}=#{v.inspect}" }.join(', ') }>"
|
34
|
+
end
|
31
35
|
end
|
32
36
|
|
33
37
|
##
|
@@ -103,7 +107,7 @@ module Commander
|
|
103
107
|
#
|
104
108
|
|
105
109
|
def option *args, &block
|
106
|
-
switches, description = seperate_switches_from_description *args
|
110
|
+
switches, description = Runner.seperate_switches_from_description *args
|
107
111
|
proc = block || option_proc(switches)
|
108
112
|
@options << {
|
109
113
|
:args => args,
|
@@ -176,36 +180,12 @@ module Commander
|
|
176
180
|
end
|
177
181
|
end
|
178
182
|
|
179
|
-
##
|
180
|
-
# Attempts to generate a method name symbol from +switch+.
|
181
|
-
# For example:
|
182
|
-
#
|
183
|
-
# -h # => :h
|
184
|
-
# --trace # => :trace
|
185
|
-
# --some-switch # => :some_switch
|
186
|
-
# --[no-]feature # => :feature
|
187
|
-
# --file FILE # => :file
|
188
|
-
# --list of,things # => :list
|
189
|
-
|
190
|
-
def switch_to_sym switch
|
191
|
-
switch.scan(/[\-\]](\w+)/).join('_').to_sym rescue nil
|
192
|
-
end
|
193
|
-
|
194
|
-
##
|
195
|
-
# Return switches and description seperated from the +args+ passed.
|
196
|
-
|
197
|
-
def seperate_switches_from_description *args
|
198
|
-
switches = args.find_all { |arg| arg.to_s =~ /^-/ }
|
199
|
-
description = args.last unless !args.last.is_a? String or args.last.match(/^-/)
|
200
|
-
return switches, description
|
201
|
-
end
|
202
|
-
|
203
183
|
##
|
204
184
|
# Creates an Options instance populated with the option values
|
205
185
|
# collected by the #option_proc.
|
206
186
|
|
207
187
|
def proxy_option_struct
|
208
|
-
|
188
|
+
proxy_options.inject Options.new do |options, (option, value)|
|
209
189
|
options.__send__ :"#{option}=", value
|
210
190
|
options
|
211
191
|
end
|
@@ -217,9 +197,7 @@ module Commander
|
|
217
197
|
# and work with option values.
|
218
198
|
|
219
199
|
def option_proc switches
|
220
|
-
|
221
|
-
@proxy_options << [switch_to_sym(switches.last), value]
|
222
|
-
end
|
200
|
+
lambda { |value| proxy_options << [Runner.switch_to_sym(switches.last), value] }
|
223
201
|
end
|
224
202
|
|
225
203
|
def inspect #:nodoc:
|
@@ -21,10 +21,12 @@
|
|
21
21
|
<% end %>
|
22
22
|
<% unless @options.empty? -%>
|
23
23
|
<%= $terminal.color "GLOBAL OPTIONS", :bold %>:
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
<% @options.each do |option| -%>
|
25
|
+
|
26
|
+
<%= option[:switches].join ', ' %>
|
27
|
+
<%= option[:description] %>
|
28
|
+
<% end -%>
|
29
|
+
<% end -%>
|
28
30
|
<% if program :help -%>
|
29
31
|
<% program(:help).each_pair do |title, body| %>
|
30
32
|
<%= $terminal.color title.to_s.upcase, :bold %>:
|
data/lib/commander/runner.rb
CHANGED
@@ -36,18 +36,18 @@ module Commander
|
|
36
36
|
|
37
37
|
def run!
|
38
38
|
trace = false
|
39
|
-
require_program :
|
39
|
+
require_program :version, :description
|
40
40
|
trap('INT') { abort program(:int_message) }
|
41
|
-
global_option('--help', 'Display help documentation') { command(:help).run *@args[1..-1]; return }
|
42
|
-
global_option('--version', 'Display version information') { say version; return }
|
43
|
-
global_option('--trace', 'Display backtrace when an error occurs') { trace = true }
|
41
|
+
global_option('-h', '--help', 'Display help documentation') { command(:help).run *@args[1..-1]; return }
|
42
|
+
global_option('-v', '--version', 'Display version information') { say version; return }
|
43
|
+
global_option('-t', '--trace', 'Display backtrace when an error occurs') { trace = true }
|
44
44
|
parse_global_options
|
45
45
|
remove_global_options
|
46
46
|
unless trace
|
47
47
|
begin
|
48
|
-
|
49
|
-
rescue InvalidCommandError
|
50
|
-
abort
|
48
|
+
run_active_command
|
49
|
+
rescue InvalidCommandError => e
|
50
|
+
abort "#{e}. Use --help for more information"
|
51
51
|
rescue \
|
52
52
|
OptionParser::InvalidOption,
|
53
53
|
OptionParser::InvalidArgument,
|
@@ -57,7 +57,7 @@ module Commander
|
|
57
57
|
abort "error: #{e}. Use --trace to view backtrace"
|
58
58
|
end
|
59
59
|
else
|
60
|
-
|
60
|
+
run_active_command
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
@@ -69,9 +69,10 @@ module Commander
|
|
69
69
|
end
|
70
70
|
|
71
71
|
##
|
72
|
-
#
|
72
|
+
# Run the active command.
|
73
73
|
|
74
|
-
def
|
74
|
+
def run_active_command
|
75
|
+
require_valid_command
|
75
76
|
if alias? command_name_from_args
|
76
77
|
active_command.run *(@aliases[command_name_from_args.to_s] + args_without_command_name)
|
77
78
|
else
|
@@ -131,16 +132,21 @@ module Commander
|
|
131
132
|
|
132
133
|
def command name, &block
|
133
134
|
yield add_command(Commander::Command.new(name)) if block
|
134
|
-
@commands[name.to_s]
|
135
|
+
@commands[name.to_s]
|
135
136
|
end
|
136
137
|
|
137
138
|
##
|
138
|
-
# Add a global option; follows the same syntax as
|
139
|
-
#
|
140
|
-
# as --version, --trace, etc.
|
139
|
+
# Add a global option; follows the same syntax as Command#option
|
140
|
+
# This would be used for switches such as --version, --trace, etc.
|
141
141
|
|
142
142
|
def global_option *args, &block
|
143
|
-
|
143
|
+
switches, description = Runner.seperate_switches_from_description *args
|
144
|
+
@options << {
|
145
|
+
:args => args,
|
146
|
+
:proc => block,
|
147
|
+
:switches => switches,
|
148
|
+
:description => description,
|
149
|
+
}
|
144
150
|
end
|
145
151
|
|
146
152
|
##
|
@@ -228,7 +234,9 @@ module Commander
|
|
228
234
|
# Returns hash of program defaults.
|
229
235
|
|
230
236
|
def program_defaults
|
231
|
-
return :help_formatter => HelpFormatter::Terminal,
|
237
|
+
return :help_formatter => HelpFormatter::Terminal,
|
238
|
+
:int_message => "\nProcess interrupted",
|
239
|
+
:name => File.basename($0)
|
232
240
|
end
|
233
241
|
|
234
242
|
##
|
@@ -246,12 +254,21 @@ module Commander
|
|
246
254
|
if args.empty?
|
247
255
|
say help_formatter.render
|
248
256
|
else
|
249
|
-
|
257
|
+
command = command args.join(' ')
|
258
|
+
require_valid_command command
|
259
|
+
say help_formatter.render_command(command)
|
250
260
|
end
|
251
261
|
end
|
252
262
|
end
|
253
263
|
end
|
254
264
|
|
265
|
+
##
|
266
|
+
# Raises InvalidCommandError when a +command+ is not found.
|
267
|
+
|
268
|
+
def require_valid_command command = active_command
|
269
|
+
raise InvalidCommandError, 'invalid command', caller if command.nil?
|
270
|
+
end
|
271
|
+
|
255
272
|
##
|
256
273
|
# Removes global options from args. This prevents an invalid
|
257
274
|
# option error from ocurring when options are parsed
|
@@ -259,8 +276,8 @@ module Commander
|
|
259
276
|
|
260
277
|
def remove_global_options
|
261
278
|
# TODO: refactor with flipflop
|
262
|
-
options.each do |
|
263
|
-
switch, has_arg = args.first.split
|
279
|
+
options.each do |option|
|
280
|
+
switch, has_arg = option[:args].first.split
|
264
281
|
past_switch, arg_removed = false, false
|
265
282
|
@args.delete_if do |arg|
|
266
283
|
if arg == switch
|
@@ -280,14 +297,29 @@ module Commander
|
|
280
297
|
# Parse global command options.
|
281
298
|
|
282
299
|
def parse_global_options
|
283
|
-
options.inject OptionParser.new do |options,
|
284
|
-
options.on *args, &proc
|
300
|
+
options.inject OptionParser.new do |options, option|
|
301
|
+
options.on *option[:args], &global_option_proc(option[:switches], &option[:proc])
|
285
302
|
end.parse! @args.dup
|
286
303
|
rescue OptionParser::InvalidOption
|
287
304
|
# Ignore invalid options since options will be further
|
288
305
|
# parsed by our sub commands.
|
289
306
|
end
|
290
307
|
|
308
|
+
##
|
309
|
+
# Returns a proc allowing for sub-commands to inherit global options.
|
310
|
+
# This functionality works weither a block is present for the global
|
311
|
+
# option or not, so simple switches such as --verbose can be used
|
312
|
+
# without a block, and used throughout all sub-commands.
|
313
|
+
|
314
|
+
def global_option_proc switches, &block
|
315
|
+
lambda do |value|
|
316
|
+
unless active_command.nil?
|
317
|
+
active_command.proxy_options << [Runner.switch_to_sym(switches.last), value]
|
318
|
+
end
|
319
|
+
yield value if block and !value.nil?
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
291
323
|
##
|
292
324
|
# Raises a CommandError when the program any of the +keys+ are not present, or empty.
|
293
325
|
|
@@ -297,6 +329,30 @@ module Commander
|
|
297
329
|
end
|
298
330
|
end
|
299
331
|
|
332
|
+
##
|
333
|
+
# Return switches and description seperated from the +args+ passed.
|
334
|
+
|
335
|
+
def self.seperate_switches_from_description *args
|
336
|
+
switches = args.find_all { |arg| arg.to_s =~ /^-/ }
|
337
|
+
description = args.last unless !args.last.is_a? String or args.last.match(/^-/)
|
338
|
+
return switches, description
|
339
|
+
end
|
340
|
+
|
341
|
+
##
|
342
|
+
# Attempts to generate a method name symbol from +switch+.
|
343
|
+
# For example:
|
344
|
+
#
|
345
|
+
# -h # => :h
|
346
|
+
# --trace # => :trace
|
347
|
+
# --some-switch # => :some_switch
|
348
|
+
# --[no-]feature # => :feature
|
349
|
+
# --file FILE # => :file
|
350
|
+
# --list of,things # => :list
|
351
|
+
|
352
|
+
def self.switch_to_sym switch
|
353
|
+
switch.scan(/[\-\]](\w+)/).join('_').to_sym rescue nil
|
354
|
+
end
|
355
|
+
|
300
356
|
private
|
301
357
|
|
302
358
|
def say *args #:nodoc:
|
data/lib/commander/version.rb
CHANGED
data/spec/command_spec.rb
CHANGED
@@ -24,14 +24,6 @@ describe Commander::Command do
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
describe "#seperate_switches_from_description" do
|
28
|
-
it "should seperate switches and description returning both" do
|
29
|
-
switches, description = *@command.seperate_switches_from_description('-h', '--help', 'display help')
|
30
|
-
switches.should == ['-h', '--help']
|
31
|
-
description.should == 'display help'
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
27
|
describe "#option" do
|
36
28
|
it "should add options" do
|
37
29
|
lambda { @command.option '--recursive' }.should change(@command.options, :length).from(1).to(2)
|
@@ -49,17 +41,6 @@ describe Commander::Command do
|
|
49
41
|
end
|
50
42
|
end
|
51
43
|
|
52
|
-
describe "#switch_to_sym" do
|
53
|
-
it "should return a symbol based on the switch name" do
|
54
|
-
@command.switch_to_sym('--trace').should == :trace
|
55
|
-
@command.switch_to_sym('--foo-bar').should == :foo_bar
|
56
|
-
@command.switch_to_sym('--[no-]feature"').should == :feature
|
57
|
-
@command.switch_to_sym('--[no-]feature ARG').should == :feature
|
58
|
-
@command.switch_to_sym('--file [ARG]').should == :file
|
59
|
-
@command.switch_to_sym('--colors colors').should == :colors
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
44
|
describe "#run" do
|
64
45
|
describe "should invoke #when_called" do
|
65
46
|
it "with arguments seperated from options" do
|
data/spec/runner_spec.rb
CHANGED
@@ -20,7 +20,7 @@ describe Commander do
|
|
20
20
|
|
21
21
|
it "should raise an error when required info has not been set" do
|
22
22
|
new_command_runner '--help'
|
23
|
-
program :
|
23
|
+
program :version, ''
|
24
24
|
lambda { run! }.should raise_error(Commander::Runner::CommandError)
|
25
25
|
end
|
26
26
|
end
|
@@ -30,8 +30,27 @@ describe Commander do
|
|
30
30
|
command(:test).should be_instance_of(Commander::Command)
|
31
31
|
end
|
32
32
|
|
33
|
-
it "should
|
34
|
-
|
33
|
+
it "should return nil when the command does not exist" do
|
34
|
+
command(:im_not_real).should be_nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#seperate_switches_from_description" do
|
39
|
+
it "should seperate switches and description returning both" do
|
40
|
+
switches, description = *Commander::Runner.seperate_switches_from_description('-h', '--help', 'display help')
|
41
|
+
switches.should == ['-h', '--help']
|
42
|
+
description.should == 'display help'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#switch_to_sym" do
|
47
|
+
it "should return a symbol based on the switch name" do
|
48
|
+
Commander::Runner.switch_to_sym('--trace').should == :trace
|
49
|
+
Commander::Runner.switch_to_sym('--foo-bar').should == :foo_bar
|
50
|
+
Commander::Runner.switch_to_sym('--[no-]feature"').should == :feature
|
51
|
+
Commander::Runner.switch_to_sym('--[no-]feature ARG').should == :feature
|
52
|
+
Commander::Runner.switch_to_sym('--file [ARG]').should == :file
|
53
|
+
Commander::Runner.switch_to_sym('--colors colors').should == :colors
|
35
54
|
end
|
36
55
|
end
|
37
56
|
|
@@ -42,14 +61,15 @@ describe Commander do
|
|
42
61
|
end
|
43
62
|
|
44
63
|
it "should pass arguments passed to the alias when called" do
|
64
|
+
gem_name = ''
|
45
65
|
new_command_runner 'install', 'gem', 'commander' do
|
46
66
|
command :install do |c|
|
47
67
|
c.option '--gem-name NAME', 'Install a gem'
|
48
|
-
c.when_called { |_, options| options.gem_name
|
68
|
+
c.when_called { |_, options| gem_name = options.gem_name }
|
49
69
|
end
|
50
70
|
alias_command :'install gem', :install, '--gem-name'
|
51
|
-
command(:install).should_receive(:run).once
|
52
71
|
end.run!
|
72
|
+
gem_name.should == 'commander'
|
53
73
|
end
|
54
74
|
end
|
55
75
|
|
@@ -61,6 +81,28 @@ describe Commander do
|
|
61
81
|
end.run!
|
62
82
|
file.should == 'foo'
|
63
83
|
end
|
84
|
+
|
85
|
+
it "should be inherited by sub-commands" do
|
86
|
+
quiet = nil
|
87
|
+
new_command_runner 'foo', '--quiet' do
|
88
|
+
global_option('--quiet', 'Suppress output')
|
89
|
+
command :foo do |c|
|
90
|
+
c.when_called { |_, options| quiet = options.quiet }
|
91
|
+
end
|
92
|
+
end.run!
|
93
|
+
quiet.should be_true
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should be inherited by sub-commands even when a block is present" do
|
97
|
+
quiet = nil
|
98
|
+
new_command_runner 'foo', '--quiet' do
|
99
|
+
global_option('--quiet', 'Suppress output') {}
|
100
|
+
command :foo do |c|
|
101
|
+
c.when_called { |_, options| quiet = options.quiet }
|
102
|
+
end
|
103
|
+
end.run!
|
104
|
+
quiet.should be_true
|
105
|
+
end
|
64
106
|
end
|
65
107
|
|
66
108
|
describe "--trace" do
|
@@ -165,9 +207,9 @@ describe Commander do
|
|
165
207
|
command_runner.active_command.should be_instance_of(Commander::Command)
|
166
208
|
end
|
167
209
|
|
168
|
-
it "should
|
210
|
+
it "should return nil when the command is not found" do
|
169
211
|
new_command_runner 'foo'
|
170
|
-
|
212
|
+
command_runner.active_command.should be_nil
|
171
213
|
end
|
172
214
|
end
|
173
215
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: visionmedia-commander
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- TJ Holowaychuk
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-03-
|
12
|
+
date: 2009-03-26 00:00:00 -07:00
|
13
13
|
default_executable: commander
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|