class Executable::Parser

The Parser class does all the heavy lifting for Executable.

Attributes

cli_class[R]

Public Class Methods

new(cli_class) click to toggle source

@param [Executable] cli_class

An executabe class.
# File lib/executable/parser.rb, line 11
def initialize(cli_class)
  @cli_class = cli_class
end

Public Instance Methods

find_long_option(obj, char) click to toggle source

@todo Sort alphabetically?

# File lib/executable/parser.rb, line 182
def find_long_option(obj, char)
  meths = obj.methods.map{ |m| m.to_s }
  meths = meths.select do |m|
    m.start_with?(char) and (m.end_with?('=') or m.end_with?('!'))
  end
  meths.first
end
invoke(obj, meth, argv) click to toggle source
# File lib/executable/parser.rb, line 192
def invoke(obj, meth, argv)
  m = (Method === meth ? meth : obj.method(meth))
  a = []
  m.arity.abs.times{ a << argv.shift }
  m.call(*a)
end
parse(argv=ARGV) click to toggle source

Parse command-line.

@param argv [Array,String] command-line arguments

# File lib/executable/parser.rb, line 21
def parse(argv=ARGV)
  # duplicate to make sure ARGV stay intact.
  argv = argv.dup
  argv = parse_shellwords(argv)

  cmd, argv = parse_subcommand(argv)
  cli  = cmd.new
  args = parse_arguments(cli, argv)

  return cli, args
end
parse_arguments(obj, argv, args=[]) click to toggle source

Parse command line options based on given object.

@param obj [Object] basis for command-line parsing @param argv [Array,String] command-line arguments @param args [Array] pre-seeded arguments to add to

@return [Array] parsed arguments

# File lib/executable/parser.rb, line 70
def parse_arguments(obj, argv, args=[])
  case argv
  when String
    require 'shellwords'
    argv = Shellwords.shellwords(argv)
  #else
  #  argv = argv.dup
  end

  #subc = nil
  #@args = []  #opts, i = {}, 0

  while argv.size > 0
    case arg = argv.shift
    when /=/
      parse_equal(obj, arg, argv, args)
    when /^--/
      parse_long(obj, arg, argv, args)
    when /^-/
      parse_flags(obj, arg, argv, args)
    else
      #if Executable === obj
      #  if cmd_class = obj.class.subcommands[arg]
      #    cmd  = cmd_class.new(obj)
      #    subc = cmd
      #    parse(cmd, argv, args)
      #  else
          args << arg
      #  end
      #end
    end
  end
 
  return args
end
parse_equal(obj, opt, argv, args) click to toggle source

Parse equal setting comman-line option.

# File lib/executable/parser.rb, line 109
def parse_equal(obj, opt, argv, args)
  if md = /^[-]*(.*?)=(.*?)$/.match(opt)
    x, v = md[1], md[2]
  else
    raise ArgumentError, "#{x}"
  end
  if obj.respond_to?("#{x}=")
    v = true  if v == 'true'   # yes or on  ?
    v = false if v == 'false'  # no  or off ?
    obj.send("#{x}=", v)
  else
    obj.__send__(:option_missing, x, v) # argv?
  end
end
parse_flags(obj, opt, argv, args) click to toggle source

Parse single-dash command-line option.

# File lib/executable/parser.rb, line 150
def parse_flags(obj, opt, argv, args)
  x = opt[1..-1]
  c = 0
  x.split(//).each do |k|
    if obj.respond_to?("#{k}=")
      m = obj.method("#{k}=")
      if obj.respond_to?("#{x}?")
        m.call(true)
      else
        invoke(obj, m, argv) #m.call(argv.shift)
      end
    elsif obj.respond_to?("#{k}!")
      invoke(obj, "#{k}!", argv)
    else
      long = find_long_option(obj, k)
      if long
        if long.end_with?('=') && obj.respond_to?(long.chomp('=')+'?')
          invoke(obj, long, [true])
        else
          invoke(obj, long, argv)
        end
      else
        obj.__send__(:option_missing, x, argv)
      end
    end
  end
end
parse_long(obj, opt, argv, args) click to toggle source

Parse double-dash command-line option.

# File lib/executable/parser.rb, line 127
def parse_long(obj, opt, argv, args)
  x = opt.sub(/^\-+/, '') # remove '--'
  if obj.respond_to?("#{x}=")
    m = obj.method("#{x}=")
    if obj.respond_to?("#{x}?")
      m.call(true)
    else
      invoke(obj, m, argv)
    end
  elsif obj.respond_to?("#{x}!")
    invoke(obj, "#{x}!", argv)
  else
    # call even if private method
    obj.__send__(:option_missing, x, argv)
  end
end
parse_shellwords(argv) click to toggle source

Make sure arguments are an array. If argv is a String, then parse using Shellwords module.

@param argv [Array,String] commmand-line arguments

# File lib/executable/parser.rb, line 37
def parse_shellwords(argv)
  if String === argv
    require 'shellwords'
    argv = Shellwords.shellwords(argv)
  end
  argv.to_a
end
parse_subcommand(argv) click to toggle source
# File lib/executable/parser.rb, line 48
def parse_subcommand(argv)
  cmd = cli_class
  arg = argv.first

  while c = cmd.subcommands[arg]
    cmd = c
    argv.shift
    arg = argv.first
  end

  return cmd, argv
end
subcommands() click to toggle source

Index of subcommands.

@return [Hash] name mapped to subcommnd class

# File lib/executable/parser.rb, line 202
def subcommands
  @cli_class.subcommands
end