Clio::Usage
Create a Usage object.
Require usage library.
require 'clio/usage'
Fake a commandline invocation.
$0 = 'test'
Create a Usage object.
usage = Clio::Usage.new
Basic Notation
Define a usage subcommand using #subcommand.
usage = Clio::Usage.new
usage.subcommand('foo')
usage.to_s.assert == 'test foo'
This is also aliased as #command.
usage = Clio::Usage.new
usage.command('foo')
usage.to_s.assert == 'test foo'
A toplevel switch/option is defined with #option.
usage = Clio::Usage.new
usage.option('verbose')
usage.to_s.assert == 'test [--verbose]'
Options can also have aliases.
usage = Clio::Usage.new usage.option(:verbose, :v) usage.to_s.assert == 'test [-v --verbose]'
Arguments are defined with #argument, which takes a type, or name and type. Multiple arguments can be defined, and are processed in the order defined.
usage = Clio::Usage.new
usage.argument('TYPE1')
usage.argument('name:TYPE2')
usage.to_s.assert == 'test <TYPE1> <name:TYPE2>'
But arguments can be index to sepcify the index. Argument index start with 1 (not 0).
usage = Clio::Usage.new usage.argument(1, 'TYPE1') usage.argument(2, 'name:TYPE2') usage.to_s.assert == 'test <TYPE1> <name:TYPE2>'
Final arguments can consume all remaining arguments. Define this with #splat.
usage = Clio::Usage.new
usage.argument('TYPE').splat(true)
usage.to_s.assert == 'test <TYPE...>'
Usage cannot have both subcommands and arguments.
usage = Clio::Usage.new
expect ArgumentError do
usage.subcommand('foo')
usage.argument('bar')
end
Anything define on a Usage object, can also be defined for a subcommand, since Usage.new actually returns and subclass of Subcommand.
usage = Clio::Usage.new usage.class.assert < Clio::Usage::Subcommand
Bringing it all together in a .
usage = Clio::Usage.new
usage.option(:verbose, :v)
usage.command('foo').argument('TYPE')
usage.to_s.assert == 'test [-v --verbose] foo <TYPE>'
Bracket Notation
Subcommand, options and arguments can also be defined using #[]. They are distinighished by syntax used. For instance, to define a subcommand, use bare syntax.
usage = Clio::Usage.new usage['foo'] usage.to_s.assert == 'test foo'
To define an option prefix the syntax with ’—’ or ’-’, and aliases are separated by spaces.
usage = Clio::Usage.new usage['--verbose -v'] usage.to_s.assert == 'test [-v --verbose]'
Arguments are defined by wrapping the type or name:type in < > brackets.
usage = Clio::Usage.new usage['<TYPE>'] usage.to_s.assert == 'test <TYPE>'
Usage Parsing
Require usage library.
require 'clio/usage'
A single toplevel option.
usage = Clio::Usage.new
usage.option('force')
cli = usage.parse('--force')
cli.options.assert == {:force=>true}
A single toplevel option with an alias.
usage = Clio::Usage.new
usage.option('force', 'f')
cli = usage.parse('-f')
cli.options.assert == {:force=>true}
A subcommand.
usage = Clio::Usage.new
usage.command('foo')
cli = usage.parse('foo')
cli.command.assert == 'foo'
cli.commands.assert == ['foo']
A subcommand with an option.
usage = Clio::Usage.new
usage.command('foo')
usage.command('foo').option('verbose')
cli = usage.parse('foo --verbose')
cli.command.assert == 'foo'
cli.commands.assert == ['foo']
cli.options.assert == {:verbose=>true}
cli[0].options.assert == {}
cli[1].options.assert == {:verbose=>true}
Commandline Definition using Core Notation
Require commandline library.
require 'clio/commandline'
Fake that we running an executable called ‘test’.
$0 = 'test'
Create a new commandline object.
@cmd = Clio::Commandline.new
We can define a subcommand using #command on #usage.
@cmd.usage.command('foo')
@cmd.to_s.assert == 'test foo'
We can define a toplevel switch using #switch.
@cmd.usage.switch('verbose')
@cmd.to_s.assert == 'test [--verbose] foo'
Switches can have aliases.
@cmd.usage.switch(:verbose, :v)
@cmd.to_s.assert == 'test [-v --verbose] foo'
There can be mulitple subcommands.
@cmd.usage.command('foo bar')
@cmd.to_s.assert == 'test [-v --verbose] foo bar'
Let’s bring it all together in one example.
cmd = Clio::Commandline.new
cmd.usage.switch(:verbose, :v)
cmd.usage.switch(:force, :f)
cmd.usage.command('foo')
cmd.usage.command('bar')
cmd.to_s.assert == 'test [-v --verbose] [-f --force] [foo | bar]'
Command Definition using Bracket Notation
Require commandline library.
require 'clio/commandline'
Since this not a real command line application, lets fake one called ‘test’.
$0 = 'test'
We can use a method to define a subcommand.
cmd = Clio::Commandline.new
cmd.usage['doc']
cmd.to_s.assert == 'test doc'
We can use a question-method to define a switch.
cmd = Clio::Commandline.new
cmd.usage['doc']
cmd.usage['--verbose']
cmd.to_s.assert == 'test [--verbose] doc'
The switch method can also take option aliases.
cmd = Clio::Commandline.new
cmd.usage['--verbose -v']
cmd.to_s.assert == 'test [-v --verbose]'
The command can take argument to process as suboptions and arguments.
cmd = Clio::Commandline.new
cmd.usage['doc']['--output=PATH']
cmd.to_s.assert == 'test doc [--output=PATH]'
cmd.usage.doc.to_s.assert == 'doc [--output=PATH]'
An option and a subcommand parsed statically.
cmd = Clio::Commandline.new
cmd.usage['--verbose -v']
cmd.usage['doc']['--output=PATH']
cmd.usage['doc']['<file>']
cmd.to_s.assert == 'test [-v --verbose] doc [--output=PATH] <file>'
We can define help for these commands and options using a seaprate help! call.
cmd = Clio::Commandline.new
cmd.usage['doc']['--output=PATH']
cmd.usage['--verbose -v']
#cmd.usage['doc'] = 'generate documentation'
#cmd.usage['--verbose -v'] = 'verbose mode'
cmd.usage.help!(
'doc', 'generate documentation',
'--verbose', 'verbose mode'
)
cmd.usage.options[0].name.assert == 'verbose'
Command Definition using Method Notation
Require commandline library.
require 'clio/commandline'
Since this not a real command line application, lets fake one called ‘test’.
$0 = 'test'
We can use a method to define a subcommand.
cmd = Clio::Commandline.new
cmd.usage.doc
cmd.to_s.assert == 'test doc'
We can use a question-method to define a switch.
cmd = Clio::Commandline.new
cmd.usage.doc
cmd.usage.verbose?
cmd.to_s.assert == 'test [--verbose] doc'
The switch method can also take option aliases.
cmd = Clio::Commandline.new
cmd.usage.verbose?(:v)
cmd.to_s.assert == 'test [-v --verbose]'
The command can take argument to process as suboptions and arguments.
cmd = Clio::Commandline.new
cmd.usage.doc('--output=PATH')
cmd.to_s.assert == 'test doc [--output=PATH]'
cmd.usage.doc.to_s.assert == 'doc [--output=PATH]'
An option and a subcommand parsed statically.
cmd = Clio::Commandline.new
cmd.usage.doc('--output=PATH')
cmd.usage.verbose?(:v)
cmd.to_s.assert == 'test [-v --verbose] doc [--output=PATH]'
We can define help for these commands and options using a seaprate help! call.
cmd = Clio::Commandline.new
cmd.usage.doc('--output=PATH')
cmd.usage.verbose?(:v)
cmd.usage.help!(
'doc', 'generate documentation',
'--verbose', 'verbose mode'
)
cmd.usage.options[0].name.assert == 'verbose'
Command Parsing
Require command library.
require 'clio/commandline'
A single toplevel option.
cmd = Clio::Commandline.new
cmd.usage.option('force')
cmd.parse('--force')
cmd.options.assert == {:force=>true}
A single toplevel option with an alias.
cmd = Clio::Commandline.new
cmd.usage.option('force', 'f')
cmd.parse('-f')
cmd.options.assert == {:force=>true}
A subcommand.
cmd = Clio::Commandline.new
cmd.usage.command('foo')
cmd.parse('foo')
cmd.command.assert == 'foo'
cmd.commands.assert == ['foo']
A subcommand with an option.
cmd = Clio::Commandline.new
cmd.usage.command('foo')
cmd.usage.command('foo').option('verbose')
cmd.parse('foo --verbose')
cmd.command.assert == 'foo'
cmd.commands.assert == ['foo']
cmd.options.assert == {:verbose=>true}
cmd[0].options.assert == {}
cmd[1].options.assert == {:verbose=>true}
Multiple subcommands.
cmd = Clio::Commandline.new
cmd.usage.command('foo').command('bar').option('verbose')
cmd.parse('foo bar --verbose')
cmd.command.assert == 'foo bar'
cmd.commands.assert == ['foo','bar']
cmd.options == {:verbose=>true}
cmd[0].options.assert == {}
cmd[1].options.assert == {}
cmd[2].options.assert == {:verbose=>true}
Multiple subcommands.
cmd = Clio::Commandline.new
cmd.usage.command('foo').option('verbose')
cmd.usage.command('foo bar')
cmd.parse('foo bar --verbose')
cmd.command.assert == 'foo bar'
cmd.commands.assert == ['foo','bar']
cmd.options == {:verbose=>true}
cmd[0].options.assert == {}
cmd[1].options.assert == {}
cmd[2].options.assert == {:verbose=>true}
Method Missing "Auto" Usage
Require Commandline library.
require 'clio/commandline'
$0 = 'test'
Handles a toplevel option using method_missing.
cli = Clio::Commandline.new('--verbose')
cli.verbose?
cli.to_s.assert == 'test [--verbose]'
Handles a toplevel option with aliases using method_missing.
cli = Clio::Commandline.new('--verbose')
cli.verbose?(:v)
cli.to_s.assert == 'test [-v --verbose]'
Returns a toplevel option value"
cli = Clio::Commandline.new('--verbose')
cli.verbose?(:v).assert == true
Create new commandline object.
cmd = Clio::Commandline.new('--verbose')
cmd.usage.command('foo')
cmd.parse
Single Character Option
Create new Commandline object.
@cmd = Clio::Commandline.new('-V')
Returns a toplevel option value.
@cmd.verbose?(:V).assert == true
Option Literal Shorthand
An option and a subcommand parsed statically.
$0 = 'test'
@cli = Clio::Commandline.new('-V foo')
@cli.usage.opt('--verbose -V')
@cli.usage.command('foo')
@cli.parse
Parses the option correctly.
@cli.options[:verbose].assert == true
Test Subclass of Subclass of Command
Require clio/commandline.rb.
require 'clio/commandline'
Fake a commandline command.
$0 = 'c0'
Create new subclass of Clio::Commandline.
@cmd_super = Class.new(Clio::Commandline) do
option('o0')
command('c1').option('o1')
command('c1 c2').option('o2')
command('c1 c2').argument('a')
command('c1 c2').argument('b')
command('c1 c2').argument('c')
end
Superclass command display usage string.
@cmd_super.usage.to_s.assert == 'c0 [--o0] c1 [--o1] c2 [--o2] <a> <b> <c>'
Subclass again.
@cmd = Class.new(@cmd_super)
Command display usage string.
@cmd.usage.to_s.assert == 'c0 [--o0] c1 [--o1] c2 [--o2] <a> <b> <c>'
Command initializes.
@cli = @cmd.new('--o0 c1 --o1 c2 --o2 a b c')
Command is inheritable.
@cmd2 = Class.new(@cmd)
Inherited command works like parent.
@cli2 = @cmd2.new('--o0 c1 --o1 c2 --o2 a b c')
@cli2.parse
Inherited command parsed correctly.
@cli2.options.assert == {:o0=>true, :o1=>true, :o2=>true}
Method missing options work.
@cli2.o0?.assert == true @cli2.o1?.assert == true @cli2.o2?.assert == true
Commandline Tab Completion
Load commandline library.
require 'clio/commandline'
Create a new command line object.
$0 = 'c0' @cli = Clio::Commandline.new
Specify usage for comamndline.
@cli.usage.option('o0')
@cli.usage.command('c1').opt('--o1=TYPE -o')
@cli.usage.command('c1 c2').option('o2')
@cli.usage.command('c1 c2').argument('a')
@cli.usage.command('c1 c2').argument('b')
@cli.usage.command('c1 c2').argument('c')
First lets make sure it parses okay.
@cli.parse('--o0 c1 --o1 atype c2 --o2 a b c')
Now let try some tab completion. First a command.
#@cli.parse('c1 -')
@cli.completion('c1').assert == ['-o --o1=TYPE', 'c2']
Now an option.
@cli.completion('c1 --o1').assert == ["TYPE"]
Examples
This is the example on the website. We put it here to make sure it runs.
require 'clio/commandline'
require 'clio/string'
cli = Clio::Commandline.new
cli.usage.document('--output=PATH -o', '*FILES')
cli.usage.verbose?('-v')
cli.usage.help(
'document' , 'generate docs',
'--verbose' , 'do it loudly'
)
cli.parse('document -v -o doc/ README [A-Z]*')
cli.command #=> "document"
cli.verbose? #=> true
cli.document.options #=> [:output => "doc/"]
cli.document.arguments #=> ["README", "[A-Z]*"]
cli.parse('--help')
if cli.help?
puts Clio::String.new(cli.help){ |s|
s.gsub!(/^\w+\:/){ |w| w.bold.underline }
s.gsub!(/[-]{1,2}\w+/){ |w| w.blue }
}
end
Commandline Parses Correctly
Load commandline library.
require 'clio/commandline'
Create a new command line object.
$0 = 'c0'
@cli = Clio::Commandline.new('--o0 c1 --o1 c2 --o2 a b c')
Specify usage for comamndline.
@cli.usage.option('o0')
@cli.usage.command('c1').option('o1')
@cli.usage.command('c1 c2').option('o2')
@cli.usage.command('c1 c2').argument('a')
@cli.usage.command('c1 c2').argument('b')
@cli.usage.command('c1 c2').argument('c')
#@cli.usage.option('o0')
#@cliusage.argument('a0')
#@cli.usage.command('c1').option('o1')
#@cli.usage.command('c1').argument('a1')
#@cli.usage.command('c1').command('c2').option('o2')
#@cli.usage.command('c1').command('c2').argument('a2')
Usage string is correct.
@cli.to_s.assert == 'c0 [--o0] c1 [--o1] c2 [--o2] <a> <b> <c>'
Parses without error.
@cli.parse
Full signature is correct.
@cli.to_a.assert == [
["c0", [], {:o0=>true}],
["c1", [], {:o1=>true}],
["c2", ["a", "b", "c"], {:o2=>true}]
]
Options provides all options merged together.
@cli.options.assert == {:o0=>true,:o1=>true,:o2=>true}
Switches method is an alias for options.
@cli.switches.assert == {:o0=>true,:o1=>true,:o2=>true}
Arguments provides all concated together.
@cli.arguments.assert == ["a", "b", "c"]
Parameters method provides arguments and options.
@cli.parameters.assert == ["a", "b", "c", {:o0=>true,:o1=>true,:o2=>true}]
Zeroth signature is correct.
@cli[0].command.assert == 'c0'
@cli[0].options.assert == {:o0=>true}
@cli[0].arguments.assert == []
@cli[0].parameters.assert == [{:o0=>true}]
@cli[0].signature.assert == ["c0", [], {:o0=>true}]
@cli[0].to_a.assert == ["c0", [], {:o0=>true}]
First signature is correct.
@cli[1].to_a.assert == ["c1", [], {:o1=>true}]
Second signature is correct.
@cli[2].to_a.assert == ["c2", ["a", "b", "c"], {:o2=>true}]
There are no more signatures after the second.
@cli[3].assert == nil
Clio::String
This is a unit test specification for the Clio::String class. This class is intended to provide a very convenient way to output colorful and aligned text to a shell console.
Require the Clio String library.
require 'clio/string'
Define a few regular strings for comparison.
@s1 = "Hi how are you." @s2 = "Fine thanks."
Define the equivalent Clio strings.
@c1 = Clio.string("Hi how are you.")
@c2 = Clio.string("Fine thanks.")
Clio::String#ansi is used to wrap the current string in an ANSI code bracket, ie. prepending with the given ANSI code and appending with the ANSI escape code.
y = @c1.ansi(:red) x = "\e[31mHi how are you.\e[0m" y.to_s.should == x
Some methods are delegated directly to the underying string, as they do not effect any ANSI codes have been applied.
y = @c1.ansi(:red).upcase x = "\e[31mHI HOW ARE YOU.\e[0m" y.to_s.should == x
Shortcut methods are provided for most ANSI Codes, such as Clio::String#red.
y = @c1.red x = "\e[31mHi how are you.\e[0m" y.to_s.should == x
Clio::String#[] will return the character at a gven index. This works like Ruby 1.9, so no size parameter is needed.
y = @c1[0] x = @s1[0,1] y.to_s.should == x
But the size parameter can be given too.
y = @c1[0,3] x = @s1[0,3] y.to_s.should == x
A Range works too.
y = @c1[0..3] x = @s1[0..3] y.to_s.should == x
Clio::String#+ works just like a regular String.
y = @c1 + @c2 x = @s1 + @s2 y.to_s.should == x
Complex cases with ANSI codes work as expected.
s1 = Clio.string("a").red
s2 = Clio.string("b").blue
y = s1 + s2
x = "\e[31ma\e[0m\e[34mb\e[0m"
y.to_s.should == x
Method #sub can replace a substring.
y = @c1.sub('Hi', 'Hello')
x = "Hello how are you."
y.to_s.assert == x
Method #gsub! can replace many substrings.
s1 = Clio.string("axax").red
s2 = Clio.string("axax").blue
y = s1 + s2
y.to_s.assert == "\e[31maxax\e[0m\e[34maxax\e[0m"
y.gsub!('x', 'y')
y.to_s.assert == "\e[31mayay\e[0m\e[34mayay\e[0m"
This specification is not complete, but it is a good start.