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.