visionmedia-commander 3.1.8 → 3.2.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/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
|