cmdparse 1.0.5 → 2.0.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 +40 -0
- data/README +12 -12
- data/Rakefile +11 -11
- data/TODO +1 -0
- data/VERSION +1 -1
- data/doc/config.yaml +2 -0
- data/doc/plugin/extract.rb +1 -1
- data/doc/src/about.page +9 -1
- data/doc/src/default.template +4 -4
- data/doc/src/documentation.page +72 -36
- data/doc/src/download.page +10 -10
- data/doc/src/features.page +4 -4
- data/doc/src/index.page +12 -1
- data/lib/cmdparse.rb +298 -270
- data/lib/cmdparse/wrappers/optparse.rb +65 -0
- data/net.rb +88 -0
- metadata +12 -10
- data/test.rb +0 -42
data/lib/cmdparse.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
#
|
2
2
|
#--
|
3
3
|
#
|
4
|
-
# $Id: cmdparse.rb
|
4
|
+
# $Id: cmdparse.rb 329 2005-08-14 15:39:05Z thomas $
|
5
5
|
#
|
6
|
-
# cmdparse:
|
6
|
+
# cmdparse: advanced command line parser supporting commands
|
7
7
|
# Copyright (C) 2004 Thomas Leitner
|
8
8
|
#
|
9
9
|
# This program is free software; you can redistribute it and/or modify it under the terms of the GNU
|
@@ -19,380 +19,408 @@
|
|
19
19
|
#
|
20
20
|
#++
|
21
21
|
#
|
22
|
-
# Look at the +CommandParser+ class for details and an example.
|
23
|
-
#
|
24
22
|
|
25
|
-
require 'optparse'
|
26
23
|
|
27
|
-
#
|
28
|
-
|
24
|
+
# Namespace module for cmdparse.
|
25
|
+
module CmdParse
|
26
|
+
|
27
|
+
# The version of this cmdparse implemention
|
28
|
+
VERSION = [2, 0, 0]
|
29
|
+
|
30
|
+
|
31
|
+
# Base class for all cmdparse errors.
|
32
|
+
class ParseError < RuntimeError
|
33
|
+
|
34
|
+
# Sets the reason for a subclass.
|
35
|
+
def self.reason( reason, has_arguments = true )
|
36
|
+
(@@reason ||= {})[self] = [reason, has_arguments]
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the reason plus the message.
|
40
|
+
def message
|
41
|
+
data = @@reason[self.class] || ['Unknown error', true]
|
42
|
+
data[0] + (data[1] ? ": " + super : '')
|
43
|
+
end
|
29
44
|
|
30
|
-
if const_defined?( 'Officious' )
|
31
|
-
Officious.delete( 'version' )
|
32
|
-
Officious.delete( 'help' )
|
33
|
-
else
|
34
|
-
DefaultList.long.delete( 'version' )
|
35
|
-
DefaultList.long.delete( 'help' )
|
36
45
|
end
|
37
46
|
|
38
|
-
#
|
39
|
-
|
40
|
-
|
41
|
-
@banner
|
47
|
+
# This error is thrown when an invalid command is encountered.
|
48
|
+
class InvalidCommandError < ParseError
|
49
|
+
reason 'Invalid command'
|
42
50
|
end
|
43
51
|
|
44
|
-
#
|
45
|
-
|
46
|
-
|
47
|
-
def get_program_name
|
48
|
-
@program_name
|
52
|
+
# This error is thrown when an invalid argument is encountered.
|
53
|
+
class InvalidArgumentError < ParseError
|
54
|
+
reason 'Invalid argument'
|
49
55
|
end
|
50
56
|
|
51
|
-
|
57
|
+
# This error is thrown when an invalid option is encountered.
|
58
|
+
class InvalidOptionError < ParseError
|
59
|
+
reason 'Invalid option'
|
60
|
+
end
|
52
61
|
|
62
|
+
# This error is thrown when no command was given and no default command was specified.
|
63
|
+
class NoCommandGivenError < ParseError
|
64
|
+
reason 'No command given', false
|
65
|
+
end
|
53
66
|
|
54
|
-
#
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
# +CommandParser+ is a class for analyzing the command line of a program. It uses the standard
|
59
|
-
# +OptionParser+ class internally for parsing the options and additionally allows the
|
60
|
-
# specification of commands. Programs which use commands as part of their command line interface
|
61
|
-
# are, for example, Subversion's +svn+ program and Rubygem's +gem+ program.
|
62
|
-
#
|
63
|
-
# == Example
|
64
|
-
#
|
65
|
-
# require 'cmdparse'
|
66
|
-
# require 'ostruct'
|
67
|
-
#
|
68
|
-
# class TestCommand < CommandParser::Command
|
69
|
-
#
|
70
|
-
# def initialize
|
71
|
-
# super('test')
|
72
|
-
# @internal = OpenStruct.new
|
73
|
-
# @internal.function = nil
|
74
|
-
# @internal.audible = false
|
75
|
-
# options.separator "Options:"
|
76
|
-
# options.on("-t", "--test FUNCTION", "Test only FUNCTION") do |func|
|
77
|
-
# @internal.function = func
|
78
|
-
# end
|
79
|
-
# options.on("-a", "--[no-]audible", "Run audible") { |@internal.audible| }
|
80
|
-
# end
|
81
|
-
#
|
82
|
-
# def description
|
83
|
-
# "Executes various tests"
|
84
|
-
# end
|
85
|
-
#
|
86
|
-
# def execute( commandParser, args )
|
87
|
-
# puts "Test: "+ args.inspect
|
88
|
-
# puts @internal.inspect
|
89
|
-
# end
|
90
|
-
#
|
91
|
-
# end
|
92
|
-
#
|
93
|
-
# cmd = CommandParser.new
|
94
|
-
# cmd.options do |opt|
|
95
|
-
# opt.program_name = "testProgram"
|
96
|
-
# opt.version = [0, 1, 0]
|
97
|
-
# opt.release = "1.0"
|
98
|
-
# opt.separator "Global options:"
|
99
|
-
# opt.on("-r", "--require TEST", "Require the TEST")
|
100
|
-
# opt.on("--delay N", Integer, "Delay test for N seconds before executing")
|
101
|
-
# end
|
102
|
-
# cmd.add_command TestCommand.new, true # sets this command as default command
|
103
|
-
# cmd.add_command CommandParser::HelpCommand.new
|
104
|
-
# cmd.add_command CommandParser::VersionCommand.new
|
105
|
-
# cmd.parse!( ARGV )
|
106
|
-
#
|
107
|
-
class CommandParser
|
67
|
+
# This error is thrown when a command is added to another command which does not support commands.
|
68
|
+
class TakesNoCommandError < ParseError
|
69
|
+
reason 'This command takes no other commands', false
|
70
|
+
end
|
108
71
|
|
109
|
-
# The version of the command parser
|
110
|
-
VERSION = [1, 0, 5]
|
111
72
|
|
112
|
-
#
|
113
|
-
class
|
114
|
-
|
115
|
-
|
73
|
+
# Base class for all parser wrappers.
|
74
|
+
class ParserWrapper
|
75
|
+
|
76
|
+
# Returns the parser instance for the object and, if a block is a given, yields the instance.
|
77
|
+
def instance
|
78
|
+
yield @instance if block_given?
|
79
|
+
@instance
|
80
|
+
end
|
81
|
+
|
82
|
+
# Parses the arguments in order, i.e. stops at the first non-option argument, and returns all
|
83
|
+
# remaining arguments.
|
84
|
+
def order( args )
|
85
|
+
raise InvalidOptionError.new( args[0] ) if args[0] =~ /^-/
|
86
|
+
args
|
87
|
+
end
|
88
|
+
|
89
|
+
# Permutes the arguments so that all options anywhere on the command line are parsed and the
|
90
|
+
# remaining non-options are returned.
|
91
|
+
def permute( args )
|
92
|
+
raise InvalidOptionError.new( args[0] ) if args.any? {|a| a =~ /^-/}
|
93
|
+
args
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns a summary string of the options.
|
97
|
+
def summarize
|
98
|
+
""
|
99
|
+
end
|
116
100
|
|
117
|
-
# This error is thrown when no command was given and no default command was specified.
|
118
|
-
class NoCommandGivenError < OptionParser::ParseError
|
119
|
-
const_set( :Reason, 'no command given'.freeze )
|
120
101
|
end
|
121
102
|
|
103
|
+
# Require default option parser wrapper
|
104
|
+
require 'cmdparse/wrappers/optparse'
|
105
|
+
|
106
|
+
|
122
107
|
# Base class for the commands. This class implements all needed methods so that it can be used by
|
123
|
-
# the +
|
108
|
+
# the +CommandParser+ class.
|
124
109
|
class Command
|
125
110
|
|
126
111
|
# The name of the command
|
127
112
|
attr_reader :name
|
128
113
|
|
129
|
-
#
|
130
|
-
|
114
|
+
# A short description of the command.
|
115
|
+
attr_accessor :short_desc
|
116
|
+
|
117
|
+
# A detailed description of the command
|
118
|
+
attr_accessor :description
|
119
|
+
|
120
|
+
# The wrapper for parsing the command line options.
|
121
|
+
attr_accessor :options
|
122
|
+
|
123
|
+
# Returns the name of the default command.
|
124
|
+
attr_reader :default_command
|
125
|
+
|
126
|
+
# Sets or returns the super command of this command. The super command is either a +Command+
|
127
|
+
# instance for normal commands or a +CommandParser+ instance for the root command.
|
128
|
+
attr_accessor :super_command
|
131
129
|
|
132
|
-
#
|
133
|
-
|
130
|
+
# Returns the list of commands for this command.
|
131
|
+
attr_reader :commands
|
132
|
+
|
133
|
+
# Initializes the command called +name+. The parameter +has_commands+ specifies if this command
|
134
|
+
# takes other commands as argument.
|
135
|
+
def initialize( name, has_commands )
|
134
136
|
@name = name
|
135
|
-
@options =
|
137
|
+
@options = ParserWrapper.new
|
138
|
+
@has_commands = has_commands
|
139
|
+
@commands = {}
|
140
|
+
@default_command = nil
|
141
|
+
end
|
142
|
+
|
143
|
+
# Returns +true+ if this command supports sub commands.
|
144
|
+
def has_commands?
|
145
|
+
@has_commands
|
146
|
+
end
|
147
|
+
|
148
|
+
# Adds a command to the command list if this command takes other commands as argument. If the
|
149
|
+
# optional parameter +default+ is true, then this command is used when no command is specified
|
150
|
+
# on the command line.
|
151
|
+
def add_command( command, default = false )
|
152
|
+
raise TakesNoCommandError.new( @name ) if !has_commands?
|
153
|
+
@commands[command.name] = command
|
154
|
+
@default_command = command.name if default
|
155
|
+
command.super_command = self
|
156
|
+
command.init
|
136
157
|
end
|
137
158
|
|
138
|
-
# For sorting commands by name
|
159
|
+
# For sorting commands by name.
|
139
160
|
def <=>( other )
|
140
161
|
@name <=> other.name
|
141
162
|
end
|
142
163
|
|
143
|
-
#
|
144
|
-
#
|
145
|
-
def
|
164
|
+
# Returns the +CommandParser+ instance for this command or +nil+ if this command was not
|
165
|
+
# assigned to a +CommandParser+ instance.
|
166
|
+
def commandparser
|
167
|
+
cmd = super_command
|
168
|
+
cmd = cmd.super_command while !cmd.nil? && !cmd.kind_of?( CommandParser )
|
169
|
+
cmd
|
146
170
|
end
|
147
171
|
|
148
|
-
#
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
172
|
+
# Returns a list of super commands, ie.:
|
173
|
+
# [command, super_command, super_super_command, ...]
|
174
|
+
def super_commands
|
175
|
+
cmds = []
|
176
|
+
cmd = self
|
177
|
+
while !cmd.nil? && !cmd.super_command.kind_of?( CommandParser )
|
178
|
+
cmds << cmd
|
179
|
+
cmd = cmd.super_command
|
180
|
+
end
|
181
|
+
cmds
|
182
|
+
end
|
183
|
+
|
184
|
+
# This method is called when the command is added to a +Command+ instance.
|
185
|
+
def init; end
|
186
|
+
|
187
|
+
# Set the given +block+ as execution block. See also: +execute+.
|
188
|
+
def set_execution_block( &block )
|
189
|
+
@exec_block = block
|
155
190
|
end
|
156
191
|
|
157
|
-
#
|
158
|
-
|
159
|
-
|
192
|
+
# Invokes the block set by +set_execution_block+. This method is called by the +CommandParser+
|
193
|
+
# instance if this command was specified on the command line.
|
194
|
+
def execute( args )
|
195
|
+
@exec_block.call( args )
|
160
196
|
end
|
161
197
|
|
162
|
-
# Defines the usage line for the command.
|
198
|
+
# Defines the usage line for the command.
|
163
199
|
def usage
|
164
|
-
"Usage: #{
|
200
|
+
tmp = "Usage: #{commandparser.program_name}"
|
201
|
+
tmp << " [options] " if !commandparser.options.instance_of?( ParserWrapper )
|
202
|
+
tmp << super_commands.reverse.collect do |c|
|
203
|
+
t = c.name
|
204
|
+
t << " [options]" if !c.options.instance_of?( ParserWrapper )
|
205
|
+
t
|
206
|
+
end.join(' ')
|
207
|
+
tmp << (has_commands? ? " COMMAND [options] [ARGS]" : " [ARGS]")
|
208
|
+
end
|
209
|
+
|
210
|
+
# Default method for showing the help for the command.
|
211
|
+
def show_help
|
212
|
+
puts "#{@name}: #{short_desc}"
|
213
|
+
puts description if description
|
214
|
+
puts
|
215
|
+
puts usage
|
216
|
+
puts
|
217
|
+
if has_commands?
|
218
|
+
list_commands
|
219
|
+
puts
|
220
|
+
end
|
221
|
+
unless (summary = options.summarize).empty?
|
222
|
+
puts summary
|
223
|
+
puts
|
224
|
+
end
|
165
225
|
end
|
166
226
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
227
|
+
#######
|
228
|
+
private
|
229
|
+
#######
|
230
|
+
|
231
|
+
def list_commands( level = 1, command = self )
|
232
|
+
puts "Available commands:" if level == 1
|
233
|
+
command.commands.sort.each do |name, cmd|
|
234
|
+
print " "*level + name.ljust( 15 ) + cmd.short_desc.to_s
|
235
|
+
print " (=default command)" if name == command.default_command
|
236
|
+
print "\n"
|
237
|
+
list_commands( level + 1, cmd ) if cmd.has_commands?
|
238
|
+
end
|
171
239
|
end
|
172
240
|
|
173
241
|
end
|
174
242
|
|
175
243
|
|
176
|
-
# The default help command.It adds the options "-h" and "--help" to the global
|
177
|
-
#
|
178
|
-
# help.
|
244
|
+
# The default help command. It adds the options "-h" and "--help" to the global options of the
|
245
|
+
# associated +CommandParser+. When the command is specified on the command line, it can show the
|
246
|
+
# main help or individual command help.
|
179
247
|
class HelpCommand < Command
|
180
248
|
|
181
249
|
def initialize
|
182
|
-
super( 'help' )
|
250
|
+
super( 'help', false )
|
251
|
+
self.short_desc = 'Provide help for individual commands'
|
252
|
+
self.description = 'This command prints the program help if no arguments are given. ' \
|
253
|
+
'If one or more command names are given as arguments, these arguments are interpreted ' \
|
254
|
+
'as a hierachy of commands and the help for the right most command is show.'
|
183
255
|
end
|
184
256
|
|
185
|
-
def init
|
186
|
-
|
187
|
-
|
188
|
-
|
257
|
+
def init
|
258
|
+
case commandparser.main_command.options
|
259
|
+
when OptionParserWrapper
|
260
|
+
commandparser.main_command.options.instance do |opt|
|
261
|
+
opt.on_tail( "-h", "--help", "Show help" ) do
|
262
|
+
execute( [] )
|
263
|
+
end
|
189
264
|
end
|
190
265
|
end
|
191
266
|
end
|
192
267
|
|
193
|
-
def description
|
194
|
-
'Provides help for the individual commands'
|
195
|
-
end
|
196
|
-
|
197
268
|
def usage
|
198
|
-
"Usage: #{
|
269
|
+
"Usage: #{commandparser.program_name} help [COMMAND SUBCOMMAND ...]"
|
199
270
|
end
|
200
271
|
|
201
|
-
def execute(
|
272
|
+
def execute( args )
|
202
273
|
if args.length > 0
|
203
|
-
|
204
|
-
|
274
|
+
cmd = commandparser.main_command
|
275
|
+
arg = args.shift
|
276
|
+
while !arg.nil? && cmd.commands.keys.include?( arg )
|
277
|
+
cmd = cmd.commands[arg]
|
278
|
+
arg = args.shift
|
279
|
+
end
|
280
|
+
if arg.nil?
|
281
|
+
cmd.show_help
|
205
282
|
else
|
206
|
-
raise
|
283
|
+
raise InvalidArgumentError, args.unshift( arg ).join(' ')
|
207
284
|
end
|
208
285
|
else
|
209
|
-
show_program_help
|
286
|
+
show_program_help
|
210
287
|
end
|
211
288
|
exit
|
212
289
|
end
|
213
290
|
|
291
|
+
#######
|
214
292
|
private
|
293
|
+
#######
|
215
294
|
|
216
|
-
def show_program_help
|
217
|
-
|
218
|
-
puts "Usage: #{commandParser.options.program_name} [global options] <command> [options] [args]"
|
219
|
-
else
|
220
|
-
puts commandParser.options.banner
|
221
|
-
end
|
295
|
+
def show_program_help
|
296
|
+
puts "Usage: #{commandparser.program_name} [options] COMMAND [options] [COMMAND [options] ...] [args]"
|
222
297
|
puts ""
|
223
|
-
|
224
|
-
width = commandParser.commands.keys.max {|a,b| a.length <=> b.length }.length
|
225
|
-
commandParser.commands.sort.each do |name, command|
|
226
|
-
print commandParser.options.summary_indent + name.ljust( width + 4 ) + command.description
|
227
|
-
print " (=default command)" if name == commandParser.default
|
228
|
-
print "\n"
|
229
|
-
end
|
298
|
+
list_commands( 1, commandparser.main_command )
|
230
299
|
puts ""
|
231
|
-
puts
|
300
|
+
puts commandparser.main_command.options.summarize
|
301
|
+
puts
|
232
302
|
end
|
233
303
|
|
234
304
|
end
|
235
305
|
|
236
306
|
|
237
|
-
# The default version command. It adds the options "-v" and "--version" to the global
|
238
|
-
# +CommandParser
|
239
|
-
# program.
|
307
|
+
# The default version command. It adds the options "-v" and "--version" to the global options of
|
308
|
+
# the associated +CommandParser+. When specified on the command line, it shows the version of the
|
309
|
+
# program.
|
240
310
|
class VersionCommand < Command
|
241
311
|
|
242
312
|
def initialize
|
243
|
-
super( 'version' )
|
244
|
-
|
245
|
-
options.separator "Options:"
|
246
|
-
options.on( "-f", "--full", "Show the full version string" ) { @fullversion = true }
|
313
|
+
super( 'version', false )
|
314
|
+
self.short_desc = "Show the version of the program"
|
247
315
|
end
|
248
316
|
|
249
|
-
def init
|
250
|
-
|
251
|
-
|
252
|
-
|
317
|
+
def init
|
318
|
+
case commandparser.main_command.options
|
319
|
+
when OptionParserWrapper
|
320
|
+
commandparser.main_command.options.instance do |opt|
|
321
|
+
opt.on_tail( "--version", "-v", "Show the version of the program" ) do
|
322
|
+
execute( [] )
|
323
|
+
end
|
253
324
|
end
|
254
325
|
end
|
255
326
|
end
|
256
327
|
|
257
|
-
def description
|
258
|
-
"Shows the version of the program"
|
259
|
-
end
|
260
|
-
|
261
328
|
def usage
|
262
|
-
"Usage: #{
|
329
|
+
"Usage: #{commandparser.program_name} version"
|
263
330
|
end
|
264
331
|
|
265
|
-
def execute(
|
266
|
-
|
267
|
-
|
268
|
-
else
|
269
|
-
version = commandParser.options.version
|
270
|
-
version = version.join( '.' ) if version.instance_of? Array
|
271
|
-
end
|
272
|
-
version = "<NO VERSION SPECIFIED>" if version.nil?
|
332
|
+
def execute( args )
|
333
|
+
version = commandparser.program_version
|
334
|
+
version = version.join( '.' ) if version.instance_of?( Array )
|
273
335
|
puts version
|
274
336
|
exit
|
275
337
|
end
|
276
338
|
|
277
339
|
end
|
278
340
|
|
279
|
-
# Holds the registered commands.
|
280
|
-
attr_reader :commands
|
281
|
-
|
282
|
-
# Returns the name of the default command.
|
283
|
-
attr_reader :default
|
284
341
|
|
285
|
-
#
|
286
|
-
|
342
|
+
# The main class for creating a command based CLI program.
|
343
|
+
class CommandParser
|
287
344
|
|
288
|
-
|
289
|
-
|
290
|
-
def initialize( handleExceptions = false )
|
291
|
-
@options = OptionParser.new
|
292
|
-
@commands = {}
|
293
|
-
@default = nil
|
294
|
-
@parsed = {}
|
295
|
-
@handleExceptions = handleExceptions
|
296
|
-
end
|
345
|
+
# The top level command representing the program itself.
|
346
|
+
attr_reader :main_command
|
297
347
|
|
298
|
-
|
299
|
-
|
300
|
-
def options # :yields: options
|
301
|
-
if block_given?
|
302
|
-
yield @options
|
303
|
-
else
|
304
|
-
@options
|
305
|
-
end
|
306
|
-
end
|
348
|
+
# The name of the program.
|
349
|
+
attr_accessor :program_name
|
307
350
|
|
308
|
-
|
309
|
-
|
310
|
-
def add_command( command, default = false )
|
311
|
-
@commands[command.name] = command
|
312
|
-
@default = command.name if default
|
313
|
-
command.init( self )
|
314
|
-
end
|
351
|
+
# The version of the program.
|
352
|
+
attr_accessor :program_version
|
315
353
|
|
316
|
-
|
317
|
-
|
318
|
-
@options.order!( args )
|
319
|
-
end
|
354
|
+
# Are Exceptions be handled gracefully? I.e. by printing error message and the help screen?
|
355
|
+
attr_reader :handle_exceptions
|
320
356
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
end
|
330
|
-
else
|
331
|
-
raise InvalidCommandError.new( @parsed[:command] ) unless commands.include?( @parsed[:command] )
|
357
|
+
# Create a new CommandParser object. The optional argument +handleExceptions+ specifies if the
|
358
|
+
# object should handle exceptions gracefully.
|
359
|
+
def initialize( handleExceptions = false )
|
360
|
+
@main_command = Command.new( 'mainCommand', true )
|
361
|
+
@main_command.super_command = self
|
362
|
+
@program_name = $0
|
363
|
+
@program_version = "0.0.0"
|
364
|
+
@handle_exceptions = handleExceptions
|
332
365
|
end
|
333
|
-
end
|
334
366
|
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
if @parsed[:command]
|
339
|
-
commands[@parsed[:command]].options.permute!( args ) unless commands[@parsed[:command]].options.nil?
|
367
|
+
# Returns the wrapper for parsing the global options.
|
368
|
+
def options
|
369
|
+
@main_command.options
|
340
370
|
end
|
341
|
-
end
|
342
371
|
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
def permute!( args ); parse!( args ); end
|
347
|
-
# Calls +parse+ - implemented to mimic OptionParser
|
348
|
-
def order( args ); parse( args ); end
|
349
|
-
# Calls +parse!+ - implemented to mimic OptionParser
|
350
|
-
def order!( args ); parse!( args ); end
|
351
|
-
# see CommandParser#parse!
|
352
|
-
def parse( args ); parse!( args.dup ); end
|
353
|
-
|
354
|
-
# Parses the given argument. First it tries to parse global arguments if given. After that the
|
355
|
-
# command name is analyzied and the options for the specific commands parsed. If +execCommand+ is
|
356
|
-
# true, the command is executed immediately. If false, the <tt>CommandParser#execute</tt> has to
|
357
|
-
# be called to execute the command. The optional +parse+ parameter specifies what should be
|
358
|
-
# parsed. If <tt>:global</tt> is included in the +parse+ array, global options are parsed; if
|
359
|
-
# <tt>:command</tt> is included, the command is parsed and if <tt>:local</tt> is included, the
|
360
|
-
# local options are parsed.
|
361
|
-
def parse!( args, execCommand = true, parse = [:global, :command, :local] )
|
362
|
-
begin
|
363
|
-
context = :global
|
364
|
-
parse_global_options!( args ) if parse.include?( :global )
|
365
|
-
parse_command!( args ) if parse.include?( :command )
|
366
|
-
|
367
|
-
context = :local
|
368
|
-
parse_local_options!( args ) if parse.include?( :local )
|
369
|
-
rescue OptionParser::ParseError => e
|
370
|
-
handle_exception( e, context )
|
372
|
+
# Sets the wrapper for parsing the global options.
|
373
|
+
def options=( wrapper )
|
374
|
+
@main_command.options = wrapper
|
371
375
|
end
|
372
376
|
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
# Executes the command. The method +CommandParser#parse!+ has to be called before this one!
|
378
|
-
def execute
|
379
|
-
begin
|
380
|
-
commands[@parsed[:command]].execute( self, @parsed[:args] ) if @parsed[:command]
|
381
|
-
rescue OptionParser::ParseError => e
|
382
|
-
handle_exception( e, :local )
|
377
|
+
# Adds a top level command.
|
378
|
+
def add_command( *args )
|
379
|
+
@main_command.add_command( *args )
|
383
380
|
end
|
384
|
-
end
|
385
381
|
|
386
|
-
|
382
|
+
# Parses the command line arguments. If a block is specified, the current hierarchy level and
|
383
|
+
# the name of the current command is yielded after the options for the level have been parsed.
|
384
|
+
def parse( argv = ARGV ) # :yields: level, commandName
|
385
|
+
level = 0
|
386
|
+
command = @main_command
|
387
|
+
|
388
|
+
while !command.nil?
|
389
|
+
argv = if command.has_commands? || ENV.include?( 'POSIXLY_CORRECT' )
|
390
|
+
command.options.order( argv )
|
391
|
+
else
|
392
|
+
command.options.permute( argv )
|
393
|
+
end
|
394
|
+
yield( level, command.name ) if block_given?
|
395
|
+
|
396
|
+
if command.has_commands?
|
397
|
+
cmdName, argv = argv[0], argv[1..-1] || []
|
398
|
+
|
399
|
+
if cmdName.nil?
|
400
|
+
if command.default_command.nil?
|
401
|
+
raise NoCommandGivenError
|
402
|
+
else
|
403
|
+
cmdName = command.default_command
|
404
|
+
end
|
405
|
+
else
|
406
|
+
raise InvalidCommandError.new( cmdName ) unless command.commands.include?( cmdName )
|
407
|
+
end
|
408
|
+
|
409
|
+
command = command.commands[cmdName]
|
410
|
+
level += 1
|
411
|
+
else
|
412
|
+
command.execute( argv )
|
413
|
+
command = nil
|
414
|
+
end
|
415
|
+
end
|
416
|
+
rescue ParseError, OptionParser::ParseError => e
|
417
|
+
raise if !@handle_exceptions
|
418
|
+
puts "Error while parsing command line:\n " + e.message
|
419
|
+
puts
|
420
|
+
@main_command.commands['help'].execute( command.super_commands.reverse.collect {|c| c.name} ) if @main_command.commands['help']
|
421
|
+
exit
|
422
|
+
end
|
387
423
|
|
388
|
-
def handle_exception( exception, context )
|
389
|
-
raise unless @handleExceptions
|
390
|
-
s = (context == :global ? "global" : "command specific")
|
391
|
-
puts "Error parsing #{s} options:\n " + exception.message
|
392
|
-
puts
|
393
|
-
commands['help'].execute( self, (context == :global ? [] : [@parsed[:command]]) ) if commands['help']
|
394
|
-
exit
|
395
424
|
end
|
396
425
|
|
397
426
|
end
|
398
|
-
|