class Benry::CLI::OptionParser

Public Class Methods

new(option_schemas=[]) click to toggle source
# File lib/benry/cli.rb, line 125
def initialize(option_schemas=[])
  #; [!bflls] takes array of option schema.
  @option_schemas = option_schemas.collect {|x|
    case x
    when OptionSchema ; x
    when Array        ; OptionSchema.parse(*x)
    else
      raise OptionDefinitionError.new("#{x.inspect}: invalid option schema.")
    end
  }
end

Public Instance Methods

each_option_schema(&callback) click to toggle source
# File lib/benry/cli.rb, line 155
def each_option_schema(&callback)
  #; [!ycgdm] yields each option schema.
  @option_schemas.each(&callback)
end
each_option_string() { |option_string, desc| ... } click to toggle source
# File lib/benry/cli.rb, line 148
def each_option_string
  #; [!luro4] yields each option string and description.
  @option_schemas.each do |schema|
    yield schema.option_string, schema.desc
  end
end
err(msg) click to toggle source
# File lib/benry/cli.rb, line 160
def err(msg)
  OptionError.new(msg)
end
option(symbol, defstr=nil, desc=nil, &callback) click to toggle source
# File lib/benry/cli.rb, line 137
def option(symbol, defstr=nil, desc=nil, &callback)
  #; [!s59ly] accepts option definition string and description.
  #; [!2gfnh] recognizes first argument as option name if it is a symbol.
  unless symbol.is_a?(Symbol)
    symbol, defstr, desc = nil, symbol, defstr
  end
  @option_schemas << OptionSchema.parse(defstr, desc, name: symbol, &callback)
  #; [!fv5g4] return self in order to chain method call.
  self
end
parse(args) click to toggle source
# File lib/benry/cli.rb, line 164
def parse(args)
  #; [!5jfhv] returns command-line options as hash object.
  #; [!06iq3] removes command-line options from args.
  #; [!j2fda] stops command-line parsing when '-' found in args.
  option_values = {}
  while args[0] && args[0].start_with?('-') && args[0] != '-'
    argstr = args.shift
    #; [!31h46] stops parsing when '--' appears in args.
    if argstr == '--'
      break
    #; [!w5dpy] can parse long options.
    elsif argstr.start_with?('--')
      parse_long_option(argstr, option_values)
    #; [!mov8e] can parse short options.
    else
      parse_short_option(args, argstr, option_values)
    end
  end
  return option_values
end

Private Instance Methods

parse_long_option(argstr, option_values) click to toggle source
# File lib/benry/cli.rb, line 187
def parse_long_option(argstr, option_values)
  argstr =~ /\A--(\w[-\w]*)(?:=(.*))?\z/
  long, val = $1, $2
  #; [!w67gl] raises error when long option is unknown.
  opt = @option_schemas.find {|x| x.long == long }  or
    raise err("--#{long}: unknown option.")
  #; [!kyd1j] raises error when required argument of long option is missing.
  if opt.arg_required?
    val  or
      raise err("#{argstr}: argument required.")
  #; [!wuyrh] uses true as default value of optional argument of long option.
  elsif opt.arg_optional?
    val ||= true
  #; [!91b2j] raises error when long option takes no argument but specified.
  else
    val.nil?  or
      raise err("#{argstr}: unexpected argument.")
    val = true
  end
  #; [!9td8b] invokes callback with long option value if callback exists.
  #; [!1hak2] invokes callback with long option values as 2nd argument.
  begin
    if (pr = opt.callback)
      val = pr.arity == 2 ? pr.call(val, option_values) : pr.call(val)
    end
  rescue => ex
    #; [!nkqln] regards RuntimeError callback raised as long option error.
    raise unless ex.class == RuntimeError
    raise err("#{argstr}: #{ex.message}")
  end
  #
  option_values[opt.name] = val
end
parse_short_option(args, argstr, option_values) click to toggle source
# File lib/benry/cli.rb, line 221
def parse_short_option(args, argstr, option_values)
  n = argstr.length
  i = 0
  while (i += 1) < n
    char = argstr[i]
    #; [!wr58v] raises error when unknown short option specified.
    opt = @option_schemas.find {|x| x.short == char } or
      raise err("-#{char}: unknown option.")
    #; [!jzdcr] raises error when requried argument of short option is missing.
    if opt.arg_required?
      val = argstr[(i+1)..-1]
      val = args.shift if val.empty?
      val  or
        raise err("-#{char}: argument required.")
      i = n
    #; [!hnki9] uses true as default value of optional argument of short option.
    elsif opt.arg_optional?
      val = argstr[(i+1)..-1]
      val = true if val.empty?
      i = n
    #; [!8gj65] uses true as value of short option which takes no argument.
    else
      val = true
    end
    #; [!l6gss] invokes callback with short option value if exists.
    #; [!g4pld] invokes callback with short option values as 2nd argument.
    begin
      if (pr = opt.callback)
        val = pr.arity == 2 ? pr.call(val, option_values) : pr.call(val)
      end
    rescue => ex
      #; [!d4mgr] regards RuntimeError callback raised as short option error.
      raise unless ex.class == RuntimeError
      space = opt.arg_required? ? ' ' : ''
      raise err("-#{char}#{space}#{val}: #{ex.message}")
    end
    #
    option_values[opt.name] = val
  end
end