class Opt::Command

Constants

Token

@api private

Attributes

commands[R]

List of registered subcommands.

Can be used to add manually created {Command}s but use with care as no collision or sanity checks are done.

@return [Array<Command>] Subcommand list.

name[R]

The command name.

options[R]

List of registered options for this command.

Can be used to add manually created {Option}s but use with care as no collision or sanity checks are done.

@return [Array<Option>] Option list.

Public Class Methods

new(name, opts = {}) click to toggle source

@api private

# File lib/opt/command.rb, line 31
def initialize(name, opts = {})
  @name     = name.to_s.freeze
  @opts     = opts
  @options  = []
  @commands = []
end

Public Instance Methods

command(name, opts = {}) { |command| ... } click to toggle source

Add a subcommand.

A command can either have subcommands or free-text options.

@example

opt.command 'add' do |cmd|
  cmd.option '--num, -n'
end

@param name [String, Symbol, to_s] The command name. This token

will be used to match when parsing arguments.

@param opts [Hash] Options.

@yield [command] Yield new command. @yieldparam command [Command] The new command.

@raise [ArgumentError] An {ArgumentError} will be raised when

the command already has a free-text option or if a command
with the same name is already registered.

@return [Command] The new command.

@api public @see Opt::Command#initialize

# File lib/opt/command.rb, line 118
def command(name, opts = {})
  if options.any?{|o| o.text? }
    raise ArgumentError.new \
      'Can only have subcommands OR free-text arguments.'
  end

  command = Command.new(name, opts)

  if commands.any?{|c| c.name == command.name }
    raise ArgumentError.new "Command `#{command.name}' already registered."
  end

  yield command if block_given?

  commands << command
  command
end
defaults() click to toggle source

Return hash with default values for all options.

@return [Hash<String, Object>] Hash with option defaults.

@api private

# File lib/opt/command.rb, line 142
def defaults
  Hash[options.map{|o| [o.name, o.default] }]
end
option(definition = nil, opts = {}, &block) click to toggle source

Register a new option.

@example An option named “help” triggered on “–help” or “-h”

command.option '--help, -h'

@example An option with exactly one argument

command.option '--level, -l', nargs: 1

@example An option with 2 or more arguments

command.option '--files', nargs: [2, :inf]
command.option '--files', nargs: [2, :infinity]
command.option '--files', nargs: [2, '*']

@example An option with 2 to 4 arguments and a specific name

command.option '--sum, -s, -a', nargs: (2..4), name: :accumulate

@example An option with 0 or more arguments

command.option '-x', nargs: '*'

@example An option with 1 or more arguments

command.option '-x', nargs: '+'

@example A free-text option

command.option 'file', name: :files, nargs: '*'

@param definition [String] The option definition. Usually a command

separated list of dashed command line switches. If definition is
not dashed a free-text argument will be given. See {Option#initialize}
for more information.

@param opts [Hash] Option hash passed to {Option#initialize}.

Used to specify a name, number of arguments, etc.

@raise [ArgumentError] An {ArgumentError} is raised when a colliding

option is already registered or you try do define a free-text
option while already heaving a subcommand registered.

@api public @see Option.new

# File lib/opt/command.rb, line 77
def option(definition = nil, opts = {}, &block)
  option = Option.new(definition, opts, &block)

  if commands.any?
    raise ArgumentError.new \
      'Can only have subcommands OR free-text arguments.'
  end

  if (opt = options.find{|o| o.collide?(option) })
    raise "Option `#{definition}' collides with already " \
          "registered option: #{opt}"
  else
    options << option
  end
end
parse(argv = ARGV) click to toggle source

Parses given list of command line tokens.

@example

opt.parse %w(-fd command -x 56 --fuubar)

@param argv [Array<String>] List of command line strings.

Defaults to {ARGV}.

@return [Result] Return a hash-like result object.

@api public @see Result

# File lib/opt/command.rb, line 159
def parse(argv = ARGV)
  result = Result.new
  result.merge! defaults

  parse_argv! parse_tokens(argv.dup), result

  result
end
parse_argv!(argv, result, options = []) click to toggle source

@api private

# File lib/opt/command.rb, line 170
def parse_argv!(argv, result, options = [])
  options += self.options

  while argv.any?
    next if options.any?{|o| o.parse!(argv, result) }

    if argv.first.text?
      if (cmd = commands.find{|c| c.name == argv.first.value })
        argv.shift
        result.command << cmd
        cmd.parse_argv!(argv, result, options)
        next
      end
    end

    raise "Unknown option (#{argv.first.type}): #{argv.first}"
  end
end

Private Instance Methods

parse_tokens(argv) click to toggle source
# File lib/opt/command.rb, line 191
def parse_tokens(argv)
  tokens = []
  argv.each_with_index do |arg, index|
    if arg == '--'
      return tokens + argv[index + 1..-1].map{|a| Token.new(:text, a) }
    elsif arg[0..1] == '--'
      tokens << Token.new(:long, arg[2..-1])
    elsif arg[0] == '-'
      tokens << Token.new(:short, arg[1..-1])
    else
      tokens << Token.new(:text, arg)
    end
  end

  tokens
end