Object
Clio's Commandline class is a very versitile command line parser. A Command can be used either declaritively, defining usage and help information upfront; or lazily, whereby information about usage is built-up as the commandline actually gets use in one's program; or you can use a mixture of the two.
As you might expect the fluent notation can be broken down into block notation.
cli = Clio::Command.new cli.usage do option(:verbose, :v) do help('verbose output') end option(:quiet, :q) do help('run silently') xor(:V) end command(:document) do help('generate documentation') option(:output, :o) do type('FILE') help('output directory') end argument('files') do multiple end end end
Clearly block notation is DRY and easier to read, but fluent notation is important to have because it allows the Commandline object to be passed around as an argument and modified easily.
This notation is very elegant, but slightly more limited in scope. For instance, subcommands that use non-letter characters, such as ':', can not be described with this notation.
cli.usage.document('*files', '--output=FILE -o') cli.usage('--verbose -V','--quiet -q') cli.usage.help( 'document' , 'generate documentation', 'validate' , 'run tests or specifications', '--verbose' , 'verbose output', '--quiet' , 'run siltently' ) cli.usage.document.help( '--output', 'output directory' 'file*', 'files to document' )
This notation is slightly more limited in scope... so...
cli.usage.command(:document, '--output=FILE -o', 'files*')
The core notation can be somewhat verbose. As a further convenience commandline usage can be defined with a brief bracket shorthand. This is especailly useful when the usage is simple and statically defined.
cli.usage['document']['--output=FILE -o']['FILE*']
Using a little creativity to improve readabilty we can convert the whole example from above using this notation.
cli.usage['--verbose -V', 'verbose output' ] \ ['--quiet -q', 'run silently' ] \ ['document', 'generate documention' ] \ [ '--output=FILE -o', 'output directory' ] \ [ 'FILE*', 'files to document' ]
Alternately the help information can be left out and defined in a seprate set of usage calls.
cli.usage['--verbose -V']['--quiet -q'] \ ['document']['--output=FILE -o']['FILE*'] cli.usage.help( 'document' , 'generate documentation', 'validate' , 'run tests or specifications', '--verbose' , 'verbose output', '--quiet' , 'run siltently' ) cli.usage['document'].help( '--output', 'output directory' 'FILE', 'files to docment' )
A little more verbose, but a bit more intutive.
Since the various notations all translate to same underlying structures, they can be mixed and matched as suites ones taste. For example we could mix Method Notation and Bracket Notation.
cli.usage.document['--output=FILE -o']['file*'] cli.usage['--verbose -V']['--quiet -q']
The important thing to keep in mind when doing this is what is returned by each type of usage call.
With usage in place, call the parse method to process the actual commandline.
cli.parse
If no command arguments are passed to parse, ARGV is used.
Lastly, Commandline provides a simple means to cache usage information to a configuration file, which then can be used again the next time the same command is used. This allows Commandline to provide high-performane tab completion.
# File lib/clio/commandline.rb, line 225 def argument(*n_type, &block) usage.argument(*n_type, &block) end
# File lib/clio/commandline.rb, line 230 def help(string=nil) usage.help(string) end
New Command.
# File lib/clio/commandline.rb, line 242 def initialize(argv=nil, opts={}, &block) argv_set(argv || ARGV) #if opts[:usage] # @usage = opts[:usage] #else # #@usage = load_cache #end if self.class == Commandline @usage = Usage.new else @usage = self.class.usage #|| Usage.new end @usage.instance_eval(&block) if block end
# File lib/clio/commandline.rb, line 219 def opt(label, help, &block) usage.opt(label, help, &block) end
# File lib/clio/commandline.rb, line 213 def option(name, *aliases, &block) usage.option(name, *aliases, &block) end
# File lib/clio/commandline.rb, line 206 def subcommand(name, help=nil, &block) usage.subcommand(name, help, &block) end
# File lib/clio/commandline.rb, line 322 def arguments ; cli.arguments ; end
# File lib/clio/commandline.rb, line 258 def argv_set(argv) # reset parser @parser = nil # convert to array if string if String===argv argv = Shellwords.shellwords(argv) end # remove anything subsequent to '--' if index = argv.index('--') argv = argv[0...index] end @argv = argv end
# File lib/clio/commandline.rb, line 273 def cli #parse unless @cli @cli end
# File lib/clio/commandline.rb, line 316 def command ; cli.command ; end
# File lib/clio/commandline.rb, line 319 def commands ; cli.commands ; end
TODO: adding '-' is best idea?
# File lib/clio/commandline.rb, line 347 def completion(argv=nil) argv_set(argv) if argv @argv << "\t" parse @argv.pop parser.errors[0][1].completion.collect{ |s| s.to_s } #@argv.pop if @argv.last == '?' #load_cache #parse end
Method missing provide passive usage and parsing.
TODO: This reparses the commandline after every query.
Need only parse if usage has change.
# File lib/clio/commandline.rb, line 369 def method_missing(s, *a) begin s = s.to_s case s when /[=]$/ n = s.chomp('=') usage.option(n).type(*a) parse res = @cli.options[n.to_sym] when /[!]$/ n = s.chomp('!') cmd = usage.commands[n.to_sym] || usage.command(n, *a) res = parse when /[?]$/ n = s.chomp('?') u = usage.option(n, *a) parse res = @cli.options[u.key] else usage.option(s, *a) parse res = @cli.options[s.to_sym] end rescue Usage::ParseError => e res = nil end return res end
Parameters
# File lib/clio/commandline.rb, line 332 def parameters ; cli.parameters ; end
# File lib/clio/commandline.rb, line 300 def parse(argv=nil) argv_set(argv) if argv @cli = parser.parse end
# File lib/clio/commandline.rb, line 306 def parser @parser ||= Usage::Parser.new(usage, @argv) end
# File lib/clio/commandline.rb, line 325 def switches ; cli.options ; end
# File lib/clio/commandline.rb, line 295 def to_s_help usage.to_s_help end
def usage(name=nil, &block)
@usage ||= Usage.new(name) @usage.instance_eval(&block) if block @usage
end
# File lib/clio/commandline.rb, line 285 def usage @usage end
Commandline fully valid?
# File lib/clio/commandline.rb, line 341 def valid? @cli.valid? end
Generated with the Darkfish Rdoc Generator 2.